boseiju/ability_tree/
colors.rs

1use 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                _ => { /* Dafuk ? */ }
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; // Fixme!
145    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}