1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum CostTokenKind {
9 AddCounter,
10 AddMana,
11 Behold,
12 BeholdExile,
13 Blight,
14 ChooseCard,
15 ChooseColor,
16 ChooseCreatureType,
17 CollectEvidence,
18 DamageYou,
19 Discard,
20 Draw,
21 Enlist,
22 Exert,
23 Exile,
24 ExileAnyGrave,
25 ExileCtrlOrGrave,
26 ExiledMoveToGrave,
27 ExileFromGrave,
28 ExileFromHand,
29 ExileFromStack,
30 ExileFromTop,
31 ExileSameGrave,
32 FlipCoin,
33 Forage,
34 GainControl,
35 GainLife,
36 Mana,
37 Mandatory,
38 Mill,
39 PayEnergy,
40 PayLife,
41 PayShards,
42 PromiseGift,
43 PutCardToLibFromBattlefield,
44 PutCardToLibFromGrave,
45 PutCardToLibFromHand,
46 PutCardToLibFromSameGrave,
47 RemoveAnyCounter,
48 Return,
49 Reveal,
50 RevealChosen,
51 RevealFromExile,
52 RevealOrChoose,
53 RollDice,
54 Sac,
55 SubCounter,
56 Tap,
57 TapXType,
58 Unattach,
59 Untap,
60 UntapYType,
61 Waterbend,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub struct CostToken<'a> {
66 pub kind: CostTokenKind,
67 pub inner: Option<&'a str>,
68}
69
70impl CostTokenKind {
71 pub fn parse(token: &str) -> Option<CostToken<'_>> {
72 Self::parse_exact(token).or_else(|| Self::parse_prefixed(token))
73 }
74
75 fn parse_exact(token: &str) -> Option<CostToken<'_>> {
76 let kind = match token {
77 "T" | "Tap" => Self::Tap,
78 "Q" | "Untap" => Self::Untap,
79 "Mandatory" => Self::Mandatory,
80 "Forage" => Self::Forage,
81 token if token.starts_with("PromiseGift") => Self::PromiseGift,
82 _ => return None,
83 };
84 Some(CostToken { kind, inner: None })
85 }
86
87 fn parse_prefixed(token: &str) -> Option<CostToken<'_>> {
88 if let Some(inner) = token.strip_prefix("Exert<") {
89 return Some(CostToken {
90 kind: Self::Exert,
91 inner: inner.strip_suffix('>'),
92 });
93 }
94
95 let prefixes = [
98 (Self::Mana, "Mana<"),
99 (Self::Sac, "Sac<"),
100 (Self::Discard, "Discard<"),
101 (Self::PayLife, "PayLife<"),
102 (Self::SubCounter, "SubCounter<"),
103 (Self::AddCounter, "AddCounter<"),
104 (Self::PayEnergy, "PayEnergy<"),
105 (Self::PayShards, "PayShards<"),
106 (Self::ChooseColor, "ChooseColor<"),
107 (Self::ChooseCreatureType, "ChooseCreatureType<"),
108 (Self::FlipCoin, "FlipCoin<"),
109 (Self::RollDice, "RollDice<"),
110 (Self::ExileFromHand, "ExileFromHand<"),
111 (Self::ExileFromGrave, "ExileFromGrave<"),
112 (Self::ExileFromTop, "ExileFromTop<"),
113 (Self::ExileFromStack, "ExileFromStack<"),
114 (Self::ExileAnyGrave, "ExileAnyGrave<"),
115 (Self::ExileSameGrave, "ExileSameGrave<"),
116 (Self::ExileCtrlOrGrave, "ExileCtrlOrGrave<"),
117 (Self::ExiledMoveToGrave, "ExiledMoveToGrave<"),
118 (Self::Exile, "Exile<"),
119 (Self::Return, "Return<"),
120 (Self::TapXType, "tapXType<"),
121 (Self::UntapYType, "untapYType<"),
122 (Self::DamageYou, "DamageYou<"),
123 (Self::Draw, "Draw<"),
124 (Self::Mill, "Mill<"),
125 (Self::Reveal, "Reveal<"),
126 (Self::ChooseCard, "ChooseCard<"),
127 (Self::RevealFromExile, "RevealFromExile<"),
128 (Self::RevealOrChoose, "RevealOrChoose<"),
129 (Self::RevealChosen, "RevealChosen<"),
130 (Self::BeholdExile, "BeholdExile<"),
131 (Self::Behold, "Behold<"),
132 (Self::GainLife, "GainLife<"),
133 (Self::GainControl, "GainControl<"),
134 (Self::RemoveAnyCounter, "RemoveAnyCounter<"),
135 (Self::Unattach, "Unattach<"),
136 (Self::Waterbend, "Waterbend<"),
137 (Self::AddMana, "AddMana<"),
138 (Self::CollectEvidence, "CollectEvidence<"),
139 (Self::PutCardToLibFromHand, "PutCardToLibFromHand<"),
140 (
141 Self::PutCardToLibFromSameGrave,
142 "PutCardToLibFromSameGrave<",
143 ),
144 (Self::PutCardToLibFromGrave, "PutCardToLibFromGrave<"),
145 (
146 Self::PutCardToLibFromBattlefield,
147 "PutCardToLibFromBattlefield<",
148 ),
149 (Self::Enlist, "Enlist<"),
150 (Self::Blight, "Blight<"),
151 ];
152
153 prefixes.iter().find_map(|(kind, prefix)| {
154 token
155 .strip_prefix(prefix)
156 .and_then(|inner| inner.strip_suffix('>'))
157 .map(|inner| CostToken {
158 kind: *kind,
159 inner: Some(inner),
160 })
161 })
162 }
163}