grovedb_merk/proofs/query/query_item/
intersect.rs

1use std::{
2    cmp::Ordering,
3    fmt,
4    ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
5};
6
7use crate::proofs::query::query_item::{
8    intersect::RangeSetItem::{
9        ExclusiveEnd, ExclusiveStart, Inclusive, UnboundedEnd, UnboundedStart,
10    },
11    QueryItem,
12};
13
14pub struct RangeSetIntersection {
15    in_both: Option<RangeSet>,
16    ours_left: Option<RangeSet>,
17    ours_right: Option<RangeSet>,
18    theirs_left: Option<RangeSet>,
19    theirs_right: Option<RangeSet>,
20}
21
22/// Concise query item representation
23#[derive(Clone, Debug)]
24pub struct RangeSet {
25    pub start: RangeSetItem,
26    pub end: RangeSetItem,
27}
28
29/// Concise query item representation
30#[derive(Clone, Copy, Debug)]
31pub struct RangeSetBorrowed<'a> {
32    pub start: RangeSetSimpleItemBorrowed<'a>,
33    pub end: RangeSetSimpleItemBorrowed<'a>,
34}
35
36impl fmt::Display for RangeSetBorrowed<'_> {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        write!(f, "[{} .. {}]", self.start, self.end)
39    }
40}
41
42/// Specifies whether we are checking if there's at least one key
43/// strictly less than (`LeftOf`) or strictly greater than (`RightOf`) a given
44/// key.
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum Direction {
47    /// Checking if there's an item < `key`
48    LeftOf,
49    /// Checking if there's an item > `key`
50    RightOf,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct KeyContainmentResult {
55    pub included: bool,
56    pub on_bounds_not_included: bool,
57}
58
59impl RangeSetBorrowed<'_> {
60    /// Returns `true` if `key` is within [start, end] boundaries, respecting
61    /// inclusive/exclusive semantics. If `start` is `Unbounded`, it is treated
62    /// like -∞ (lowest possible). If `end` is `Unbounded`, it is treated like
63    /// +∞ (highest possible).
64    pub fn could_contain_key<K: AsRef<[u8]>>(&self, key: K) -> KeyContainmentResult {
65        let key_bytes = key.as_ref();
66
67        // 1) Check lower boundary (start)
68        let (passes_start, on_start_exclusive) = match &self.start {
69            RangeSetSimpleItemBorrowed::Unbounded => (true, false), // -∞ => all keys are >= -∞
70            RangeSetSimpleItemBorrowed::Inclusive(bound_bytes) => {
71                (key_bytes >= bound_bytes.as_slice(), false)
72            }
73            RangeSetSimpleItemBorrowed::Exclusive(bound_bytes) => (
74                key_bytes > bound_bytes.as_slice(),
75                key_bytes == bound_bytes.as_slice(),
76            ),
77        };
78
79        // 2) Check upper boundary (end)
80        let (passes_end, on_end_exclusive) = match &self.end {
81            RangeSetSimpleItemBorrowed::Unbounded => (true, false), // +∞ => all keys are <= +∞
82            RangeSetSimpleItemBorrowed::Inclusive(bound_bytes) => {
83                (key_bytes <= bound_bytes.as_slice(), false)
84            }
85            RangeSetSimpleItemBorrowed::Exclusive(bound_bytes) => (
86                key_bytes < bound_bytes.as_slice(),
87                key_bytes == bound_bytes.as_slice(),
88            ),
89        };
90
91        // 3) Key is contained only if it satisfies both constraints
92        KeyContainmentResult {
93            included: passes_start && passes_end,
94            on_bounds_not_included: on_start_exclusive || on_end_exclusive,
95        }
96    }
97
98    /// Checks if there's at least one item in [start, end] that is strictly
99    /// to the *left* (< `key`) or *right* (> `key`) of `key`, depending on
100    /// `direction`.
101    ///
102    /// - `Direction::LeftOf` => returns true if [start..end] might contain an
103    ///   item < key.
104    /// - `Direction::RightOf` => returns true if [start..end] might contain an
105    ///   item > key.
106    pub fn could_have_items_in_direction<K: AsRef<[u8]>>(
107        &self,
108        key: K,
109        direction: Direction,
110    ) -> bool {
111        let key_bytes = key.as_ref();
112        match direction {
113            Direction::LeftOf => {
114                // We want to know if there's any item in [start, end] that is < key.
115                // That is possible if the start boundary is strictly less than `key`.
116                match &self.start {
117                    // Unbounded => effectively -∞ => definitely < key
118                    RangeSetSimpleItemBorrowed::Unbounded => true,
119                    // Inclusive(b) => items start at b. If b >= key, then no item is < key.
120                    // Only if b < key, we might have something < key.
121                    RangeSetSimpleItemBorrowed::Inclusive(b) => b.as_slice() < key_bytes,
122                    // Exclusive(b) => items start strictly after b => if b < key,
123                    // we still might have item < key. However if b == key, we start after key => no
124                    // item < key.
125                    RangeSetSimpleItemBorrowed::Exclusive(b) => b.as_slice() < key_bytes,
126                }
127            }
128            Direction::RightOf => {
129                // We want to know if there's any item in [start, end] that is > key.
130                // That is possible if the end boundary is strictly greater than `key`.
131                match &self.end {
132                    // Unbounded => effectively +∞ => definitely > key
133                    RangeSetSimpleItemBorrowed::Unbounded => true,
134                    // Inclusive(b) => items extend up to b. If b <= key, then no item is > key.
135                    // Only if b > key, we might have something > key.
136                    RangeSetSimpleItemBorrowed::Inclusive(b) => b.as_slice() > key_bytes,
137                    // Exclusive(b) => items extend up to but not including b.
138                    // If b > key => there's space for an item > key. If b == key => no item > key.
139                    RangeSetSimpleItemBorrowed::Exclusive(b) => b.as_slice() > key_bytes,
140                }
141            }
142        }
143    }
144}
145
146#[derive(Default)]
147pub struct QueryItemManyIntersectionResult {
148    pub in_both: Option<Vec<QueryItem>>,
149    pub ours: Option<Vec<QueryItem>>,
150    pub theirs: Option<Vec<QueryItem>>,
151}
152
153pub struct QueryItemIntersectionResultTheirsLeftovers {
154    pub theirs_left: Option<QueryItem>,
155    pub theirs_right: Option<QueryItem>,
156}
157
158impl QueryItemManyIntersectionResult {
159    fn push_ours(&mut self, our_query_item: QueryItem) {
160        let ours_vec = self.ours.get_or_insert(vec![]);
161        ours_vec.push(our_query_item);
162    }
163
164    fn push_theirs(&mut self, their_query_item: QueryItem) {
165        let theirs_vec = self.theirs.get_or_insert(vec![]);
166        theirs_vec.push(their_query_item);
167    }
168
169    fn push_ours_and_in_both_from_result(
170        &mut self,
171        query_item_intersection_result: QueryItemIntersectionResult,
172    ) -> QueryItemIntersectionResultTheirsLeftovers {
173        let QueryItemIntersectionResult {
174            in_both,
175            ours_left,
176            ours_right,
177            theirs_left,
178            theirs_right,
179        } = query_item_intersection_result;
180        if let Some(in_both) = in_both {
181            let in_both_vec = self.in_both.get_or_insert(vec![]);
182            in_both_vec.push(in_both);
183        }
184        if let Some(ours_left) = ours_left {
185            let ours_vec = self.ours.get_or_insert(vec![]);
186            ours_vec.push(ours_left);
187        }
188        if let Some(ours_right) = ours_right {
189            let ours_vec = self.ours.get_or_insert(vec![]);
190            ours_vec.push(ours_right);
191        }
192
193        QueryItemIntersectionResultTheirsLeftovers {
194            theirs_left,
195            theirs_right,
196        }
197    }
198
199    #[allow(unused)]
200    fn push_theirs_from_result(
201        &mut self,
202        query_item_intersection_result: QueryItemIntersectionResultTheirsLeftovers,
203    ) {
204        let QueryItemIntersectionResultTheirsLeftovers {
205            theirs_left,
206            theirs_right,
207        } = query_item_intersection_result;
208        if let Some(theirs_left) = theirs_left {
209            let theirs_vec = self.theirs.get_or_insert(vec![]);
210            theirs_vec.push(theirs_left);
211        }
212        if let Some(theirs_right) = theirs_right {
213            let theirs_vec = self.theirs.get_or_insert(vec![]);
214            theirs_vec.push(theirs_right);
215        }
216    }
217
218    fn merge_in(&mut self, query_item_many_intersection_result: Self) {
219        let QueryItemManyIntersectionResult {
220            in_both,
221            ours,
222            theirs,
223        } = query_item_many_intersection_result;
224        if let Some(mut in_both) = in_both {
225            let in_both_vec = self.in_both.get_or_insert(vec![]);
226            in_both_vec.append(&mut in_both);
227        }
228        if let Some(mut ours) = ours {
229            let ours_vec = self.ours.get_or_insert(vec![]);
230            ours_vec.append(&mut ours);
231        }
232        if let Some(mut theirs) = theirs {
233            let theirs_vec = self.theirs.get_or_insert(vec![]);
234            theirs_vec.append(&mut theirs);
235        }
236    }
237}
238
239pub struct QueryItemIntersectionResult {
240    pub in_both: Option<QueryItem>,
241    pub ours_left: Option<QueryItem>,
242    pub ours_right: Option<QueryItem>,
243    pub theirs_left: Option<QueryItem>,
244    pub theirs_right: Option<QueryItem>,
245}
246
247impl From<RangeSetIntersection> for QueryItemIntersectionResult {
248    fn from(range_set_intersection: RangeSetIntersection) -> Self {
249        Self {
250            in_both: range_set_intersection.in_both.map(|a| a.to_query_item()),
251            ours_left: range_set_intersection.ours_left.map(|a| a.to_query_item()),
252            ours_right: range_set_intersection.ours_right.map(|a| a.to_query_item()),
253            theirs_left: range_set_intersection
254                .theirs_left
255                .map(|a| a.to_query_item()),
256            theirs_right: range_set_intersection
257                .theirs_right
258                .map(|a| a.to_query_item()),
259        }
260    }
261}
262
263impl RangeSet {
264    // TODO: convert to impl of From/To trait
265    pub fn to_query_item(&self) -> QueryItem {
266        match (&self.start, &self.end) {
267            (RangeSetItem::Inclusive(start), RangeSetItem::Inclusive(end)) => {
268                if start == end {
269                    QueryItem::Key(start.clone())
270                } else {
271                    QueryItem::RangeInclusive(RangeInclusive::new(start.clone(), end.clone()))
272                }
273            }
274            (RangeSetItem::Inclusive(start), RangeSetItem::ExclusiveEnd(end)) => {
275                QueryItem::Range(Range {
276                    start: start.clone(),
277                    end: end.clone(),
278                })
279            }
280            (RangeSetItem::Inclusive(start), RangeSetItem::UnboundedEnd) => {
281                QueryItem::RangeFrom(RangeFrom {
282                    start: start.clone(),
283                })
284            }
285            (RangeSetItem::ExclusiveStart(start), RangeSetItem::ExclusiveEnd(end)) => {
286                QueryItem::RangeAfterTo(Range {
287                    start: start.clone(),
288                    end: end.clone(),
289                })
290            }
291            (RangeSetItem::ExclusiveStart(start), RangeSetItem::Inclusive(end)) => {
292                QueryItem::RangeAfterToInclusive(RangeInclusive::new(start.clone(), end.clone()))
293            }
294            (RangeSetItem::ExclusiveStart(start), RangeSetItem::UnboundedEnd) => {
295                QueryItem::RangeAfter(RangeFrom {
296                    start: start.clone(),
297                })
298            }
299            (RangeSetItem::UnboundedStart, RangeSetItem::UnboundedEnd) => {
300                QueryItem::RangeFull(RangeFull)
301            }
302            (RangeSetItem::UnboundedStart, RangeSetItem::Inclusive(end)) => {
303                QueryItem::RangeToInclusive(RangeToInclusive { end: end.clone() })
304            }
305            (RangeSetItem::UnboundedStart, RangeSetItem::ExclusiveEnd(end)) => {
306                QueryItem::RangeTo(RangeTo { end: end.clone() })
307            }
308            _ => {
309                // TODO: return proper error, this should be unreachable
310                //  if the range set was created from a valid query item,
311                //  actually should return None in this case
312                unreachable!()
313            }
314        }
315    }
316
317    pub fn intersect(&self, other: RangeSet) -> RangeSetIntersection {
318        // check if the range sets do not overlap
319        if self.end < other.start || other.end < self.start {
320            // the sets do not overlap
321            // no common element
322            if self.end < other.start {
323                // self is at the left
324                return RangeSetIntersection {
325                    in_both: None,
326                    ours_left: Some(self.clone()),
327                    ours_right: None,
328                    theirs_right: Some(other),
329                    theirs_left: None,
330                };
331            } else {
332                return RangeSetIntersection {
333                    in_both: None,
334                    ours_left: None,
335                    ours_right: Some(self.clone()),
336                    theirs_left: Some(other),
337                    theirs_right: None,
338                };
339            }
340        }
341
342        // sets overlap
343        let (smaller_start, bigger_start) =
344            RangeSetItem::order_items(&self.start, &other.start, self.start.cmp(&other.start));
345
346        let (smaller_end, larger_end) =
347            RangeSetItem::order_items(&self.end, &other.end, self.end.cmp(&other.end));
348
349        // assume they are equal and progressively update the common boundary
350        let mut intersection_result = RangeSetIntersection {
351            in_both: Some(self.clone()),
352            ours_left: None,
353            ours_right: None,
354            theirs_left: None,
355            theirs_right: None,
356        };
357
358        // if the comparison of the start are not equal then we have value for left
359        if self.start != other.start {
360            if &self.start == smaller_start {
361                // ours left
362                intersection_result.ours_left = Some(RangeSet {
363                    start: smaller_start.clone(),
364                    end: bigger_start.invert(false),
365                });
366            } else {
367                intersection_result.theirs_left = Some(RangeSet {
368                    start: smaller_start.clone(),
369                    end: bigger_start.invert(false),
370                });
371            }
372        }
373
374        // if the comparison of the end is not equal then we have value for right
375        if self.end != other.end {
376            if self.end > other.end {
377                // ours right
378                intersection_result.ours_right = Some(RangeSet {
379                    start: smaller_end.invert(true),
380                    end: larger_end.clone(),
381                });
382            } else {
383                intersection_result.theirs_right = Some(RangeSet {
384                    start: smaller_end.invert(true),
385                    end: larger_end.clone(),
386                });
387            }
388        }
389
390        intersection_result.in_both = Some(RangeSet {
391            start: bigger_start.clone(),
392            end: smaller_end.clone(),
393        });
394
395        intersection_result
396    }
397}
398
399/// Represents all possible value types in a range set
400#[derive(Eq, PartialEq, Clone, Debug)]
401pub enum RangeSetItem {
402    UnboundedStart,
403    UnboundedEnd,
404    Inclusive(Vec<u8>),
405    ExclusiveStart(Vec<u8>),
406    ExclusiveEnd(Vec<u8>),
407}
408
409#[derive(Eq, PartialEq, Clone, Copy, Debug)]
410pub enum RangeSetSimpleItemBorrowed<'a> {
411    Unbounded,
412    Inclusive(&'a Vec<u8>),
413    Exclusive(&'a Vec<u8>),
414}
415impl fmt::Display for RangeSetSimpleItemBorrowed<'_> {
416    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417        match self {
418            RangeSetSimpleItemBorrowed::Unbounded => write!(f, "Unbounded"),
419            RangeSetSimpleItemBorrowed::Inclusive(b) => write!(f, "Inclusive({:X?})", b),
420            RangeSetSimpleItemBorrowed::Exclusive(b) => write!(f, "Exclusive({:X?})", b),
421        }
422    }
423}
424
425impl RangeSetItem {
426    pub fn invert(&self, is_start: bool) -> RangeSetItem {
427        match &self {
428            RangeSetItem::Inclusive(v) => {
429                if is_start {
430                    RangeSetItem::ExclusiveStart(v.clone())
431                } else {
432                    RangeSetItem::ExclusiveEnd(v.clone())
433                }
434            }
435            RangeSetItem::ExclusiveStart(v) | RangeSetItem::ExclusiveEnd(v) => {
436                RangeSetItem::Inclusive(v.clone())
437            }
438            RangeSetItem::UnboundedStart => RangeSetItem::UnboundedStart,
439            RangeSetItem::UnboundedEnd => RangeSetItem::UnboundedEnd,
440        }
441    }
442
443    /// Given som ordering and two items, this returns the items orders
444    pub fn order_items<'a>(
445        item_one: &'a RangeSetItem,
446        item_two: &'a RangeSetItem,
447        order: Ordering,
448    ) -> (&'a RangeSetItem, &'a RangeSetItem) {
449        match order {
450            Ordering::Less => (item_one, item_two),
451            _ => (item_two, item_one),
452        }
453    }
454}
455
456impl PartialOrd for RangeSetItem {
457    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
458        Some(self.cmp(other))
459    }
460}
461
462impl Ord for RangeSetItem {
463    fn cmp(&self, other: &Self) -> Ordering {
464        match (self, other) {
465            (UnboundedStart, UnboundedStart) => Ordering::Equal,
466            (UnboundedEnd, UnboundedEnd) => Ordering::Equal,
467
468            // unbounded start begins at negative infinity so it's smaller than all other values
469            (UnboundedStart, _) => Ordering::Less,
470            (_, UnboundedStart) => Ordering::Greater,
471
472            // unbounded end stops at positive infinity so larger than all other values
473            (UnboundedEnd, _) => Ordering::Greater,
474            (_, UnboundedEnd) => Ordering::Less,
475
476            (Inclusive(v1), Inclusive(v2))
477            | (ExclusiveStart(v1), ExclusiveStart(v2))
478            | (ExclusiveEnd(v1), ExclusiveEnd(v2)) => v1.cmp(v2),
479
480            (Inclusive(v1), ExclusiveStart(v2)) | (ExclusiveEnd(v1), Inclusive(v2)) => {
481                match v1.cmp(v2) {
482                    Ordering::Equal | Ordering::Less => Ordering::Less,
483                    _ => Ordering::Greater,
484                }
485            }
486            (Inclusive(v1), ExclusiveEnd(v2)) | (ExclusiveStart(v1), Inclusive(v2)) => {
487                match v1.cmp(v2) {
488                    Ordering::Less => Ordering::Less,
489                    _ => Ordering::Greater,
490                }
491            }
492
493            (ExclusiveStart(v1), ExclusiveEnd(v2)) | (ExclusiveEnd(v2), ExclusiveStart(v1)) => {
494                // start goes up, end goes down
495                // if they are equal, exclusive end is smaller cause it stops just before the
496                // number
497                match v1.cmp(v2) {
498                    Ordering::Equal | Ordering::Greater => Ordering::Greater,
499                    _ => Ordering::Less,
500                }
501            }
502        }
503    }
504}
505
506impl QueryItem {
507    pub fn intersect(&self, other: &Self) -> QueryItemIntersectionResult {
508        self.to_range_set().intersect(other.to_range_set()).into()
509    }
510
511    // TODO: convert to impl of From/To trait
512    pub fn to_range_set(&self) -> RangeSet {
513        match self {
514            QueryItem::Key(start) => RangeSet {
515                start: RangeSetItem::Inclusive(start.clone()),
516                end: RangeSetItem::Inclusive(start.clone()),
517            },
518            QueryItem::Range(range) => RangeSet {
519                start: RangeSetItem::Inclusive(range.start.clone()),
520                end: RangeSetItem::ExclusiveEnd(range.end.clone()),
521            },
522            QueryItem::RangeInclusive(range) => RangeSet {
523                start: RangeSetItem::Inclusive(range.start().clone()),
524                end: RangeSetItem::Inclusive(range.end().clone()),
525            },
526            QueryItem::RangeFull(..) => RangeSet {
527                start: RangeSetItem::UnboundedStart,
528                end: RangeSetItem::UnboundedEnd,
529            },
530            QueryItem::RangeFrom(range) => RangeSet {
531                start: RangeSetItem::Inclusive(range.start.clone()),
532                end: RangeSetItem::UnboundedEnd,
533            },
534            QueryItem::RangeTo(range) => RangeSet {
535                start: RangeSetItem::UnboundedStart,
536                end: RangeSetItem::ExclusiveEnd(range.end.clone()),
537            },
538            QueryItem::RangeToInclusive(range) => RangeSet {
539                start: RangeSetItem::UnboundedStart,
540                end: RangeSetItem::Inclusive(range.end.clone()),
541            },
542            QueryItem::RangeAfter(range) => RangeSet {
543                start: RangeSetItem::ExclusiveStart(range.start.clone()),
544                end: RangeSetItem::UnboundedEnd,
545            },
546            QueryItem::RangeAfterTo(range) => RangeSet {
547                start: RangeSetItem::ExclusiveStart(range.start.clone()),
548                end: RangeSetItem::ExclusiveEnd(range.end.clone()),
549            },
550            QueryItem::RangeAfterToInclusive(range) => RangeSet {
551                start: RangeSetItem::ExclusiveStart(range.start().clone()),
552                end: RangeSetItem::Inclusive(range.end().clone()),
553            },
554        }
555    }
556
557    // TODO: convert to impl of From/To trait
558    pub fn to_range_set_borrowed(&self) -> Option<RangeSetBorrowed> {
559        match self {
560            QueryItem::Key(start) => Some(RangeSetBorrowed {
561                start: RangeSetSimpleItemBorrowed::Inclusive(start),
562                end: RangeSetSimpleItemBorrowed::Inclusive(start),
563            }),
564            QueryItem::Range(range) => Some(RangeSetBorrowed {
565                start: RangeSetSimpleItemBorrowed::Inclusive(&range.start),
566                end: RangeSetSimpleItemBorrowed::Exclusive(&range.end),
567            }),
568            QueryItem::RangeInclusive(range) => Some(RangeSetBorrowed {
569                start: RangeSetSimpleItemBorrowed::Inclusive(range.start()),
570                end: RangeSetSimpleItemBorrowed::Inclusive(range.end()),
571            }),
572            QueryItem::RangeFull(..) => Some(RangeSetBorrowed {
573                start: RangeSetSimpleItemBorrowed::Unbounded,
574                end: RangeSetSimpleItemBorrowed::Unbounded,
575            }),
576            QueryItem::RangeFrom(range) => Some(RangeSetBorrowed {
577                start: RangeSetSimpleItemBorrowed::Inclusive(&range.start),
578                end: RangeSetSimpleItemBorrowed::Unbounded,
579            }),
580            QueryItem::RangeTo(range) => Some(RangeSetBorrowed {
581                start: RangeSetSimpleItemBorrowed::Unbounded,
582                end: RangeSetSimpleItemBorrowed::Exclusive(&range.end),
583            }),
584            QueryItem::RangeToInclusive(range) => Some(RangeSetBorrowed {
585                start: RangeSetSimpleItemBorrowed::Unbounded,
586                end: RangeSetSimpleItemBorrowed::Inclusive(&range.end),
587            }),
588            QueryItem::RangeAfter(range) => Some(RangeSetBorrowed {
589                start: RangeSetSimpleItemBorrowed::Exclusive(&range.start),
590                end: RangeSetSimpleItemBorrowed::Unbounded,
591            }),
592            QueryItem::RangeAfterTo(range) => Some(RangeSetBorrowed {
593                start: RangeSetSimpleItemBorrowed::Exclusive(&range.start),
594                end: RangeSetSimpleItemBorrowed::Exclusive(&range.end),
595            }),
596            QueryItem::RangeAfterToInclusive(range) => Some(RangeSetBorrowed {
597                start: RangeSetSimpleItemBorrowed::Exclusive(range.start()),
598                end: RangeSetSimpleItemBorrowed::Inclusive(range.end()),
599            }),
600        }
601    }
602
603    /// For this intersection to work ours and theirs must be ordered
604    pub fn intersect_many_ordered(
605        ours: &mut Vec<Self>,
606        theirs: Vec<Self>,
607    ) -> QueryItemManyIntersectionResult {
608        let mut result = QueryItemManyIntersectionResult::default();
609        for our_item in ours.drain(..) {
610            // We create an intersection result for this one item
611            let mut one_item_pair_intersections = QueryItemManyIntersectionResult::default();
612            // We add our item
613            // In the end the item might be split up
614            one_item_pair_intersections.push_ours(our_item);
615            for their_item in theirs.clone() {
616                // We take the vector of our item
617                // It might be empty if it has already been completely consumed
618                // Meaning that all the item was inside of their items
619                if let Some(our_item_split_sections) = one_item_pair_intersections.ours.take() {
620                    let mut maybe_temp_their_item = Some(their_item);
621                    for our_partial_item in our_item_split_sections {
622                        if let Some(temp_their_item) = maybe_temp_their_item {
623                            let intersection_result = our_partial_item.intersect(&temp_their_item);
624                            // ours and in both are guaranteed to be unique
625                            let theirs_leftovers = one_item_pair_intersections
626                                .push_ours_and_in_both_from_result(intersection_result);
627                            // if we assume theirs is ordered
628                            // then we can push the left leftover
629                            if let Some(theirs_left) = theirs_leftovers.theirs_left {
630                                one_item_pair_intersections.push_theirs(theirs_left)
631                            }
632                            maybe_temp_their_item = theirs_leftovers.theirs_right
633                        } else {
634                            // there is no more of their item left
635                            // just push our partial item
636                            one_item_pair_intersections.push_ours(our_partial_item)
637                        }
638                    }
639                    // we need to add the end theirs leftovers
640                    if let Some(theirs_left) = maybe_temp_their_item {
641                        one_item_pair_intersections.push_theirs(theirs_left)
642                    }
643                } else {
644                    one_item_pair_intersections.push_theirs(their_item)
645                }
646            }
647            result.merge_in(one_item_pair_intersections)
648        }
649        result
650    }
651}
652
653#[cfg(test)]
654mod test {
655    use std::{
656        cmp::Ordering,
657        ops::{Range, RangeInclusive},
658    };
659
660    use crate::proofs::query::query_item::{intersect::RangeSetItem, QueryItem};
661
662    #[test]
663    pub fn test_range_set_query_item_conversion() {
664        assert_eq!(
665            QueryItem::Key(vec![5]).to_range_set().to_query_item(),
666            QueryItem::Key(vec![5])
667        );
668        assert_eq!(
669            QueryItem::Range(Range {
670                start: vec![2],
671                end: vec![5]
672            })
673            .to_range_set()
674            .to_query_item(),
675            QueryItem::Range(Range {
676                start: vec![2],
677                end: vec![5]
678            })
679        );
680        assert_eq!(
681            QueryItem::RangeInclusive(RangeInclusive::new(vec![2], vec![5]))
682                .to_range_set()
683                .to_query_item(),
684            QueryItem::RangeInclusive(RangeInclusive::new(vec![2], vec![5]))
685        );
686        assert_eq!(
687            QueryItem::RangeFull(..).to_range_set().to_query_item(),
688            QueryItem::RangeFull(..)
689        );
690        assert_eq!(
691            QueryItem::RangeFrom(vec![5]..)
692                .to_range_set()
693                .to_query_item(),
694            QueryItem::RangeFrom(vec![5]..)
695        );
696        assert_eq!(
697            QueryItem::RangeTo(..vec![3]).to_range_set().to_query_item(),
698            QueryItem::RangeTo(..vec![3])
699        );
700        assert_eq!(
701            QueryItem::RangeToInclusive(..=vec![3])
702                .to_range_set()
703                .to_query_item(),
704            QueryItem::RangeToInclusive(..=vec![3])
705        );
706        assert_eq!(
707            QueryItem::RangeAfter(vec![4]..)
708                .to_range_set()
709                .to_query_item(),
710            QueryItem::RangeAfter(vec![4]..)
711        );
712        assert_eq!(
713            QueryItem::RangeAfterTo(vec![3]..vec![6])
714                .to_range_set()
715                .to_query_item(),
716            QueryItem::RangeAfterTo(vec![3]..vec![6])
717        );
718        assert_eq!(
719            QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])
720                .to_range_set()
721                .to_query_item(),
722            QueryItem::RangeAfterToInclusive(vec![3]..=vec![7])
723        );
724    }
725
726    #[test]
727    pub fn test_range_set_item_compare() {
728        // doing a pyramid compare, to prevent repeated test
729        // if we compare A and B, we don't compare B and A further down
730
731        // test equality
732        assert_eq!(
733            RangeSetItem::Inclusive(vec![1]).cmp(&RangeSetItem::Inclusive(vec![1])),
734            Ordering::Equal
735        );
736        assert_eq!(
737            RangeSetItem::ExclusiveStart(vec![1]).cmp(&RangeSetItem::ExclusiveStart(vec![1])),
738            Ordering::Equal
739        );
740        assert_eq!(
741            RangeSetItem::ExclusiveEnd(vec![1]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
742            Ordering::Equal
743        );
744        assert_eq!(
745            RangeSetItem::UnboundedStart.cmp(&RangeSetItem::UnboundedStart),
746            Ordering::Equal
747        );
748        assert_eq!(
749            RangeSetItem::UnboundedEnd.cmp(&RangeSetItem::UnboundedEnd),
750            Ordering::Equal
751        );
752
753        // test same item but less value
754        assert_eq!(
755            RangeSetItem::Inclusive(vec![1]).cmp(&RangeSetItem::Inclusive(vec![2])),
756            Ordering::Less
757        );
758        assert_eq!(
759            RangeSetItem::ExclusiveStart(vec![1]).cmp(&RangeSetItem::ExclusiveStart(vec![2])),
760            Ordering::Less
761        );
762        assert_eq!(
763            RangeSetItem::ExclusiveEnd(vec![1]).cmp(&RangeSetItem::ExclusiveEnd(vec![2])),
764            Ordering::Less
765        );
766
767        // test same item but greater value
768        assert_eq!(
769            RangeSetItem::Inclusive(vec![3]).cmp(&RangeSetItem::Inclusive(vec![2])),
770            Ordering::Greater
771        );
772        assert_eq!(
773            RangeSetItem::ExclusiveStart(vec![3]).cmp(&RangeSetItem::ExclusiveStart(vec![2])),
774            Ordering::Greater
775        );
776        assert_eq!(
777            RangeSetItem::ExclusiveEnd(vec![3]).cmp(&RangeSetItem::ExclusiveEnd(vec![2])),
778            Ordering::Greater
779        );
780
781        // unbounded end is greater than everything
782        // tried creating the maximum possible vector with vec![u8::MAX; isize::MAX as
783        // usize])) but got memory allocation problems
784        assert_eq!(
785            RangeSetItem::UnboundedEnd.cmp(&RangeSetItem::Inclusive(vec![u8::MAX; 1000])),
786            Ordering::Greater
787        );
788        assert_eq!(
789            RangeSetItem::UnboundedEnd.cmp(&RangeSetItem::ExclusiveStart(vec![u8::MAX; 1000])),
790            Ordering::Greater
791        );
792        assert_eq!(
793            RangeSetItem::UnboundedEnd.cmp(&RangeSetItem::ExclusiveEnd(vec![u8::MAX; 1000])),
794            Ordering::Greater
795        );
796        assert_eq!(
797            RangeSetItem::UnboundedEnd.cmp(&RangeSetItem::UnboundedStart),
798            Ordering::Greater
799        );
800
801        // unbounded start is less than everything
802        assert_eq!(
803            RangeSetItem::UnboundedStart.cmp(&RangeSetItem::Inclusive(vec![])),
804            Ordering::Less
805        );
806        assert_eq!(
807            RangeSetItem::UnboundedStart.cmp(&RangeSetItem::ExclusiveStart(vec![])),
808            Ordering::Less
809        );
810        assert_eq!(
811            RangeSetItem::UnboundedStart.cmp(&RangeSetItem::ExclusiveEnd(vec![])),
812            Ordering::Less
813        );
814
815        // test inclusive
816        // exclusive start represents value + step_size
817        // if step size is 1 and value is 1 then it starts at 2 (basically excluding 1)
818        // hence inclusive at 1 is less since 1 < 2
819        assert_eq!(
820            RangeSetItem::Inclusive(vec![1]).cmp(&RangeSetItem::ExclusiveStart(vec![1])),
821            Ordering::Less
822        );
823        assert_eq!(
824            RangeSetItem::Inclusive(vec![0]).cmp(&RangeSetItem::ExclusiveStart(vec![1])),
825            Ordering::Less
826        );
827        assert_eq!(
828            RangeSetItem::Inclusive(vec![2]).cmp(&RangeSetItem::ExclusiveStart(vec![1])),
829            Ordering::Greater
830        );
831        // exclusive end represents value - step_size
832        // if step size is 1 and value is 1 then it represents at 0 (includes everything
833        // before 1) hence inclusive at 1 is greater since 1 > 0
834        assert_eq!(
835            RangeSetItem::Inclusive(vec![1]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
836            Ordering::Greater
837        );
838        assert_eq!(
839            RangeSetItem::Inclusive(vec![0]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
840            Ordering::Less
841        );
842        assert_eq!(
843            RangeSetItem::Inclusive(vec![2]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
844            Ordering::Greater
845        );
846
847        // test exclusive start
848        // exclusive start is greater than exclusive end for >= same value
849        assert_eq!(
850            RangeSetItem::ExclusiveStart(vec![1]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
851            Ordering::Greater
852        );
853        assert_eq!(
854            RangeSetItem::ExclusiveStart(vec![2]).cmp(&RangeSetItem::ExclusiveEnd(vec![1])),
855            Ordering::Greater
856        );
857        // but less when the value is less
858        assert_eq!(
859            RangeSetItem::ExclusiveStart(vec![1]).cmp(&RangeSetItem::ExclusiveEnd(vec![2])),
860            Ordering::Less
861        );
862    }
863}