worlde_automaton/
types.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5#[repr(transparent)]
6pub struct Letter(u8);
7
8impl Letter {
9 #[must_use]
13 pub const fn try_new(b: u8) -> Option<Self> {
14 match b {
15 b'a'..=b'z' => Some(Self(b - b'a')),
16 b'A'..=b'Z' => Some(Self(b - b'A')),
17 _ => None,
18 }
19 }
20
21 #[must_use]
26 pub const fn new(b: u8) -> Self {
27 match b {
28 b'a'..=b'z' => Self(b - b'a'),
29 b'A'..=b'Z' => Self(b - b'A'),
30 _ => panic!("Invalid letter, only accept [a-zA-Z]"),
31 }
32 }
33}
34
35impl From<Letter> for u8 {
36 fn from(letter: Letter) -> Self {
37 b'a' + letter.0
38 }
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43#[repr(transparent)]
44pub struct LetterSet(u32);
45
46impl LetterSet {
47 #[must_use]
49 pub const fn new() -> Self {
50 Self(0)
51 }
52
53 #[must_use]
55 pub const fn contains(self, letter: Letter) -> bool {
56 (self.0 >> letter.0) & 1 == 1
57 }
58
59 #[must_use]
61 pub const fn add(self, letter: Letter) -> Self {
62 Self(self.0 | (1 << letter.0))
63 }
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68#[repr(transparent)]
69pub struct LetterList(u32);
70
71impl LetterList {
72 #[must_use]
74 pub const fn new() -> Self {
75 Self(0)
76 }
77
78 #[must_use]
80 pub const fn len(self) -> u32 {
81 self.0 & 0x1F
82 }
83
84 #[must_use]
86 pub const fn is_empty(self) -> bool {
87 self.0 == 0
88 }
89
90 #[must_use]
95 pub const fn add(self, letter: Letter) -> Self {
96 let len = self.len() + 1;
97 debug_assert!(len <= 5, "maximum capacity of 5 is reached");
98 Self((letter.0 as u32 + 1) << (5 * len) | (self.0 & !0x1F) | len)
99 }
100
101 #[must_use]
105 pub const fn remove(self, letter: Letter) -> (bool, Self) {
106 let t = letter.0 as u32 + 1;
107 let mut r = 0;
108 let mut rs = 5;
109 let mut n = self.0 >> 5;
110 while n != 0 {
111 let x = n & 0x1F;
112 n >>= 5;
113
114 if x == t {
115 return (true, Self(r | n << rs | (self.len() - 1)));
116 }
117
118 r |= x << rs;
119 rs += 5;
120 }
121
122 (false, self)
123 }
124
125 #[must_use]
127 pub const fn iter(self) -> LetterListIter {
128 LetterListIter(self.0 >> 5)
129 }
130}
131
132#[allow(missing_copy_implementations)] #[derive(Clone, Debug)]
135pub struct LetterListIter(u32);
136
137impl Iterator for LetterListIter {
138 type Item = Letter;
139
140 fn next(&mut self) -> Option<Self::Item> {
141 if self.0 == 0 {
142 return None;
143 }
144 let x = (self.0 & 0x1F) - 1;
145 let x = u8::try_from(x).ok()?;
147 self.0 >>= 5;
148 Some(Letter(x))
149 }
150}
151
152impl IntoIterator for LetterList {
153 type Item = Letter;
154
155 type IntoIter = LetterListIter;
156
157 fn into_iter(self) -> Self::IntoIter {
158 self.iter()
159 }
160}
161
162#[derive(Clone, Copy, Debug, PartialEq, Eq)]
169#[repr(transparent)]
170pub struct Constraint(u32);
171
172impl Constraint {
173 #[must_use]
175 pub const fn new() -> Self {
176 Self(1 << 31)
177 }
178
179 #[must_use]
184 pub const fn accept(self, letter: Letter) -> bool {
185 #[allow(clippy::cast_possible_truncation)]
187 let must = (self.0 >> 26) as u8;
188 if must < 32 {
189 must == letter.0
190 } else {
191 !LetterSet(self.0).contains(letter)
192 }
193 }
194
195 #[must_use]
197 pub const fn is_free(self) -> bool {
198 self.0 >> 31 == 1
199 }
200
201 #[must_use]
203 pub const fn must(self, letter: Letter) -> Self {
204 Self((letter.0 as u32) << 26 | (self.0 & 0x03FF_FFFF))
205 }
206
207 #[must_use]
209 pub const fn must_not(self, letter: Letter) -> Self {
210 Self(LetterSet(self.0).add(letter).0)
211 }
212
213 #[must_use]
218 pub const fn must_letter(self) -> Letter {
219 #[allow(clippy::cast_possible_truncation)]
221 Letter(((self.0 >> 26) & 0x1F) as _)
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_letter_try_new() {
231 assert_eq!(Letter::try_new(b'a'), Some(Letter(0)));
232 assert_eq!(Letter::try_new(b'z'), Some(Letter(25)));
233 assert_eq!(Letter::try_new(b'A'), Some(Letter(0)));
234 assert_eq!(Letter::try_new(b'Z'), Some(Letter(25)));
235 assert_eq!(Letter::try_new(b' '), None);
236 assert_eq!(Letter::try_new(b'0'), None);
237 assert_eq!(Letter::try_new(b'9'), None);
238 assert_eq!(Letter::try_new(b'.'), None);
239 assert_eq!(Letter::try_new(b'!'), None);
240 }
241
242 #[test]
243 fn test_letter_new() {
244 assert_eq!(Letter::new(b'a'), Letter(0));
245 assert_eq!(Letter::new(b'z'), Letter(25));
246 assert_eq!(Letter::new(b'A'), Letter(0));
247 assert_eq!(Letter::new(b'Z'), Letter(25));
248 }
249
250 #[test]
251 fn test_letter_into() {
252 assert_eq!(u8::from(Letter::new(b'a')), b'a');
253 assert_eq!(u8::from(Letter::new(b'z')), b'z');
254 assert_eq!(u8::from(Letter::new(b'A')), b'a');
255 assert_eq!(u8::from(Letter::new(b'Z')), b'z');
256 }
257
258 #[test]
259 #[should_panic(expected = "Invalid letter, only accept [a-zA-Z]")]
260 const fn test_letter_new_invalid() {
261 let _ = Letter::new(b' ');
262 }
263
264 #[test]
265 fn test_set() {
266 let set = LetterSet::new();
267 assert!(!set.contains(Letter(0)));
268 assert!(!set.contains(Letter(1)));
269 let set = set.add(Letter(0));
270 assert!(set.contains(Letter(0)));
271 assert!(!set.contains(Letter(1)));
272 let set = set.add(Letter(1));
273 assert!(set.contains(Letter(0)));
274 assert!(set.contains(Letter(1)));
275 let set = set.add(Letter(0));
277 assert!(set.contains(Letter(0)));
278 assert!(set.contains(Letter(1)));
279 }
280
281 #[test]
282 fn test_list() {
283 let list = LetterList::new();
284 assert_eq!(list.len(), 0);
285
286 let list = list.add(Letter(0));
287 assert_eq!(list.len(), 1);
288
289 let list = list.add(Letter(1));
290 assert_eq!(list.len(), 2);
291
292 let list = list.add(Letter(0));
294 assert_eq!(list.len(), 3);
295 }
296
297 fn contains(ev: LetterList, letter: Letter) -> bool {
298 ev.iter().any(|l| l == letter)
299 }
300
301 #[test]
302 fn test_list_contains() {
303 let list = LetterList::new();
304 assert!(!contains(list, Letter(0)));
305 assert!(!contains(list, Letter(1)));
306
307 let list = list.add(Letter(0));
308 assert!(contains(list, Letter(0)));
309 assert!(!contains(list, Letter(1)));
310
311 let list = list.add(Letter(1));
312 assert!(contains(list, Letter(0)));
313 assert!(contains(list, Letter(1)));
314
315 let list = list.add(Letter(0));
316 assert!(contains(list, Letter(0)));
317 assert!(contains(list, Letter(1)));
318 }
319
320 #[test]
321 fn test_list_remove() {
322 let list = LetterList::new();
323 let (removed, _) = list.remove(Letter(0));
324 assert!(!removed);
325
326 let list = list.add(Letter(0));
327 let (removed, list2) = list.remove(Letter(0));
328 assert!(removed);
329 assert!(contains(list, Letter(0)));
330 assert!(!contains(list2, Letter(0)));
331
332 let list = list.add(Letter(1));
333 let (removed, list2) = list.remove(Letter(1));
334 assert!(removed);
335 assert!(contains(list, Letter(0)));
336 assert!(contains(list, Letter(1)));
337 assert!(contains(list2, Letter(0)));
338 assert!(!contains(list2, Letter(1)));
339
340 let list = list.add(Letter(0));
341 let (removed, list2) = list.remove(Letter(0));
342 assert!(removed);
343 assert!(contains(list, Letter(0)));
344 assert!(contains(list, Letter(1)));
345 assert!(contains(list2, Letter(0)));
346 assert!(contains(list2, Letter(1)));
347 }
348
349 #[test]
350 fn test_list_iter() {
351 let list = LetterList::new()
352 .add(Letter(0))
353 .add(Letter(1))
354 .add(Letter(2));
355
356 let letters = list.into_iter().collect::<Vec<_>>();
357 assert_eq!(letters, &[Letter(0), Letter(1), Letter(2)]);
358 }
359
360 #[test]
361 #[should_panic(expected = "maximum capacity of 5 is reached")]
362 const fn test_list_full() {
363 let list = LetterList(5);
364 let _ = list.add(Letter(0));
365 }
366
367 #[test]
368 fn test_constraint() {
369 let cons = Constraint::new();
370 assert!(cons.accept(Letter(0)));
371 assert!(cons.accept(Letter(1)));
372
373 let cons = cons.must_not(Letter(0));
374 assert!(!cons.accept(Letter(0)));
375 assert!(cons.accept(Letter(1)));
376
377 let cons = cons.must(Letter(0));
378 assert!(cons.accept(Letter(0)));
379 assert!(!cons.accept(Letter(1)));
380 }
381
382 #[test]
383 fn test_constraint_is_free() {
384 let cons = Constraint::new();
385 assert!(cons.is_free());
386
387 let cons = cons.must_not(Letter(0));
388 assert!(cons.is_free());
389
390 let cons = cons.must(Letter(0));
391 assert!(!cons.is_free());
392 }
393
394 #[test]
395 fn test_constraint_must_letter() {
396 let cons = Constraint::new();
397
398 let cons = cons.must(Letter(1));
399 assert_eq!(cons.must_letter(), Letter(1));
400
401 let cons = cons.must(Letter(2));
402 assert_eq!(cons.must_letter(), Letter(2));
403 }
404}