splinter_rs/splinter/
cut.rs

1use crate::{bitmap::BitmapExt, cow::CowSplinter, ops::Cut, relational::Relation};
2
3use super::{Splinter, SplinterRef};
4
5impl Cut for Splinter {
6    type Output = Splinter;
7
8    fn cut(&mut self, rhs: &Self) -> Self::Output {
9        let mut out = Splinter::default();
10
11        let rhs = &rhs.partitions;
12        self.partitions.retain(|&a, left| {
13            if let Some(right) = rhs.get(a) {
14                // we need to cut right out of left
15                left.retain(|&b, left| {
16                    if let Some(right) = right.get(b) {
17                        // we need to cut right out of left
18                        left.retain(|&c, left| {
19                            if let Some(right) = right.get(c) {
20                                out.insert_block(a, b, c, left.cut(right));
21                                left.has_bits_set()
22                            } else {
23                                true
24                            }
25                        });
26                        !left.is_empty()
27                    } else {
28                        true
29                    }
30                });
31                !left.is_empty()
32            } else {
33                true
34            }
35        });
36
37        out
38    }
39}
40
41impl<T: AsRef<[u8]>> Cut<SplinterRef<T>> for Splinter {
42    type Output = Splinter;
43
44    fn cut(&mut self, rhs: &SplinterRef<T>) -> Self::Output {
45        let mut out = Splinter::default();
46
47        let rhs = rhs.load_partitions();
48        self.partitions.retain(|&a, left| {
49            if let Some(right) = rhs.get(a) {
50                // we need to cut right out of left
51                left.retain(|&b, left| {
52                    if let Some(right) = right.get(b) {
53                        // we need to cut right out of left
54                        left.retain(|&c, left| {
55                            if let Some(right) = right.get(c) {
56                                out.insert_block(a, b, c, left.cut(&right));
57                                left.has_bits_set()
58                            } else {
59                                true
60                            }
61                        });
62                        !left.is_empty()
63                    } else {
64                        true
65                    }
66                });
67                !left.is_empty()
68            } else {
69                true
70            }
71        });
72
73        out
74    }
75}
76
77// CowSplinter cut Splinter
78impl<T1: AsRef<[u8]>> Cut<Splinter> for CowSplinter<T1> {
79    type Output = Splinter;
80
81    fn cut(&mut self, rhs: &Splinter) -> Self::Output {
82        self.to_mut().cut(rhs)
83    }
84}
85
86// CowSplinter cut SplinterRef
87impl<T1: AsRef<[u8]>, T2: AsRef<[u8]>> Cut<SplinterRef<T2>> for CowSplinter<T1> {
88    type Output = Splinter;
89
90    fn cut(&mut self, rhs: &SplinterRef<T2>) -> Self::Output {
91        self.to_mut().cut(rhs)
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use crate::{
98        Splinter,
99        ops::Cut,
100        testutil::{TestSplinter, mksplinter, mksplinters},
101    };
102
103    impl Cut<TestSplinter> for Splinter {
104        type Output = Splinter;
105
106        fn cut(&mut self, rhs: &TestSplinter) -> Self::Output {
107            use TestSplinter::*;
108            match rhs {
109                Splinter(rhs) => self.cut(rhs),
110                SplinterRef(rhs) => self.cut(rhs),
111            }
112        }
113    }
114
115    fn check_cut<L, R, E, O>(left: L, right: R, expected_cut: E, expected_out: O)
116    where
117        L: IntoIterator<Item = u32> + Clone,
118        R: IntoIterator<Item = u32> + Clone,
119        E: IntoIterator<Item = u32> + Clone,
120        O: IntoIterator<Item = u32> + Clone,
121    {
122        let left = mksplinter(left);
123        let right = mksplinters(right);
124        let expected_cut = mksplinter(expected_cut);
125        let expected_out = mksplinter(expected_out);
126        for rhs in right.into_iter() {
127            let mut left = left.clone();
128            let label = format!("lhs: {left:?}, rhs: {rhs:?}");
129            let out = left.cut(&rhs);
130            assert_eq!(left, expected_cut, "cut: {label}");
131            assert_eq!(out, expected_out, "intersection: {label}");
132        }
133    }
134
135    #[test]
136    fn test_sanity() {
137        check_cut(0..0, 0..0, 0..0, 0..0);
138        check_cut(0..10, 0..5, 5..10, 0..5);
139        check_cut(0..10, 0..10, 0..0, 0..10);
140    }
141}