boseiju/ability_tree/
colors.rs1use crate::ability_tree::AbilityTreeNode;
2use crate::ability_tree::MAX_CHILDREN_PER_NODE;
3use crate::ability_tree::MAX_NODE_DATA_SIZE;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6#[derive(serde::Serialize, serde::Deserialize)]
7pub struct Colors {
8 pub white: bool,
9 pub blue: bool,
10 pub black: bool,
11 pub red: bool,
12 pub green: bool,
13 #[cfg(feature = "spanned_tree")]
14 span: crate::ability_tree::span::TreeSpan,
15}
16
17impl Colors {
18 pub fn empty() -> Colors {
19 Colors {
20 white: false,
21 blue: false,
22 black: false,
23 red: false,
24 green: false,
25 #[cfg(feature = "spanned_tree")]
26 span: Default::default(),
27 }
28 }
29
30 pub fn from_iter<I: Iterator<Item = mtg_data::Color>>(colors: I) -> Self {
31 let mut result = Self::empty();
32 for color in colors {
33 match color {
34 mtg_data::Color::Black => result.black = true,
35 mtg_data::Color::Blue => result.blue = true,
36 mtg_data::Color::Green => result.green = true,
37 mtg_data::Color::Red => result.red = true,
38 mtg_data::Color::White => result.white = true,
39 _ => { }
40 }
41 }
42 result
43 }
44
45 pub fn iter(&self) -> impl Iterator<Item = mtg_data::Color> {
46 [
47 (self.white, mtg_data::Color::White),
48 (self.blue, mtg_data::Color::Blue),
49 (self.black, mtg_data::Color::Black),
50 (self.red, mtg_data::Color::Red),
51 (self.green, mtg_data::Color::Green),
52 ]
53 .into_iter()
54 .filter_map(|(on, name)| on.then_some(name))
55 }
56
57 pub fn from_bitmask(bitmask: i16) -> Self {
58 Colors {
59 white: (bitmask & (1 << 0)) > 0,
60 blue: (bitmask & (1 << 1)) > 0,
61 black: (bitmask & (1 << 2)) > 0,
62 red: (bitmask & (1 << 3)) > 0,
63 green: (bitmask & (1 << 4)) > 0,
64 #[cfg(feature = "spanned_tree")]
65 span: Default::default(),
66 }
67 }
68
69 pub fn to_bitmask(&self) -> i16 {
70 let white = if self.white { 1 << 0 } else { 0 };
71 let blue = if self.blue { 1 << 1 } else { 0 };
72 let black = if self.black { 1 << 2 } else { 0 };
73 let red = if self.red { 1 << 3 } else { 0 };
74 let green = if self.green { 1 << 4 } else { 0 };
75 white | blue | black | red | green
76 }
77}
78
79impl AbilityTreeNode for Colors {
80 fn node_id(&self) -> usize {
81 use idris::Idris;
82 crate::ability_tree::tree_node::NodeKind::Colors.id()
83 }
84
85 fn children(&self) -> arrayvec::ArrayVec<&dyn AbilityTreeNode, MAX_CHILDREN_PER_NODE> {
86 arrayvec::ArrayVec::new_const()
87 }
88
89 fn data(&self) -> arrayvec::ArrayVec<u8, MAX_NODE_DATA_SIZE> {
90 unimplemented!()
91 }
92
93 fn display(&self, out: &mut crate::utils::TreeFormatter<'_>) -> std::io::Result<()> {
94 use std::io::Write;
95 write!(out, "{self}")
96 }
97
98 fn node_tag(&self) -> &'static str {
99 "colors"
100 }
101
102 #[cfg(feature = "spanned_tree")]
103 fn node_span(&self) -> super::span::TreeSpan {
104 self.span
105 }
106}
107
108impl std::fmt::Display for Colors {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 use std::fmt::Write;
111 let mut colors = self.iter().peekable();
112 while let Some(next) = colors.next() {
113 f.write_char(next.as_char())?;
114 if colors.peek().is_some() {
115 f.write_char(' ')?;
116 }
117 }
118 Ok(())
119 }
120}
121
122impl Default for Colors {
123 fn default() -> Self {
124 Self {
125 white: false,
126 blue: false,
127 black: false,
128 red: false,
129 green: false,
130 #[cfg(feature = "spanned_tree")]
131 span: Default::default(),
132 }
133 }
134}
135
136#[cfg(feature = "parser")]
137impl crate::utils::DummyInit for Colors {
138 fn dummy_init() -> Self {
139 Default::default()
140 }
141}
142
143impl<S: AsRef<str>> TryFrom<&[S]> for Colors {
144 type Error = String; fn try_from(colors: &[S]) -> Result<Self, Self::Error> {
146 use std::str::FromStr;
147 let mut result = Colors::empty();
148
149 for color_str in colors {
150 let color_flag = match mtg_data::Color::from_str(color_str.as_ref())? {
151 mtg_data::Color::Colorless => {
152 return Err(format!("Colorless isn't valid in color combination!"))?;
153 }
154 mtg_data::Color::White => &mut result.white,
155 mtg_data::Color::Blue => &mut result.blue,
156 mtg_data::Color::Black => &mut result.black,
157 mtg_data::Color::Red => &mut result.red,
158 mtg_data::Color::Green => &mut result.green,
159 };
160 if *color_flag {
161 let color_str = color_str.as_ref();
162 return Err(format!("Duplicate color {color_str} in combination"));
163 } else {
164 *color_flag = true;
165 }
166 }
167
168 Ok(result)
169 }
170}