Skip to main content

t_oc/
lib.rs

1//! Trie Occurrence Counter is frequency dictionary that uses any `impl Iterator<Item = char>` type as occurrent.
2//!
3//! Support for English letters A–Za–z OOB.
4
5use std::vec::Vec;
6
7/// Versatile result type used by tree entry operations.
8pub type VerRes = Result<usize, KeyError>;
9/// Addition result type used by [`Toc::add`] operation.
10pub type AddRes = Result<Option<usize>, KeyError>;
11
12mod uc;
13use uc::UC;
14
15mod aide;
16
17/// `Letter` is `Alphabet` element, represents tree node.
18#[cfg_attr(test, derive(PartialEq))]
19struct Letter {
20    #[cfg(test)]
21    val: char,
22    ab: Option<Alphabet>,
23    ct: Option<usize>,
24}
25
26impl Letter {
27    const fn new() -> Self {
28        Letter {
29            #[cfg(test)]
30            val: '💚',
31            ab: None,
32            ct: None,
33        }
34    }
35
36    const fn ab(&self) -> bool {
37        self.ab.is_some()
38    }
39
40    const fn ct(&self) -> bool {
41        self.ct.is_some()
42    }
43
44    const fn to_mut_ptr(&self) -> *mut Self {
45        (self as *const Self).cast_mut()
46    }
47}
48
49/// Tree node arms. Consists of `Letter`s.
50type Alphabet = Box<[Letter]>;
51/// Index conversion function. Tighten with alphabet used.
52/// Returns corresponding `usize`d index of `char`.
53///
54/// For details see `english_letters::ix` implementation.
55pub type Ix = fn(char) -> usize;
56
57/// Reversal index conversion function. Symmetrically mirrors `Ix` function.
58///
59/// For details see `english_letters::re` implementation.
60pub type Re = fn(usize) -> char;
61
62/// Alphabet function, tree arms generation of length specified.
63fn ab(len: usize) -> Alphabet {
64    let mut ab = Vec::with_capacity(len);
65
66    #[cfg(test)]
67    #[cfg(feature = "test-ext")]
68    let mut c = 'A' as u8;
69
70    let sc = ab.spare_capacity_mut();
71    for ix in 0..len {
72        let mut _letter = sc[ix].write(Letter::new());
73
74        #[cfg(test)]
75        #[cfg(feature = "test-ext")]
76        {
77            _letter.val = c as char;
78
79            const Z: u8 = 'Z' as u8;
80            c = if c == Z { 'a' as u8 } else { c + 1 }
81        }
82    }
83
84    unsafe { ab.set_len(len) };
85
86    ab.into_boxed_slice()
87}
88
89/// Module for working with English alphabet letters, A-Za-z.
90///
91/// For details see `Toc::new_with()`.
92pub mod english_letters {
93
94    /// 26
95    pub const BASE_ALPHABET_LEN: usize = 26;
96    /// 52
97    pub const ALPHABET_LEN: usize = BASE_ALPHABET_LEN * 2;
98
99    const A: usize = 'A' as usize;
100    #[allow(non_upper_case_globals)]
101    const a: usize = 'a' as usize;
102
103    /// Index conversion function.
104    pub fn ix(c: char) -> usize {
105        let code_point = c as usize;
106
107        match code_point {
108            | c if c > 64 && c < 91 => c - A,
109            | c if c > 96 && c < 123 => c - a + BASE_ALPHABET_LEN,
110            | _ => {
111                panic!("Index conversion failed because code point `{code_point}` is unsupported.")
112            },
113        }
114    }
115
116    /// Index reversal conversion function.
117    pub fn re(i: usize) -> char {
118        let code_point = match i {
119            | i if i < 26 => i + A,
120            | i if i > 25 && i < 52 => i + a - BASE_ALPHABET_LEN,
121            | _ => {
122                panic!("Char conversion failed because index `{i}` conversion is not supported.")
123            },
124        };
125
126        code_point as u8 as char
127    }
128}
129
130/// Key error type used by tree entry operations.
131#[derive(Debug, PartialEq, Eq, Clone)]
132pub enum KeyError {
133    /// Zero occurrent usage.
134    ZeroLen,
135    /// Unknown occurrent usage.
136    Unknown,
137}
138
139#[cfg_attr(test, derive(PartialEq, Debug))]
140enum TraRes<'a> {
141    Ok(&'a Letter),
142    OkMut(&'a mut Letter),
143    ZeroLen,
144    UnknownForNotEntry,
145    UnknownForAbsentPath,
146}
147
148impl<'a> TraRes<'a> {
149    fn ver_res(&self) -> KeyError {
150        let p = || panic!("Unsupported");
151
152        return match self {
153            | TraRes::ZeroLen => KeyError::ZeroLen,
154            | TraRes::UnknownForNotEntry | TraRes::UnknownForAbsentPath => KeyError::Unknown,
155            | TraRes::Ok(_) => p(),
156            | TraRes::OkMut(_) => p(),
157        };
158    }
159}
160
161// TC: Ω(n ⋅ alphabet size) ⇒ Ω(n), n = nodes count
162// SC: Θ(s + n) ⇒ Θ(s), n = nodes count, s = key lengths sum
163// to lower estimation add unpredictable count of string clonings
164// and buffers (capacity-) reallocations
165fn ext(ab: &Alphabet, buff: &mut String, re: Re, o: &mut Vec<(String, usize)>) {
166    for ix in 0..ab.len() {
167        buff.push(re(ix));
168
169        let letter = &ab[ix];
170
171        if let Some(ct) = letter.ct {
172            let key = buff.clone();
173            o.push((key, ct));
174        }
175
176        if let Some(ab) = letter.ab.as_ref() {
177            ext(ab, buff, re, o);
178        }
179
180        _ = buff.pop();
181    }
182}
183
184/// Trie Occurrence Counter is frequency dictionary that uses any `impl Iterator<Item = char>` type as occurrent.
185///
186/// OOB English letters A–Za–z support only.
187///
188/// ```
189/// use t_oc::Toc;
190/// use std::panic::catch_unwind;
191///
192/// let mut toc = Toc::new();
193/// let occurrent = "true";
194///
195/// _ = toc.add(occurrent.chars(), None);
196/// _ = toc.add(true.to_string().chars(), None);
197///
198/// assert_eq!(2, toc.acq(occurrent.chars()).unwrap());
199/// toc.put(occurrent.chars(), 15);
200/// assert_eq!(15, toc.acq(occurrent.chars()).unwrap());
201///
202/// let catch = catch_unwind(move|| _ = toc.add("#&%".chars(), None));
203/// assert!(catch.is_err());
204/// ```
205///
206/// When asymptotic computational complexity is not explicitly specified , it is:
207/// - TC: Θ(c) where c is count of `char`s iterated over.
208/// - SC: Θ(0).
209pub struct Toc {
210    // tree root
211    rt: Alphabet,
212    // index fn
213    ix: Ix,
214    // rev index fn
215    re: Option<Re>,
216    // alphabet len
217    al: usize,
218    // backtrace buff
219    tr: UC<Vec<*mut Letter>>,
220    // occurrent count
221    ct: usize,
222}
223
224impl Toc {
225    /// Constructs default version of `Toc`, i.e. via
226    /// `fn new_with()` with `english_letters::{ix, re, ALPHABET_LEN}`.
227    pub fn new() -> Self {
228        Self::new_with(
229            english_letters::ix,
230            Some(english_letters::re),
231            english_letters::ALPHABET_LEN,
232        )
233    }
234
235    /// Allows to use custom alphabet different from default alphabet.
236    ///
237    /// ```
238    /// use t_oc::Toc;
239    ///
240    /// fn ix(c: char) -> usize {
241    ///     match c {
242    ///         '&' => 0,
243    ///         '|' => 1,
244    ///         _ => panic!(),
245    ///     }
246    /// }
247    ///
248    /// // if `fn Toc::ext` will not be used, pass `None` for `re`
249    /// fn re(i: usize) -> char {
250    ///     match i {
251    ///         0 => '&',
252    ///         1 => '|',
253    ///         _ => panic!(),
254    ///     }
255    /// }
256    ///
257    /// let ab_len = 2;
258    ///
259    /// let mut toc = Toc::new_with(ix, Some(re), ab_len);
260    /// let a = "&";
261    /// let b = "|";
262    /// let aba = "&|&";
263    /// _ = toc.add(a.chars(), None);
264    /// _ = toc.add(a.chars(), None);
265    /// _ = toc.add(b.chars(), None);
266    /// _ = toc.add(aba.chars(), None);
267    /// assert_eq!(2, toc.acq(a.chars()).unwrap());
268    /// assert_eq!(1, toc.acq(aba.chars()).unwrap());
269    pub fn new_with(ix: Ix, re: Option<Re>, ab_len: usize) -> Self {
270        Self {
271            rt: ab(ab_len),
272            ix,
273            re,
274            al: ab_len,
275            tr: UC::new(Vec::new()),
276            ct: 0,
277        }
278    }
279
280    /// Used to set internal backtracing buffer capacity.
281    ///
282    /// `Toc` uses internal buffer, to avoid excessive allocations and copying, which grows
283    /// over time due backtracing in `rem` method which backtraces whole path from entry
284    /// node to root node.
285    ///
286    /// Use this method to shrink or extend it to fit actual program needs. Neither shrinking nor extending
287    /// is guaranteed to be exact. See `Vec::with_capacity()` and `Vec::reserve()`. For optimal `rem` performance, set `approx_cap` to, at least, `occurrent.count()`.
288    ///
289    /// Some high value is sufficient anyway. Since buffer continuous
290    /// usage, its capacity will likely expand at some point in time to size sufficient to all occurrents.
291    ///
292    /// Return value is actual buffer capacity.
293    ///
294    /// **Note:** While `String` is UTF8 encoded, its byte length does not have to equal its `char` count
295    /// which is either equal or lesser.
296    /// ```
297    /// let sights = "🤩";
298    /// assert_eq!(4, sights.len());
299    /// assert_eq!(1, sights.chars().count());
300    ///
301    /// let yes = "sí";
302    /// assert_eq!(3, yes.len());
303    /// assert_eq!(2, yes.chars().nth(1).unwrap().len_utf8());
304    ///
305    /// let abc = "abc";
306    /// assert_eq!(3, abc.len());
307    /// ```
308    pub fn put_trace_cap(&mut self, approx_cap: usize) -> usize {
309        let tr = &mut self.tr;
310        let cp = tr.capacity();
311
312        if cp < approx_cap {
313            tr.reserve(approx_cap);
314        } else if cp > approx_cap {
315            *tr.aq_mut() = Vec::with_capacity(approx_cap);
316        }
317
318        tr.capacity()
319    }
320
321    /// Used to obtain internal backtracing buffer capacity.
322    ///
323    /// Check with `fn put_trace_cap` for details.
324    pub fn acq_trace_cap(&self) -> usize {
325        self.tr.capacity()
326    }
327
328    /// Used to add occurence to tree.
329    ///
330    /// Counter is of word size. Add overflow is wrapped using [`usize::wrapping_add`].
331    ///
332    /// Optional `val` parameter can be used to insert exact value.
333    ///
334    /// Return value is `Ok(Option<usize>)` for non-zero occurent and holds previous value, if there was some.
335    ///
336    /// Only invalid key classified is zero-length key.
337    ///
338    /// - SC: Θ(q) where q is number of unique nodes, i.e. `char`s in respective branches.
339    pub fn add(&mut self, mut occurrent: impl Iterator<Item = char>, val: Option<usize>) -> AddRes {
340        let c = occurrent.next();
341
342        if c.is_none() {
343            return Err(KeyError::ZeroLen);
344        }
345
346        let c = unsafe { c.unwrap_unchecked() };
347
348        let ix = self.ix;
349        let al = self.al;
350
351        let mut letter = &mut self.rt[ix(c)];
352
353        while let Some(c) = occurrent.next() {
354            let alphabet = letter.ab.get_or_insert_with(|| ab(al));
355            letter = &mut alphabet[ix(c)];
356        }
357
358        let ct = letter.ct;
359
360        let ct_none = ct.is_none();
361        if ct_none {
362            self.ct += 1;
363        }
364
365        letter.ct = Some(if let Some(v) = val {
366            v
367        } else {
368            if ct_none {
369                1
370            } else {
371                unsafe { ct.unwrap_unchecked() }.wrapping_add(1)
372            }
373        });
374
375        Ok(ct)
376    }
377
378    /// Used to acquire value for `occurrent`.
379    ///
380    /// If `Ok(usize)`, `usize` is `occurrent` occurrences count.
381    pub fn acq(&self, occurrent: impl Iterator<Item = char>) -> VerRes {
382        let track_res = self.track(occurrent, false, false);
383        if let TraRes::Ok(l) = track_res {
384            let ct = l.ct;
385            let ct = unsafe { ct.unwrap_unchecked() };
386            Ok(ct)
387        } else {
388            Err(track_res.ver_res())
389        }
390    }
391
392    /// Used to put new value for `occurrent` occurrences.
393    ///
394    /// If `Ok(usize)`, `usize` is previous value.
395    pub fn put(&mut self, occurrent: impl Iterator<Item = char>, val: usize) -> VerRes {
396        let track_res = self.track(occurrent, false, true);
397
398        if let TraRes::OkMut(l) = track_res {
399            let old = l.ct.replace(val);
400            let old = unsafe { old.unwrap_unchecked() };
401            Ok(old)
402        } else {
403            Err(track_res.ver_res())
404        }
405    }
406
407    /// Used to remove `occurrent` from tree.
408    ///
409    /// If `Ok(usize)`, `usize` is `occurrent` occurrences count.
410    ///
411    /// - _c_ is count of `char`s iterated over.
412    /// - TC: Ω(c) or ϴ(c) (backtracing buffer capacity dependent complexity).
413    /// - SC: ϴ(c).
414    ///
415    /// Check with `put_trace_cap` for details on backtracing.
416    pub fn rem(&mut self, occurrent: impl Iterator<Item = char>) -> VerRes {
417        let track_res = self.track(occurrent, true, false);
418        let res = if let TraRes::Ok(_) = track_res {
419            let ct = Self::rem_actual(self);
420            self.ct -= 1;
421            Ok(ct)
422        } else {
423            Err(track_res.ver_res())
424        };
425
426        self.tr.clear();
427        res
428    }
429
430    fn rem_actual(&mut self) -> usize {
431        let mut trace = self.tr.iter().map(|x| unsafe { x.as_mut() }.unwrap());
432        let entry = unsafe { trace.next_back().unwrap_unchecked() };
433
434        let ct = entry.ct.take();
435
436        if !entry.ab() {
437            while let Some(l) = trace.next_back() {
438                let alphabet = l.ab.as_ref().unwrap();
439                let mut remove_alphab = true;
440
441                for ix in 0..self.al {
442                    let letter = &alphabet[ix];
443
444                    if letter.ab() || letter.ct() {
445                        remove_alphab = false;
446                        break;
447                    }
448                }
449
450                if remove_alphab {
451                    l.ab = None;
452                } else {
453                    break;
454                }
455
456                if l.ct() {
457                    break;
458                }
459            }
460        }
461
462        unsafe { ct.unwrap_unchecked() }
463    }
464
465    // - s is count of `char`s iterated over
466    // - TC: Ω(s) when `tracing = true`, ϴ(s) otherwise
467    // - SC: ϴ(s) when `tracing = true`, ϴ(0) otherwise
468    fn track(
469        &self,
470        mut occurrent: impl Iterator<Item = char>,
471        tracing: bool,
472        okmut: bool,
473    ) -> TraRes {
474        let c = occurrent.next();
475
476        if c.is_none() {
477            return TraRes::ZeroLen;
478        }
479
480        let c = unsafe { c.unwrap_unchecked() };
481
482        let ix = &self.ix;
483        let tr = self.tr.uplift();
484
485        let mut letter = &self.rt[ix(c)];
486
487        loop {
488            if tracing {
489                tr.push(letter.to_mut_ptr())
490            }
491
492            if let Some(c) = occurrent.next() {
493                if let Some(ab) = letter.ab.as_ref() {
494                    letter = &ab[ix(c)];
495                } else {
496                    return TraRes::UnknownForAbsentPath;
497                }
498            } else {
499                break;
500            }
501        }
502
503        if letter.ct() {
504            if okmut {
505                let l_mut = unsafe { letter.to_mut_ptr().as_mut().unwrap_unchecked() };
506                TraRes::OkMut(l_mut)
507            } else {
508                TraRes::Ok(letter)
509            }
510        } else {
511            TraRes::UnknownForNotEntry
512        }
513    }
514
515    /// Used to extract occurences from tree.
516    ///
517    /// Extraction is alphabetically ordered. Does not clear tree. Use `fn clr` for clearing.
518    ///
519    /// Return value is `None` for empty `Toc`.
520    ///
521    /// - TC: Ω(n) where n is count of nodes in tree.
522    /// - SC: Θ(s) where s is occurrent lengths summation.
523    ///
524    /// Returned set can be overcapacitated, i.e. its capacity
525    /// will not be shrunken according to its length.
526    pub fn ext(&self) -> Option<Vec<(String, usize)>> {
527        if let Some(re) = self.re {
528            if self.ct == 0 {
529                return None;
530            }
531
532            // capacity is prebuffered to 1000
533            let mut buff = String::with_capacity(1000);
534
535            // capacity is prebuffered to 1000
536            let mut res = Vec::with_capacity(1000);
537
538            ext(&self.rt, &mut buff, re, &mut res);
539            Some(res)
540        } else {
541            panic!("This method is unsupported when `new_with` `re` parameter is provided with `None`.");
542        }
543    }
544
545    /// Used to clear tree.
546    ///
547    /// Return value is count of occurrents in tree before clearing.
548    ///
549    /// TC: Θ(n) where n is count of nodes in tree.
550    pub fn clr(&mut self) -> usize {
551        self.rt = ab(self.al);
552        let ct = self.ct;
553        self.ct = 0;
554        ct
555    }
556
557    /// Used to acquire count of occurrents in tree.
558    pub const fn ct(&self) -> usize {
559        self.ct
560    }
561}
562
563#[cfg(test)]
564mod tests_of_units {
565
566    use crate::Letter;
567    use std::fmt::{Debug, Formatter};
568
569    impl Debug for Letter {
570        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
571            let ab = some_none(self.ab.as_ref());
572
573            return f.write_fmt(format_args!(
574                "Letter {{\n  val: {}\n  ab: {}\n  ct: {:?}\n}}",
575                self.val, ab, self.ct
576            ));
577
578            fn some_none<T>(val: Option<&T>) -> &'static str {
579                if val.is_some() {
580                    "Some"
581                } else {
582                    "None"
583                }
584            }
585        }
586    }
587
588    mod letter {
589
590        use crate::{Letter, ab as ab_fn};
591
592        #[test]
593        fn new() {
594            let letter = Letter::new();
595
596            assert_eq!('💚', letter.val);
597            assert!(letter.ab.is_none());
598            assert!(letter.ct.is_none());
599        }
600
601        #[test]
602        fn ab() {
603            let mut letter = Letter::new();
604            assert_eq!(false, letter.ab());
605
606            letter.ab = Some(ab_fn(0));
607            assert_eq!(true, letter.ab());
608        }
609
610        #[test]
611        fn ct() {
612            let mut letter = Letter::new();
613            assert_eq!(false, letter.ct());
614
615            letter.ct = Some(0);
616            assert_eq!(true, letter.ct());
617        }
618    }
619
620    mod ab {
621
622        use crate::english_letters::ALPHABET_LEN;
623        use crate::ab as ab_fn;
624
625        #[test]
626        fn ab() {
627            let ab = ab_fn(ALPHABET_LEN);
628            assert_eq!(ALPHABET_LEN, ab.len());
629
630            #[cfg(feature = "test-ext")]
631            {
632                let chain = ('A'..='Z').chain('a'..='z');
633
634                for (ix, c) in chain.enumerate() {
635                    let letter = &ab[ix];
636
637                    assert_eq!(c, letter.val);
638                    assert!(letter.ab.is_none());
639                    assert!(letter.ct.is_none());
640                }
641            }
642        }
643
644        #[test]
645        fn zero_len() {
646            let ab = ab_fn(0);
647            assert_eq!(0, ab.len());
648        }
649    }
650
651    mod english_letters {
652
653        use crate::english_letters::{ALPHABET_LEN, BASE_ALPHABET_LEN};
654
655        #[test]
656        fn consts() {
657            assert_eq!(26, BASE_ALPHABET_LEN);
658            assert_eq!(52, ALPHABET_LEN);
659        }
660
661        mod ix {
662            use crate::english_letters::ix;
663            use std::panic::catch_unwind;
664
665            #[test]
666            fn ixes() {
667                assert_eq!(0, ix('A'));
668                assert_eq!(25, ix('Z'));
669                assert_eq!(26, ix('a'));
670                assert_eq!(51, ix('z'));
671            }
672
673            #[test]
674            fn unsupported_char() {
675                let ucs = unsupported_chars();
676
677                for (c, cp) in ucs.map(|x| (x as char, x)) {
678                    let result = catch_unwind(|| ix(c));
679                    assert!(result.is_err());
680
681                    let err = unsafe { result.unwrap_err_unchecked() };
682                    let downcast = err.downcast_ref::<String>().unwrap();
683                    let proof = format!(
684                        "Index conversion failed because code point `{cp}` is unsupported."
685                    );
686                    assert_eq!(&proof, downcast);
687                }
688            }
689
690            fn unsupported_chars() -> [u8; 4] {
691                #[rustfmt::skip] let ucs =
692                [
693                    'A' as u8 -1, 'Z' as u8 +1, // 65–90
694                    'a' as u8 -1, 'z' as u8 +1, // 97–122
695                ];
696                ucs
697            }
698        }
699
700        mod re {
701            use crate::english_letters::re;
702
703            #[test]
704            fn ixes() {
705                assert_eq!('A', re(0));
706                assert_eq!('Z', re(25));
707                assert_eq!('a', re(26));
708                assert_eq!('z', re(51));
709            }
710
711            #[test]
712            #[should_panic(
713                expected = "Char conversion failed because index `52` conversion is not supported."
714            )]
715            fn unsupported_ix() {
716                _ = re(52)
717            }
718        }
719    }
720
721    mod ext {
722
723        type Nest = (char, usize);
724
725        use crate::{ab as ab_ctor, ext, Alphabet};
726        use crate::english_letters::{ALPHABET_LEN, ix, re};
727
728        fn ab_fn() -> Alphabet {
729            ab_ctor(ALPHABET_LEN)
730        }
731
732        #[test]
733        fn basic_test() {
734            let mut ab = ab_fn();
735
736            ab[ix('A')].ct = Some(1);
737            ab[ix('z')].ct = Some(2);
738
739            let mut buff = String::new();
740            let mut test = Vec::new();
741
742            ext(&ab, &mut buff, re, &mut test);
743
744            let proof = vec![(String::from("A"), 1), (String::from("z"), 2)];
745            assert_eq!(proof, test);
746        }
747
748        #[test]
749        fn nesting() {
750            let mut root = ab_fn();
751
752            let nesting = [
753                (('A', 3), ('z', 5)),
754                (('B', 5), ('y', 8)),
755                (('y', 10), ('B', 12)),
756                (('z', 99), ('A', 103)),
757            ];
758
759            for n in nesting {
760                prep(&mut root, n);
761            }
762
763            let mut buff = String::new();
764            let mut test = Vec::new();
765
766            ext(&root, &mut buff, re, &mut test);
767
768            let proof = vec![
769                (String::from("A"), 3),
770                (String::from("Az"), 5),
771                (String::from("B"), 5),
772                (String::from("By"), 8),
773                (String::from("y"), 10),
774                (String::from("yB"), 12),
775                (String::from("z"), 99),
776                (String::from("zA"), 103),
777            ];
778
779            assert_eq!(proof, test);
780
781            fn prep(ab: &mut Alphabet, n: (Nest, Nest)) {
782                let ultra = n.0;
783                let infra = n.1;
784
785                let u_l = &mut ab[ix(ultra.0)];
786                let mut ul_ab = ab_fn();
787
788                let i_l = &mut ul_ab[ix(infra.0)];
789                i_l.ct = Some(infra.1);
790
791                u_l.ab = Some(ul_ab);
792                u_l.ct = Some(ultra.1);
793            }
794        }
795
796        #[test]
797        fn in_depth_recursion() {
798            let mut root = ab_fn();
799
800            let paths = [
801                ("AA", 13),
802                ("AzBq", 11),
803                ("By", 329),
804                ("ZaZazAzAzAbYyb", 55),
805                ("yBC", 7),
806                ("ybXr", 53),
807                ("ybXrQUTmop", 33),
808                ("ybXrQUTmopFVB", 99),
809                ("ybXrQUTmopRFG", 80),
810                ("zAzAZaZaZaByYB", 44),
811            ];
812
813            for p in paths {
814                let mut chars = p.0.chars();
815                let mut le = &mut root[ix(chars.next().unwrap())];
816
817                while let Some(c) = chars.next() {
818                    let ab = le.ab.get_or_insert_with(|| ab_fn());
819                    le = &mut ab[ix(c)];
820                }
821
822                le.ct = Some(p.1)
823            }
824
825            let mut buff = String::new();
826            let mut test = Vec::new();
827
828            ext(&root, &mut buff, re, &mut test);
829
830            let proof = vec![
831                (String::from("AA"), 13),
832                (String::from("AzBq"), 11),
833                (String::from("By"), 329),
834                (String::from("ZaZazAzAzAbYyb"), 55),
835                (String::from("yBC"), 7),
836                (String::from("ybXr"), 53),
837                (String::from("ybXrQUTmop"), 33),
838                (String::from("ybXrQUTmopFVB"), 99),
839                (String::from("ybXrQUTmopRFG"), 80),
840                (String::from("zAzAZaZaZaByYB"), 44),
841            ];
842
843            assert_eq!(proof, test);
844        }
845    }
846
847    mod track_res {
848        use crate::{TraRes, Letter};
849        use crate::KeyError::{ZeroLen, Unknown};
850
851        #[test]
852        fn ver_res_convertible() {
853            assert_eq!(ZeroLen, TraRes::ZeroLen.ver_res());
854            assert_eq!(Unknown, TraRes::UnknownForAbsentPath.ver_res());
855            assert_eq!(Unknown, TraRes::UnknownForNotEntry.ver_res());
856        }
857
858        use std::{ops::Deref, panic::catch_unwind};
859        #[test]
860        fn ver_res_nonconvertible() {
861            let err = catch_unwind(|| TraRes::Ok(&Letter::new()).ver_res());
862
863            assert_eq!(true, err.is_err());
864            assert_eq!(
865                &"Unsupported",
866                err.unwrap_err().downcast::<&str>().unwrap().deref()
867            );
868
869            let err = catch_unwind(|| TraRes::OkMut(&mut Letter::new()).ver_res());
870
871            assert_eq!(true, err.is_err());
872            assert_eq!(
873                &"Unsupported",
874                err.unwrap_err().downcast::<&str>().unwrap().deref()
875            );
876        }
877    }
878
879    mod toc {
880        use crate::{Toc, ab};
881        use crate::english_letters::{ix, re, ALPHABET_LEN};
882
883        #[test]
884        fn new() {
885            let toc = Toc::new();
886            assert_eq!(ALPHABET_LEN, toc.al);
887            assert_eq!(ix as usize, toc.ix as usize);
888            assert_eq!(re as usize, toc.re.unwrap() as usize);
889        }
890
891        #[test]
892        fn new_with() {
893            fn test_ix(_c: char) -> usize {
894                0
895            }
896
897            fn test_re(_i: usize) -> char {
898                '\0'
899            }
900
901            let ab_len = 10;
902            let toc = Toc::new_with(test_ix, Some(test_re), ab_len);
903
904            assert_eq!(ab(ab_len), toc.rt);
905            assert_eq!(ab_len, toc.al);
906            assert_eq!(test_ix as usize, toc.ix as usize);
907            assert_eq!(test_re as usize, toc.re.unwrap() as usize);
908            assert_eq!(0, toc.tr.capacity());
909            assert_eq!(0, toc.ct);
910        }
911
912        mod put_trace_cap {
913            use crate::Toc;
914
915            #[test]
916            fn extend() {
917                const NEW_CAP: usize = 10;
918
919                let mut toc = Toc::new();
920                assert!(toc.tr.capacity() < NEW_CAP);
921
922                let size = toc.put_trace_cap(NEW_CAP);
923                assert!(size >= NEW_CAP);
924                assert!(toc.tr.capacity() >= NEW_CAP);
925            }
926
927            #[test]
928            fn shrink() {
929                const NEW_CAP: usize = 10;
930                const OLD_CAP: usize = 50;
931
932                let mut toc = Toc::new();
933                *toc.tr = Vec::with_capacity(OLD_CAP);
934
935                let size = toc.put_trace_cap(NEW_CAP);
936                assert!(size >= NEW_CAP && size < OLD_CAP);
937                let cap = toc.tr.capacity();
938                assert!(cap >= NEW_CAP && cap < OLD_CAP);
939            }
940
941            #[test]
942            fn same() {
943                let mut toc = Toc::new();
944                let cap = toc.tr.capacity();
945
946                let size = toc.put_trace_cap(cap);
947                assert_eq!(cap, size);
948                assert_eq!(cap, toc.tr.capacity());
949            }
950        }
951
952        #[test]
953        fn acq_trace_cap() {
954            const VAL: usize = 10;
955
956            let mut toc = Toc::new();
957            let tr = &mut toc.tr;
958
959            assert!(tr.capacity() < VAL);
960            tr.reserve_exact(VAL);
961            let cap = tr.capacity();
962            assert_eq!(cap, toc.acq_trace_cap());
963        }
964
965        mod add {
966            use crate::Toc;
967            use crate::KeyError::ZeroLen;
968            use crate::english_letters::ix;
969
970            #[test]
971            fn basic_test() {
972                let entry = || "impreciseness".chars();
973
974                let mut toc = Toc::new();
975                assert_eq!(Ok(None), toc.add(entry(), None));
976                assert_eq!(1, toc.ct);
977
978                let chars: Vec<char> = entry().collect();
979                let len = chars.len();
980                let last_ix = len - 1;
981
982                let mut sup_ab = &toc.rt;
983                for c_ix in 0..len {
984                    let c = chars[c_ix];
985                    let l = &sup_ab[ix(c)];
986
987                    let terminal_it = c_ix == last_ix;
988
989                    let sub_ab = l.ab.as_ref();
990                    assert_eq!(terminal_it, sub_ab.is_none(), "{c_ix}, {c}, {terminal_it}",);
991
992                    if terminal_it {
993                        let ct = l.ct.as_ref();
994                        assert!(ct.is_some());
995                        let ct = unsafe { ct.unwrap_unchecked() };
996                        assert_eq!(&1, ct);
997                    } else {
998                        sup_ab = unsafe { sub_ab.unwrap_unchecked() };
999                    }
1000                }
1001            }
1002
1003            #[test]
1004            fn zero_occurrent() {
1005                let mut toc = Toc::new();
1006                assert_eq!(Err(ZeroLen), toc.add("".chars(), None));
1007                assert_eq!(0, toc.ct);
1008            }
1009
1010            #[test]
1011            fn singular_occurrent() {
1012                let mut toc = Toc::new();
1013                assert_eq!(Ok(None), toc.add("a".chars(), None));
1014                assert_eq!(Some(1), toc.rt[ix('a')].ct);
1015                assert_eq!(1, toc.ct);
1016            }
1017
1018            #[test]
1019            fn double_add() {
1020                let entry = || "impreciseness".chars();
1021
1022                let mut toc = Toc::new();
1023                assert_eq!(Ok(None), toc.add(entry(), None));
1024                assert_eq!(1, toc.ct);
1025
1026                assert_eq!(Ok(Some(1)), toc.add(entry(), None));
1027                assert_eq!(1, toc.ct);
1028
1029                let chars: Vec<char> = entry().collect();
1030                let len = chars.len();
1031                let last_ix = len - 1;
1032
1033                let mut sup_ab = &toc.rt;
1034                for c_ix in 0..len {
1035                    let c = chars[c_ix];
1036                    let l = &sup_ab[ix(c)];
1037
1038                    let terminal_it = c_ix == last_ix;
1039
1040                    let sub_ab = l.ab.as_ref();
1041                    assert_eq!(terminal_it, sub_ab.is_none(), "{c_ix}, {c}, {terminal_it}",);
1042
1043                    if terminal_it {
1044                        let ct = l.ct.as_ref();
1045                        assert!(ct.is_some());
1046                        let ct = unsafe { ct.unwrap_unchecked() };
1047                        assert_eq!(&2, ct);
1048                    } else {
1049                        sup_ab = unsafe { sub_ab.unwrap_unchecked() };
1050                    }
1051                }
1052            }
1053
1054            #[test]
1055            fn exact() {
1056                let entry = || "impreciseness".chars();
1057                const VAL: usize = 15;
1058
1059                let mut toc = Toc::new();
1060                assert_eq!(Ok(None), toc.add(entry(), Some(VAL)));
1061                assert_eq!(1, toc.ct);
1062
1063                assert_eq!(Ok(VAL), toc.acq(entry()));
1064            }
1065
1066            #[test]
1067            fn exact_over() {
1068                let entry = || "impreciseness".chars();
1069                const VAL: usize = 15;
1070
1071                let mut toc = Toc::new();
1072                _ = toc.add(entry(), None);
1073                assert_eq!(1, toc.ct);
1074
1075                assert_eq!(Ok(Some(1)), toc.add(entry(), Some(VAL)));
1076                assert_eq!(1, toc.ct);
1077
1078                assert_eq!(Ok(VAL), toc.acq(entry()));
1079            }
1080
1081            #[test]
1082            #[allow(non_snake_case)]
1083            #[rustfmt::skip]
1084            #[cfg(feature = "test-ext")]
1085            fn load() {
1086
1087                let strs = [
1088                    ("zzbb", 44_441), ("zzaa", 88_999),
1089                    ("xya", 77_666), ("xyz", 22_333),
1090                    ("abc", 33_222), ("abd", 74_332),
1091                    ("abcd", 11_234), ("abce", 11_234),
1092                    ("qaa", 16_678), ("qrs", 24_555),
1093                    ("qrt", 900_001), ("qua", 130_901),
1094                    ("qwa", 2_006),
1095                    ("percent", 77_110), ("percentile", 99_888),
1096                    ("quail", 20_333), ("qualification", 33_111),
1097                    ("quality", 555_666), ("quantity", 116_777),
1098                    ("XYAB", 544_555), ("XYABA", 111_900),
1099                    ("JUI", 30_000), ("JUN", 100_000),
1100                    ("XYA", 80_000), ("XYQ", 11_111),
1101                    ("XYZ", 111_333), ("XYABC", 222_000),
1102                    ("MOMENT", 15_999), ("INSTANT", 34_341),
1103                    ("JUNCTURE", 789_223),
1104                    ("ABC", 14_234), ("ABD", 34_123)
1105                ];
1106
1107                let mut toc = Toc::new();
1108                for (s, c) in strs {
1109                    for i in 0..c {
1110                        let res = toc.add(s.chars(), None);
1111                        let prev = if i > 0 {
1112                            Some(i)
1113                        } else {
1114                            None
1115                        };        
1116                        assert_eq!(Ok(prev), res);
1117                    }
1118                }
1119
1120                for (s, c) in strs {
1121                    let res = toc.acq(s.chars());
1122                    assert_eq!(Ok(c), res);                 
1123                }
1124                
1125                assert_eq!(strs.len(), toc.ct);
1126            }
1127
1128            #[test]
1129            fn overflow_wrap() {
1130                let mut toc = Toc::new();
1131
1132                let entry = || "a".chars();
1133
1134                _ = toc.add(entry(), None);
1135                _ = toc.put(entry(), usize::MAX);
1136                _ = toc.add(entry(), None);
1137                assert_eq!(Ok(0), toc.acq(entry()));
1138                assert_eq!(1, toc.ct);
1139            }
1140        }
1141
1142        mod acq {
1143            use crate::Toc;
1144            use crate::KeyError::{ZeroLen, Unknown};
1145
1146            #[test]
1147            #[allow(non_upper_case_globals)]
1148            fn known_unknown() {
1149                let a = || "a".chars();
1150                let b = || "b".chars();
1151
1152                let mut toc = Toc::new();
1153                _ = toc.add(a(), None);
1154
1155                assert_eq!(Ok(1), toc.acq(a()));
1156                assert_eq!(Err(Unknown), toc.acq(b()));
1157            }
1158
1159            #[test]
1160            fn zero_occurrent() {
1161                let toc = Toc::new();
1162                assert_eq!(Err(ZeroLen), toc.acq("".chars()));
1163            }
1164        }
1165
1166        mod put {
1167            use crate::Toc;
1168            use crate::KeyError::{ZeroLen, Unknown};
1169
1170            #[test]
1171            #[allow(non_upper_case_globals)]
1172            fn known_unknown() {
1173                let a = || "a".chars();
1174                let b = || "b".chars();
1175
1176                let mut toc = Toc::new();
1177                _ = toc.add(a(), None);
1178
1179                assert_eq!(Ok(1), toc.put(a(), 3));
1180                assert_eq!(Ok(3), toc.acq(a()));
1181                assert_eq!(Err(Unknown), toc.put(b(), 3));
1182            }
1183
1184            #[test]
1185            fn zero_occurrent() {
1186                let mut toc = Toc::new();
1187                assert_eq!(Err(ZeroLen), toc.put("".chars(), 3));
1188            }
1189        }
1190
1191        mod rem {
1192            use crate::Toc;
1193            use crate::KeyError::{ZeroLen, Unknown};
1194
1195            #[test]
1196            fn known_unknown() {
1197                let known = || "VigilantAndVigourous".chars();
1198                let unknown = || "NeglectfulAndFeeble".chars();
1199
1200                let mut toc = Toc::new();
1201                _ = toc.add(known(), None);
1202
1203                assert_eq!(Err(Unknown), toc.rem(unknown()));
1204                assert_eq!(0, toc.tr.len());
1205
1206                assert_eq!(1, toc.ct());
1207
1208                assert_eq!(Ok(1), toc.rem(known()));
1209                assert_eq!(Err(Unknown), toc.acq(known()));
1210                assert_eq!(0, toc.tr.len());
1211
1212                assert_eq!(0, toc.ct());
1213            }
1214
1215            #[test]
1216            fn zero_occurrent() {
1217                let mut toc = Toc::new();
1218                assert_eq!(Err(ZeroLen), toc.rem("".chars()));
1219            }
1220        }
1221
1222        mod rem_actual {
1223            use crate::{Toc, TraRes};
1224            use crate::KeyError::Unknown;
1225            use crate::english_letters::ix;
1226
1227            #[test]
1228            fn basic_test() {
1229                let entry = || "ABCxyz".chars();
1230                let mut toc = Toc::new();
1231                _ = toc.add(entry(), None);
1232
1233                _ = toc.track(entry(), true, false);
1234
1235                assert_eq!(1, Toc::rem_actual(&mut toc));
1236
1237                #[allow(non_snake_case)]
1238                let K = &toc.rt[ix('A')];
1239                assert_eq!(false, K.ab());
1240            }
1241
1242            #[test]
1243            fn ab_len_test() {
1244                let ix = |c| match c {
1245                    | 'a' => 0,
1246                    | 'z' => 99,
1247                    | _ => panic!(),
1248                };
1249
1250                let key_1 = || "aaa".chars();
1251                let key_2 = || "aaz".chars();
1252
1253                let key_1_val = 50;
1254                let key_2_val = 60;
1255
1256                let mut toc = Toc::new_with(ix, None, 100);
1257                _ = toc.add(key_1(), Some(key_1_val));
1258                _ = toc.add(key_2(), Some(key_2_val));
1259
1260                _ = toc.track(key_1(), true, false);
1261
1262                assert_eq!(key_1_val, Toc::rem_actual(&mut toc));
1263                assert!(toc.acq(key_2()).is_ok());
1264            }
1265
1266            #[test]
1267            fn inner_entry() {
1268                let mut toc = Toc::new();
1269
1270                let outer = || "Keyword".chars();
1271                _ = toc.add(outer(), None);
1272
1273                let inner = || "Key".chars();
1274                _ = toc.add(inner(), None);
1275
1276                _ = toc.track(inner(), true, false);
1277
1278                assert_eq!(1, Toc::rem_actual(&mut toc));
1279                assert_eq!(Err(Unknown), toc.acq(inner()));
1280                assert_eq!(Ok(1), toc.acq(outer()));
1281            }
1282
1283            #[test]
1284            fn entry_with_peer_entry() {
1285                let mut toc = Toc::new();
1286
1287                let peer = || "Keyworder".chars();
1288                _ = toc.add(peer(), None);
1289
1290                let test = || "Keywordee".chars();
1291                _ = toc.add(test(), None);
1292
1293                _ = toc.track(test(), true, false);
1294
1295                assert_eq!(1, Toc::rem_actual(&mut toc));
1296                assert_eq!(Err(Unknown), toc.acq(test()));
1297                assert_eq!(Ok(1), toc.acq(peer()));
1298            }
1299
1300            #[test]
1301            fn entry_with_peer_with_alphabet() {
1302                let mut toc = Toc::new();
1303
1304                let peer = || "Keyworders".chars();
1305                _ = toc.add(peer(), None);
1306
1307                let test = || "Keywordee".chars();
1308                _ = toc.add(test(), None);
1309
1310                _ = toc.track(test(), true, false);
1311
1312                assert_eq!(1, Toc::rem_actual(&mut toc));
1313                assert_eq!(Err(Unknown), toc.acq(test()));
1314                assert_eq!(Ok(1), toc.acq(peer()));
1315            }
1316
1317            #[test]
1318            fn entry_under_entry() {
1319                let mut toc = Toc::new();
1320
1321                let above = || "Keyworder".chars();
1322                _ = toc.add(above(), None);
1323
1324                let under = || "Keyworders".chars();
1325                _ = toc.add(under(), None);
1326
1327                _ = toc.track(under(), true, false);
1328
1329                assert_eq!(1, Toc::rem_actual(&mut toc));
1330                assert_eq!(Err(Unknown), toc.acq(under()));
1331                assert_eq!(Ok(1), toc.acq(above()));
1332
1333                let res = toc.track(above(), false, false);
1334                if let TraRes::Ok(l) = res {
1335                    #[cfg(feature = "test-ext")]
1336                    assert_eq!('r', l.val);
1337                    assert_eq!(false, l.ab());
1338                } else {
1339                    panic!("TraRes::Ok(_) was expected, instead {:?}.", res);
1340                }
1341            }
1342        }
1343
1344        mod track {
1345            use crate::{Toc, TraRes};
1346
1347            #[test]
1348            fn zero_occurrent() {
1349                let toc = Toc::new();
1350                let res = toc.track("".chars(), false, false);
1351                assert_eq!(TraRes::ZeroLen, res);
1352            }
1353
1354            #[test]
1355            #[cfg(feature = "test-ext")]
1356            fn singular_occurrent() {
1357                let entry = || "A".chars();
1358
1359                let mut toc = Toc::new();
1360
1361                _ = toc.add(entry(), None);
1362                let res = toc.track(entry(), true, false);
1363
1364                if let TraRes::Ok(l) = res {
1365                    let l_val = l.val;
1366                    let tr = &toc.tr;
1367
1368                    assert_eq!('A', l_val);
1369                    assert_eq!(1, tr.len());
1370
1371                    let l = unsafe { tr[0].as_ref() }.unwrap();
1372                    assert_eq!('A', l.val)
1373                } else {
1374                    panic!("TraRes::Ok(_) was expected, instead {:?}.", res);
1375                }
1376            }
1377
1378            #[test]
1379            #[cfg(feature = "test-ext")]
1380            fn tracing() {
1381                let entry = || "DictionaryLexicon".chars();
1382
1383                let mut toc = Toc::new();
1384                _ = toc.add(entry(), None);
1385                _ = toc.track(entry(), true, false);
1386
1387                let proof = entry().collect::<Vec<char>>();
1388                let tr = &toc.tr;
1389
1390                assert_eq!(proof.len(), tr.len());
1391
1392                for (x, &c) in proof.iter().enumerate() {
1393                    let l = tr[x];
1394                    let l = unsafe { l.as_ref() }.unwrap();
1395                    assert_eq!(c, l.val);
1396                }
1397            }
1398
1399            #[test]
1400            #[cfg(feature = "test-ext")]
1401            fn ok_variants() {
1402                let entry = || "Wordbook".chars();
1403                let last = 'k';
1404
1405                let mut toc = Toc::new();
1406                _ = toc.add(entry(), None);
1407                let res = toc.track(entry(), false, false);
1408
1409                match res {
1410                    | TraRes::Ok(l) => assert_eq!(last, l.val),
1411                    | _ => panic!("TraRes::Ok(_) was expected, instead {:?}.", res),
1412                }
1413
1414                let res = toc.track(entry(), false, true);
1415                match res {
1416                    | TraRes::OkMut(l) => assert_eq!(last, l.val),
1417                    | _ => panic!("TraRes::OkMut(_) was expected, instead {:?}.", res),
1418                }
1419            }
1420
1421            #[test]
1422            fn unknown_not_path() {
1423                let key = || "Wordbook".chars();
1424                let bad_key = || "Wordbooks".chars();
1425
1426                let mut toc = Toc::new();
1427                _ = toc.add(key(), None);
1428                let res = toc.track(bad_key(), false, false);
1429                assert_eq!(TraRes::UnknownForAbsentPath, res);
1430            }
1431
1432            #[test]
1433            fn unknown_not_entry() {
1434                let key = || "Wordbooks".chars();
1435                let bad_key = || "Wordbook".chars();
1436
1437                let mut toc = Toc::new();
1438                _ = toc.add(key(), None);
1439                let res = toc.track(bad_key(), false, false);
1440                assert_eq!(TraRes::UnknownForNotEntry, res);
1441            }
1442        }
1443
1444        mod ext {
1445            use crate::Toc;
1446            use crate::english_letters::ix;
1447
1448            #[test]
1449            fn basic_test() {
1450                let proof = vec![
1451                    (String::from("AA"), 13),
1452                    (String::from("AzBq"), 11),
1453                    (String::from("By"), 329),
1454                    (String::from("ZaZazAzAzAbYyb"), 55),
1455                    (String::from("yBC"), 7),
1456                    (String::from("ybXr"), 53),
1457                    (String::from("ybXrQUTmop"), 33),
1458                    (String::from("ybXrQUTmopFVB"), 99),
1459                    (String::from("ybXrQUTmopRFG"), 80),
1460                    (String::from("zAzAZaZaZaByYB"), 44),
1461                ];
1462
1463                let mut toc = Toc::new();
1464                for p in proof.iter() {
1465                    _ = toc.add(p.0.chars(), Some(p.1));
1466                }
1467
1468                let ext = toc.ext();
1469                assert_eq!(true, ext.is_some());
1470
1471                let ext = ext.unwrap();
1472                assert_eq!(proof.len(), ext.len());
1473                assert_eq!(proof, ext);
1474                assert_eq!(true, ext.capacity() >= 1000);
1475
1476                for p in proof.iter() {
1477                    assert_eq!(Ok(p.1), toc.acq(p.0.chars()));
1478                }
1479            }
1480
1481            #[test]
1482            #[should_panic(
1483                expected = "This method is unsupported when `new_with` `re` parameter is provided with `None`."
1484            )]
1485            fn re_not_provided() {
1486                _ = Toc::new_with(ix, None, 0).ext()
1487            }
1488
1489            #[test]
1490            fn empty_tree() {
1491                let toc = Toc::new();
1492                assert_eq!(None, toc.ext());
1493            }
1494        }
1495
1496        use crate::KeyError::Unknown;
1497
1498        #[test]
1499        fn clr() {
1500            let key = || "abc".chars();
1501
1502            let mut toc = Toc::new();
1503            _ = toc.add(key(), None);
1504            assert_eq!(1, toc.clr());
1505
1506            assert_eq!(Err(Unknown), toc.acq(key()));
1507            assert_eq!(ab(ALPHABET_LEN), toc.rt);
1508            assert_eq!(0, toc.ct);
1509        }
1510
1511        #[test]
1512        fn ct() {
1513            let test = 3;
1514            let mut toc = Toc::new();
1515            assert_eq!(0, toc.ct());
1516            toc.ct = test;
1517            assert_eq!(test, toc.ct());
1518        }
1519    }
1520}
1521
1522// cargo fmt & cargo test --features test-ext --release
1523// cargo fmt & cargo test --release