Skip to main content

lattices/
pair.rs

1use crate::{DeepReveal, Lattice, LatticeBimorphism};
2
3/// Pair compound lattice.
4///
5/// `LatA` and `LatB` specify the nested lattice types.
6///
7/// When merging, both sub-lattices are always merged.
8#[derive(Copy, Clone, Debug, Default, Eq, Lattice)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Pair<LatA, LatB> {
11    /// The "left" Lattice of the Pair lattice.
12    pub a: LatA,
13
14    /// The "right" Lattice of the Pair lattice.
15    pub b: LatB,
16}
17
18impl<LatA, LatB> Pair<LatA, LatB> {
19    /// Create a `Pair` from the given values.
20    pub fn new(a: LatA, b: LatB) -> Self {
21        Self { a, b }
22    }
23
24    /// Create a `Pair` from the given values, using `Into`.
25    pub fn new_from(a: impl Into<LatA>, b: impl Into<LatB>) -> Self {
26        Self::new(a.into(), b.into())
27    }
28
29    /// Reveal the inner value as a shared reference.
30    pub fn as_reveal_ref(&self) -> (&LatA, &LatB) {
31        (&self.a, &self.b)
32    }
33
34    /// Reveal the inner value as an exclusive reference.
35    pub fn as_reveal_mut(&mut self) -> (&mut LatA, &mut LatB) {
36        (&mut self.a, &mut self.b)
37    }
38
39    /// Gets the inner by value, consuming self.
40    pub fn into_reveal(self) -> (LatA, LatB) {
41        (self.a, self.b)
42    }
43}
44
45impl<LatA, LatB> DeepReveal for Pair<LatA, LatB>
46where
47    LatA: DeepReveal,
48    LatB: DeepReveal,
49{
50    type Revealed = (LatA::Revealed, LatB::Revealed);
51
52    fn deep_reveal(self) -> Self::Revealed {
53        (self.a.deep_reveal(), self.b.deep_reveal())
54    }
55}
56
57/// Bimorphism which pairs up the two input lattices.
58#[derive(Default)]
59pub struct PairBimorphism;
60impl<LatA, LatB> LatticeBimorphism<LatA, LatB> for PairBimorphism {
61    type Output = Pair<LatA, LatB>;
62
63    fn call(&mut self, lat_a: LatA, lat_b: LatB) -> Self::Output {
64        Pair::new(lat_a, lat_b)
65    }
66}
67
68#[cfg(test)]
69mod test {
70    use std::collections::HashSet;
71
72    use super::*;
73    use crate::set_union::{SetUnionBTreeSet, SetUnionHashSet, SetUnionSingletonSet};
74    use crate::test::{check_all, check_lattice_bimorphism};
75    use crate::{Merge, WithTop};
76
77    #[cfg(feature = "alloc")]
78    #[test]
79    fn consistency() {
80        use alloc::vec;
81
82        let mut test_vec = vec![];
83
84        for a in [vec![], vec![0], vec![1], vec![0, 1]] {
85            for b in [vec![], vec![0], vec![1], vec![0, 1]] {
86                test_vec.push(Pair::new(
87                    SetUnionHashSet::new_from(HashSet::from_iter(a.clone())),
88                    SetUnionHashSet::new_from(HashSet::from_iter(b.clone())),
89                ));
90            }
91        }
92
93        check_all(&test_vec);
94    }
95
96    #[cfg(feature = "alloc")]
97    #[test]
98    fn consistency_withtop() {
99        use alloc::vec::Vec;
100
101        let mut test_vec = Vec::new();
102
103        let sub_items = &[
104            Some(&[] as &[usize]),
105            Some(&[0]),
106            Some(&[1]),
107            Some(&[0, 1]),
108            None,
109        ];
110
111        for a in sub_items {
112            for b in sub_items {
113                test_vec.push(Pair::new(
114                    WithTop::new(
115                        a.map(|x| SetUnionHashSet::new_from(HashSet::from_iter(x.iter().cloned()))),
116                    ),
117                    WithTop::new(
118                        b.map(|x| SetUnionHashSet::new_from(HashSet::from_iter(x.iter().cloned()))),
119                    ),
120                ));
121            }
122        }
123
124        check_all(&test_vec);
125    }
126
127    #[test]
128    fn test_merge_direction() {
129        let src = Pair::new(
130            SetUnionSingletonSet::new_from(5),
131            SetUnionSingletonSet::new_from("hello"),
132        );
133        let mut dst = Pair::new(
134            SetUnionHashSet::new_from([1, 2]),
135            SetUnionBTreeSet::new_from(["world"]),
136        );
137        dst.merge(src);
138    }
139
140    #[test]
141    fn test_pair_bimorphism() {
142        let items_a = &[
143            SetUnionHashSet::new_from([]),
144            SetUnionHashSet::new_from([0]),
145            SetUnionHashSet::new_from([1]),
146            SetUnionHashSet::new_from([0, 1]),
147        ];
148        let items_b = &[
149            SetUnionBTreeSet::new("hello".chars().collect()),
150            SetUnionBTreeSet::new("world".chars().collect()),
151        ];
152
153        check_lattice_bimorphism(PairBimorphism, items_a, items_a);
154        check_lattice_bimorphism(PairBimorphism, items_a, items_b);
155        check_lattice_bimorphism(PairBimorphism, items_b, items_a);
156        check_lattice_bimorphism(PairBimorphism, items_b, items_b);
157    }
158}