sigma_types/
all_pairs.rs

1//! Iterable data structure in which each adjacent pair of elements satisfies a given invariant.
2
3use core::{fmt, marker::PhantomData};
4
5/// Iterable data structure in which each adjacent pair of elements satisfies a given invariant.
6#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct AllPairs<Invariant: crate::Test<Input::Item, 2>, Input: IntoIterator + fmt::Debug>(
8    PhantomData<Invariant>,
9    PhantomData<Input>,
10)
11where
12    Input::Item: fmt::Debug,
13    for<'i> &'i Input: IntoIterator<Item = &'i Input::Item>;
14
15impl<Invariant: crate::Test<Input::Item, 2>, Input: IntoIterator + fmt::Debug> crate::Test<Input, 1>
16    for AllPairs<Invariant, Input>
17where
18    Input::Item: fmt::Debug,
19    for<'i> &'i Input: IntoIterator<Item = &'i Input::Item>,
20{
21    const ADJECTIVE: &str = "all pairwise valid";
22
23    type Error<'i>
24        = NotAllPairs<'i, Input::Item, Invariant>
25    where
26        Input: 'i;
27
28    #[inline]
29    fn test([input]: [&Input; 1]) -> Result<(), Self::Error<'_>> {
30        let mut iter = input.into_iter();
31
32        // Since Rust can't reassign references,
33        // get a pointer for each item and reassign that instead:
34        let mut last_ptr: *const _ = {
35            let Some(last_ref) = iter.next() else {
36                return Ok(());
37            };
38            last_ref
39        };
40        for (index_of_fst, current) in iter.enumerate() {
41            // SAFETY:
42            // Just dereferencing a known reference
43            // whose referencee may be changed.
44            let last = unsafe { &*last_ptr };
45            match Invariant::test([last, current]) {
46                Ok(()) => {}
47                Err(error) => {
48                    return Err(NotAllPairs {
49                        elem_fst: last,
50                        elem_snd: current,
51                        error,
52                        index_of_fst,
53                    });
54                }
55            }
56            last_ptr = current;
57        }
58        Ok(())
59    }
60}
61
62/// At least one pair in an iterator did not satisfy the given invariant.
63#[non_exhaustive]
64#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
65pub struct NotAllPairs<'i, Item: fmt::Debug, Invariant: crate::Test<Item, 2>> {
66    /// First element of the pair.
67    elem_fst: &'i Item,
68    /// Second element of the pair.
69    elem_snd: &'i Item,
70    /// Error indicating why this pair wasn't valid.
71    error: Invariant::Error<'i>,
72    /// After how many other elements
73    /// did we see the first element of this pair?
74    index_of_fst: usize,
75}
76
77impl<Item: fmt::Debug, Invariant: crate::Test<Item, 2>> fmt::Display
78    for NotAllPairs<'_, Item, Invariant>
79{
80    #[inline]
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        #![expect(
83            clippy::use_debug,
84            reason = "Intentional and informative, not just forgotten print-debugging"
85        )]
86
87        let Self {
88            elem_fst,
89            elem_snd,
90            ref error,
91            index_of_fst,
92        } = *self;
93        write!(f, "Elements #{index_of_fst} and #")?;
94        if let Some(index_of_snd) = index_of_fst.checked_add(1) {
95            fmt::Display::fmt(&index_of_snd, f)
96        } else {
97            write!(f, "[`usize` overflow]")
98        }?;
99        write!(
100            f,
101            " ({elem_fst:#?} and {elem_snd:#?}) were not {}: {error}",
102            Invariant::ADJECTIVE,
103        )
104    }
105}