1use crate::pattern::*;
3use std::collections::BTreeSet;
4
5type Dependencies = BTreeSet<Special>;
6
7impl Pattern<Parsed> {
8 pub fn optimize(self) -> (Pattern<Optimized>, Dependencies) {
9 let mut dependencies = Dependencies::new();
10 let output = Optimize::optimize(self, &mut dependencies);
11 (output, dependencies)
12 }
13}
14
15pub trait Optimize {
16 type Output;
17
18 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output;
19}
20
21impl Optimize for Literal<Parsed> {
22 type Output = Literal<Optimized>;
23
24 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
25 Self::Output {
26 value: self.value.to_string(),
27 }
28 }
29}
30
31impl Optimize for Special<Parsed> {
32 type Output = Special<Optimized>;
33
34 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
35 dependencies.insert(self.clone());
36 match self {
37 Self::Wordlist(name) => Self::Output::Wordlist(name),
38 Self::Markov(name) => Self::Output::Markov(name),
39 Self::Preset(name) => Self::Output::Preset(name),
40 }
41 }
42}
43
44impl Optimize for Set<Parsed> {
45 type Output = Set<Optimized>;
46
47 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
48 self.into()
49 }
50}
51
52impl Optimize for Item<Parsed> {
53 type Output = Item<Optimized>;
54
55 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
56 Self::Output {
57 pattern: Optimize::optimize(self.pattern, dependencies),
58 repeat: self.repeat,
59 optional: self.optional,
60 }
61 }
62}
63
64impl Segment<Optimized> {
65 fn is_empty(&self) -> bool {
66 self.items.iter().any(|i| !i.is_empty())
67 }
68}
69
70impl Group<Optimized> {
71 fn is_empty(&self) -> bool {
72 self.segments.iter().any(|s| !s.is_empty())
73 }
74}
75
76impl Item<Optimized> {
77 fn is_empty(&self) -> bool {
78 if self.repeat == (0..=0) {
80 return true;
81 }
82
83 match &self.pattern {
84 Pattern::Group(group) => group.is_empty(),
85 Pattern::Set(_) => false,
86 Pattern::Special(_) => false,
87 Pattern::Literal(literal) => literal.value.is_empty(),
88 }
89 }
90
91 fn is_modified(&self) -> bool {
92 self.optional || self.repeat != (1..=1)
93 }
94
95 fn try_fuse(&mut self, item: Self) -> Result<(), Self> {
96 if self.is_modified() || item.is_modified() {
98 return Err(item);
99 }
100
101 match (&mut self.pattern, &item.pattern) {
102 (Pattern::Literal(left), Pattern::Literal(right)) => {
103 left.value.push_str(&right.value);
104 Ok(())
105 }
106 _ => Err(item),
107 }
108 }
109
110 fn flatten(self) -> impl Iterator<Item = Self> {
111 if self.is_modified() {
112 }
114
115 match &self.pattern {
116 Pattern::Group(group) if group.segments.len() == 1 => {}
117 _ => {}
118 }
119
120 std::iter::once(self)
121 }
122
123 fn simplify(self) -> Self {
124 if self.is_modified() {
125 return self;
126 }
127
128 match &self.pattern {
129 Pattern::Set(set) => {
130 self
132 }
133 _ => self,
134 }
135 }
136}
137
138impl Optimize for Segment<Parsed> {
139 type Output = Segment<Optimized>;
140
141 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
142 Self::Output {
143 items: self
144 .items
145 .into_iter()
146 .map(|item| item.optimize(dependencies))
147 .map(Item::simplify)
149 .filter(|i| !i.is_empty())
151 .flat_map(Item::flatten)
153 .fold(Vec::new(), |mut items, item| {
155 if let Some(last) = items.last_mut() {
156 if let Err(item) = last.try_fuse(item) {
157 items.push(item);
158 }
159 } else {
160 items.push(item);
161 }
162 items
163 }),
164 }
165 }
166}
167
168impl Optimize for Group<Parsed> {
169 type Output = Group<Optimized>;
170
171 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
172 Self::Output {
173 segments: self
174 .segments
175 .into_iter()
176 .map(|segment| segment.optimize(dependencies))
177 .collect(),
178 }
179 }
180}
181
182impl Optimize for Pattern<Parsed> {
183 type Output = Pattern<Optimized>;
184
185 fn optimize(self, dependencies: &mut Dependencies) -> Self::Output {
186 match self {
187 Self::Group(group) => Self::Output::Group(group.optimize(dependencies)),
188 Self::Set(set) => Self::Output::Set(set.optimize(dependencies)),
189 Self::Literal(literal) => Self::Output::Literal(literal.optimize(dependencies)),
190 Self::Special(special) => Self::Output::Special(special.optimize(dependencies)),
191 }
192 }
193}