boseiju/ability_tree/terminals/
mana_cost.rs

1use crate::ability_tree::AbilityTreeNode;
2use crate::ability_tree::MAX_CHILDREN_PER_NODE;
3use crate::lexer::IntoToken;
4
5/// A cost requiring mana.
6///
7/// See also <https://mtg.fandom.com/wiki/Mana_cost>
8#[derive(serde::Serialize, serde::Deserialize)]
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ManaCost {
11    pub cost: arrayvec::ArrayVec<crate::ability_tree::terminals::Mana, MAX_CHILDREN_PER_NODE>,
12    #[cfg(feature = "spanned_tree")]
13    pub span: crate::ability_tree::span::TreeSpan,
14}
15
16impl ManaCost {
17    pub fn mana_value(&self) -> usize {
18        self.cost.iter().map(|mana| mana.mana_value()).sum()
19    }
20}
21
22impl AbilityTreeNode for ManaCost {
23    fn node_id(&self) -> usize {
24        use idris::Idris;
25        crate::ability_tree::NodeKind::ManaCost.id()
26    }
27
28    fn children(&self) -> arrayvec::ArrayVec<&dyn AbilityTreeNode, MAX_CHILDREN_PER_NODE> {
29        let mut children = arrayvec::ArrayVec::new_const();
30        for cost in self.cost.iter() {
31            children.push(cost as &dyn AbilityTreeNode);
32        }
33        children
34    }
35
36    fn display(&self, out: &mut crate::utils::TreeFormatter<'_>) -> std::io::Result<()> {
37        use std::io::Write;
38        write!(out, "mana cost: ")?;
39        for mana in self.cost.iter() {
40            mana.display(out)?;
41        }
42        Ok(())
43    }
44
45    fn node_tag(&self) -> &'static str {
46        "mana cost"
47    }
48
49    #[cfg(feature = "spanned_tree")]
50    fn node_span(&self) -> crate::ability_tree::span::TreeSpan {
51        self.span
52    }
53}
54
55impl IntoToken for ManaCost {
56    fn try_from_span(span: &crate::lexer::Span) -> Option<Self> {
57        let mut cost = arrayvec::ArrayVec::new_const();
58        /* Yeah, yeah, it's not that hard and may not need a regex. Whatever for now. */
59        lazy_static::lazy_static!(
60            static ref mana_cost_regex: regex::Regex = regex::Regex::new(r"(\{[^{}]+\})")
61                .expect("Failed to compile the mana cost iterator regex: {e}");
62        );
63
64        for capture in mana_cost_regex.captures_iter(&span.text) {
65            let span = crate::lexer::Span {
66                start: span.start + capture.get_match().start(),
67                length: capture.get_match().len(),
68                text: capture.get_match().as_str(),
69            };
70            let mana = crate::ability_tree::terminals::Mana::try_from_span(&span)?;
71            cost.push(mana);
72        }
73
74        Some(ManaCost {
75            cost,
76            #[cfg(feature = "spanned_tree")]
77            span: span.into(),
78        })
79    }
80}
81
82impl std::ops::Deref for ManaCost {
83    type Target = [crate::ability_tree::terminals::Mana];
84    fn deref(&self) -> &Self::Target {
85        self.cost.as_slice()
86    }
87}
88
89impl std::ops::DerefMut for ManaCost {
90    fn deref_mut(&mut self) -> &mut Self::Target {
91        self.cost.as_mut_slice()
92    }
93}
94
95#[cfg(feature = "parser")]
96impl crate::utils::DummyInit for ManaCost {
97    fn dummy_init() -> Self {
98        Self {
99            cost: crate::utils::dummy(),
100            #[cfg(feature = "spanned_tree")]
101            span: Default::default(),
102        }
103    }
104}