1#[cfg(feature = "semver")]
39pub mod semver;
40
41use std::borrow::Borrow;
42use std::cmp::Ordering;
43use std::fmt::{Debug, Display, Formatter};
44use std::ops::Bound::{self, Excluded, Included, Unbounded};
45use std::ops::RangeBounds;
46
47#[cfg(any(feature = "proptest", test))]
48use proptest::prelude::*;
49use smallvec::{smallvec, SmallVec};
50
51#[derive(Debug, Clone, Eq, PartialEq, Hash)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize))]
73#[cfg_attr(feature = "serde", serde(transparent))]
74pub struct Ranges<V> {
75 segments: SmallVec<[Interval<V>; 1]>,
79}
80
81#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub enum SetRelation {
87 Subset,
89 Disjoint,
91 Overlapping,
93}
94
95type Interval<V> = (Bound<V>, Bound<V>);
97
98impl<V> Ranges<V> {
99 pub fn empty() -> Self {
101 Self {
102 segments: SmallVec::new(),
103 }
104 }
105
106 pub fn full() -> Self {
108 Self {
109 segments: smallvec![(Unbounded, Unbounded)],
110 }
111 }
112
113 pub fn higher_than(v: impl Into<V>) -> Self {
115 Self {
116 segments: smallvec![(Included(v.into()), Unbounded)],
117 }
118 }
119
120 pub fn strictly_higher_than(v: impl Into<V>) -> Self {
122 Self {
123 segments: smallvec![(Excluded(v.into()), Unbounded)],
124 }
125 }
126
127 pub fn strictly_lower_than(v: impl Into<V>) -> Self {
129 Self {
130 segments: smallvec![(Unbounded, Excluded(v.into()))],
131 }
132 }
133
134 pub fn lower_than(v: impl Into<V>) -> Self {
136 Self {
137 segments: smallvec![(Unbounded, Included(v.into()))],
138 }
139 }
140
141 pub fn between(v1: impl Into<V>, v2: impl Into<V>) -> Self {
143 Self {
144 segments: smallvec![(Included(v1.into()), Excluded(v2.into()))],
145 }
146 }
147
148 pub fn is_empty(&self) -> bool {
150 self.segments.is_empty()
151 }
152}
153
154impl<V: Clone> Ranges<V> {
155 pub fn singleton(v: impl Into<V>) -> Self {
157 let v = v.into();
158 Self {
159 segments: smallvec![(Included(v.clone()), Included(v))],
160 }
161 }
162
163 pub fn complement(&self) -> Self {
165 match self.segments.first() {
166 None => Self::full(),
168
169 Some((Unbounded, Unbounded)) => Self::empty(),
171
172 Some((Included(v), Unbounded)) => Self::strictly_lower_than(v.clone()),
174 Some((Excluded(v), Unbounded)) => Self::lower_than(v.clone()),
175
176 Some((Unbounded, Included(v))) => {
177 Self::negate_segments(Excluded(v.clone()), &self.segments[1..])
178 }
179 Some((Unbounded, Excluded(v))) => {
180 Self::negate_segments(Included(v.clone()), &self.segments[1..])
181 }
182 Some((Included(_), Included(_)))
183 | Some((Included(_), Excluded(_)))
184 | Some((Excluded(_), Included(_)))
185 | Some((Excluded(_), Excluded(_))) => Self::negate_segments(Unbounded, &self.segments),
186 }
187 }
188
189 fn negate_segments(start: Bound<V>, segments: &[Interval<V>]) -> Self {
191 let mut complement_segments = SmallVec::new();
192 let mut start = start;
193 for (v1, v2) in segments {
194 complement_segments.push((
195 start,
196 match v1 {
197 Included(v) => Excluded(v.clone()),
198 Excluded(v) => Included(v.clone()),
199 Unbounded => unreachable!(),
200 },
201 ));
202 start = match v2 {
203 Included(v) => Excluded(v.clone()),
204 Excluded(v) => Included(v.clone()),
205 Unbounded => Unbounded,
206 }
207 }
208 if !matches!(start, Unbounded) {
209 complement_segments.push((start, Unbounded));
210 }
211
212 Self {
213 segments: complement_segments,
214 }
215 }
216}
217
218impl<V: Ord> Ranges<V> {
219 pub fn as_singleton(&self) -> Option<&V> {
221 match self.segments.as_slice() {
222 [(Included(v1), Included(v2))] => {
223 if v1 == v2 {
224 Some(v1)
225 } else {
226 None
227 }
228 }
229 _ => None,
230 }
231 }
232
233 pub fn bounding_range(&self) -> Option<(Bound<&V>, Bound<&V>)> {
239 self.segments.first().map(|(start, _)| {
240 let end = self
241 .segments
242 .last()
243 .expect("if there is a first element, there must be a last element");
244 (start.as_ref(), end.1.as_ref())
245 })
246 }
247
248 pub fn contains<Q>(&self, version: &Q) -> bool
250 where
251 V: Borrow<Q>,
252 Q: ?Sized + PartialOrd,
253 {
254 self.segments
255 .binary_search_by(|segment| {
256 within_bounds(version, segment).reverse()
259 })
260 .is_ok()
262 }
263
264 pub fn contains_many<'s, I, BV>(&'s self, versions: I) -> impl Iterator<Item = bool> + 's
270 where
271 I: Iterator<Item = BV> + 's,
272 BV: Borrow<V> + 's,
273 {
274 #[cfg(debug_assertions)]
275 let mut last: Option<BV> = None;
276 versions.scan(0, move |i, v| {
277 #[cfg(debug_assertions)]
278 {
279 if let Some(l) = last.as_ref() {
280 assert!(
281 l.borrow() <= v.borrow(),
282 "`contains_many` `versions` argument incorrectly sorted"
283 );
284 }
285 }
286 while let Some(segment) = self.segments.get(*i) {
287 match within_bounds(v.borrow(), segment) {
288 Ordering::Less => return Some(false),
289 Ordering::Equal => return Some(true),
290 Ordering::Greater => *i += 1,
291 }
292 }
293 #[cfg(debug_assertions)]
294 {
295 last = Some(v);
296 }
297 Some(false)
298 })
299 }
300
301 pub fn from_range_bounds<R, IV>(bounds: R) -> Self
303 where
304 R: RangeBounds<IV>,
305 IV: Clone + Into<V>,
306 {
307 let start = match bounds.start_bound() {
308 Included(v) => Included(v.clone().into()),
309 Excluded(v) => Excluded(v.clone().into()),
310 Unbounded => Unbounded,
311 };
312 let end = match bounds.end_bound() {
313 Included(v) => Included(v.clone().into()),
314 Excluded(v) => Excluded(v.clone().into()),
315 Unbounded => Unbounded,
316 };
317 if valid_segment(&start, &end) {
318 Self {
319 segments: smallvec![(start, end)],
320 }
321 } else {
322 Self::empty()
323 }
324 }
325
326 fn check_invariants(self) -> Self {
328 if cfg!(debug_assertions) {
329 for p in self.segments.as_slice().windows(2) {
330 assert!(end_before_start_with_gap(&p[0].1, &p[1].0));
331 }
332 for (s, e) in self.segments.iter() {
333 assert!(valid_segment(s, e));
334 }
335 }
336 self
337 }
338}
339
340fn cmp_bounds_start<V: PartialOrd>(left: Bound<&V>, right: Bound<&V>) -> Option<Ordering> {
354 Some(match (left, right) {
355 (Unbounded, Unbounded) => Ordering::Equal,
358 (Included(_left), Unbounded) => Ordering::Greater,
361 (Excluded(_left), Unbounded) => Ordering::Greater,
364 (Unbounded, Included(_right)) => Ordering::Less,
367 (Included(left), Included(right)) => left.partial_cmp(right)?,
370 (Excluded(left), Included(right)) => match left.partial_cmp(right)? {
371 Ordering::Less => Ordering::Less,
374 Ordering::Equal => Ordering::Greater,
377 Ordering::Greater => Ordering::Greater,
380 },
381 (Unbounded, Excluded(_right)) => Ordering::Less,
384 (Included(left), Excluded(right)) => match left.partial_cmp(right)? {
385 Ordering::Less => Ordering::Less,
388 Ordering::Equal => Ordering::Less,
391 Ordering::Greater => Ordering::Greater,
394 },
395 (Excluded(left), Excluded(right)) => left.partial_cmp(right)?,
398 })
399}
400
401fn cmp_bounds_end<V: PartialOrd>(left: Bound<&V>, right: Bound<&V>) -> Option<Ordering> {
417 Some(match (left, right) {
418 (Unbounded, Unbounded) => Ordering::Equal,
421 (Included(_left), Unbounded) => Ordering::Less,
424 (Excluded(_left), Unbounded) => Ordering::Less,
427 (Unbounded, Included(_right)) => Ordering::Greater,
430 (Included(left), Included(right)) => left.partial_cmp(right)?,
433 (Excluded(left), Included(right)) => match left.partial_cmp(right)? {
434 Ordering::Less => Ordering::Less,
437 Ordering::Equal => Ordering::Less,
440 Ordering::Greater => Ordering::Greater,
443 },
444 (Unbounded, Excluded(_right)) => Ordering::Greater,
445 (Included(left), Excluded(right)) => match left.partial_cmp(right)? {
446 Ordering::Less => Ordering::Less,
449 Ordering::Equal => Ordering::Greater,
452 Ordering::Greater => Ordering::Greater,
455 },
456 (Excluded(left), Excluded(right)) => left.partial_cmp(right)?,
459 })
460}
461
462impl<V: PartialOrd> PartialOrd for Ranges<V> {
463 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
467 for (left, right) in self.segments.iter().zip(other.segments.iter()) {
468 let start_cmp = cmp_bounds_start(left.start_bound(), right.start_bound())?;
469 if start_cmp != Ordering::Equal {
470 return Some(start_cmp);
471 }
472 let end_cmp = cmp_bounds_end(left.end_bound(), right.end_bound())?;
473 if end_cmp != Ordering::Equal {
474 return Some(end_cmp);
475 }
476 }
477 Some(self.segments.len().cmp(&other.segments.len()))
478 }
479}
480
481impl<V: Ord> Ord for Ranges<V> {
482 fn cmp(&self, other: &Self) -> Ordering {
483 self.partial_cmp(other)
484 .expect("PartialOrd must be `Some(Ordering)` for types that implement `Ord`")
485 }
486}
487
488fn within_bounds<Q, V>(version: &Q, segment: &Interval<V>) -> Ordering
495where
496 V: Borrow<Q>,
497 Q: ?Sized + PartialOrd,
498{
499 let below_lower_bound = match segment {
500 (Excluded(start), _) => version <= start.borrow(),
501 (Included(start), _) => version < start.borrow(),
502 (Unbounded, _) => false,
503 };
504 if below_lower_bound {
505 return Ordering::Less;
506 }
507 let below_upper_bound = match segment {
508 (_, Unbounded) => true,
509 (_, Included(end)) => version <= end.borrow(),
510 (_, Excluded(end)) => version < end.borrow(),
511 };
512 if below_upper_bound {
513 return Ordering::Equal;
514 }
515 Ordering::Greater
516}
517
518fn valid_segment<T: PartialOrd>(start: &Bound<T>, end: &Bound<T>) -> bool {
520 match (start, end) {
521 (Included(s), Included(e)) => s <= e,
523 (Included(s), Excluded(e)) => s < e,
524 (Excluded(s), Included(e)) => s < e,
525 (Excluded(s), Excluded(e)) => s < e,
526 (Unbounded, _) | (_, Unbounded) => true,
527 }
528}
529
530fn end_before_start_with_gap<V: PartialOrd>(end: &Bound<V>, start: &Bound<V>) -> bool {
548 match (end, start) {
549 (_, Unbounded) => false,
550 (Unbounded, _) => false,
551 (Included(left), Included(right)) => left < right,
552 (Included(left), Excluded(right)) => left < right,
553 (Excluded(left), Included(right)) => left < right,
554 (Excluded(left), Excluded(right)) => left <= right,
555 }
556}
557
558fn left_start_is_smaller<V: PartialOrd>(left: Bound<V>, right: Bound<V>) -> bool {
559 match (left, right) {
560 (Unbounded, _) => true,
561 (_, Unbounded) => false,
562 (Included(l), Included(r)) => l <= r,
563 (Excluded(l), Excluded(r)) => l <= r,
564 (Included(l), Excluded(r)) => l <= r,
565 (Excluded(l), Included(r)) => l < r,
566 }
567}
568
569fn left_end_is_smaller<V: PartialOrd>(left: Bound<V>, right: Bound<V>) -> bool {
570 match (left, right) {
571 (_, Unbounded) => true,
572 (Unbounded, _) => false,
573 (Included(l), Included(r)) => l <= r,
574 (Excluded(l), Excluded(r)) => l <= r,
575 (Excluded(l), Included(r)) => l <= r,
576 (Included(l), Excluded(r)) => l < r,
577 }
578}
579
580fn group_adjacent_locations(
589 mut locations: impl Iterator<Item = Option<usize>>,
590) -> impl Iterator<Item = (Option<usize>, Option<usize>)> {
591 let mut seg = locations.next().flatten().map(|ver| (None, Some(ver)));
593 std::iter::from_fn(move || {
594 for ver in locations.by_ref() {
595 if let Some(ver) = ver {
596 seg = Some((seg.map_or(Some(ver), |(s, _)| s), Some(ver)));
598 } else {
599 if seg.is_some() {
601 return seg.take();
602 }
603 }
604 }
605 seg.take().map(|(s, _)| (s, None))
607 })
608}
609
610impl<V: Ord + Clone> Ranges<V> {
611 pub fn union(&self, other: &Self) -> Self {
613 let mut output = SmallVec::new();
614 let mut accumulator: Option<(&Bound<_>, &Bound<_>)> = None;
615 let mut left_iter = self.segments.iter().peekable();
616 let mut right_iter = other.segments.iter().peekable();
617 loop {
618 let smaller_interval = match (left_iter.peek(), right_iter.peek()) {
619 (Some((left_start, left_end)), Some((right_start, right_end))) => {
620 if left_start_is_smaller(left_start.as_ref(), right_start.as_ref()) {
621 left_iter.next();
622 (left_start, left_end)
623 } else {
624 right_iter.next();
625 (right_start, right_end)
626 }
627 }
628 (Some((left_start, left_end)), None) => {
629 left_iter.next();
630 (left_start, left_end)
631 }
632 (None, Some((right_start, right_end))) => {
633 right_iter.next();
634 (right_start, right_end)
635 }
636 (None, None) => break,
637 };
638
639 if let Some(accumulator_) = accumulator {
640 if end_before_start_with_gap(accumulator_.1, smaller_interval.0) {
641 output.push((accumulator_.0.clone(), accumulator_.1.clone()));
642 accumulator = Some(smaller_interval);
643 } else {
644 let accumulator_end = match (accumulator_.1, smaller_interval.1) {
645 (_, Unbounded) | (Unbounded, _) => &Unbounded,
646 (Included(l), Excluded(r) | Included(r)) if l == r => accumulator_.1,
647 (Included(l) | Excluded(l), Included(r) | Excluded(r)) => {
648 if l > r {
649 accumulator_.1
650 } else {
651 smaller_interval.1
652 }
653 }
654 };
655 accumulator = Some((accumulator_.0, accumulator_end));
656 }
657 } else {
658 accumulator = Some(smaller_interval)
659 }
660 }
661
662 if let Some(accumulator) = accumulator {
663 output.push((accumulator.0.clone(), accumulator.1.clone()));
664 }
665
666 Self { segments: output }.check_invariants()
667 }
668
669 pub fn intersection(&self, other: &Self) -> Self {
671 let mut output = SmallVec::new();
672 let mut left_iter = self.segments.iter().peekable();
673 let mut right_iter = other.segments.iter().peekable();
674 while let Some(((left_start, left_end), (right_start, right_end))) =
681 left_iter.peek().zip(right_iter.peek())
682 {
683 let left_end_is_smaller = left_end_is_smaller(left_end.as_ref(), right_end.as_ref());
685 let (other_start, end) = if left_end_is_smaller {
691 left_iter.next();
692 (right_start, left_end)
693 } else {
694 right_iter.next();
695 (left_start, right_end)
696 };
697 if !valid_segment(other_start, end) {
703 continue;
706 }
707 let start = match (left_start, right_start) {
708 (Included(l), Included(r)) => Included(std::cmp::max(l, r)),
709 (Excluded(l), Excluded(r)) => Excluded(std::cmp::max(l, r)),
710
711 (Included(i), Excluded(e)) | (Excluded(e), Included(i)) => {
712 if i <= e {
713 Excluded(e)
714 } else {
715 Included(i)
716 }
717 }
718 (s, Unbounded) | (Unbounded, s) => s.as_ref(),
719 };
720 output.push((start.cloned(), end.clone()))
723 }
724
725 Self { segments: output }.check_invariants()
726 }
727
728 pub fn is_disjoint(&self, other: &Self) -> bool {
733 let mut left_iter = self.segments.iter().peekable();
735 let mut right_iter = other.segments.iter().peekable();
736
737 while let Some((left, right)) = left_iter.peek().zip(right_iter.peek()) {
738 if !valid_segment(&right.start_bound(), &left.end_bound()) {
739 left_iter.next();
740 } else if !valid_segment(&left.start_bound(), &right.end_bound()) {
741 right_iter.next();
742 } else {
743 return false;
744 }
745 }
746
747 true
749 }
750
751 pub fn relation(&self, other: &Self) -> SetRelation {
756 if self.segments.len() > 1
758 && self.segments.len() == other.segments.len()
759 && self.segments == other.segments
760 {
761 return SetRelation::Subset;
762 }
763
764 let mut other_iter = other.segments.iter().peekable();
765 let mut is_subset = true;
766 let mut overlaps = false;
767
768 for subset_elem in &self.segments {
769 while other_iter.peek().is_some_and(|containing_elem| {
770 !valid_segment(&subset_elem.start_bound(), &containing_elem.end_bound())
771 }) {
772 other_iter.next();
773 }
774
775 let Some(containing_elem) = other_iter.peek() else {
776 is_subset = false;
777 break;
778 };
779
780 if !valid_segment(&containing_elem.start_bound(), &subset_elem.end_bound()) {
781 is_subset = false;
782 continue;
783 }
784
785 overlaps = true;
786 if !left_start_is_smaller(containing_elem.start_bound(), subset_elem.start_bound())
787 || !left_end_is_smaller(subset_elem.end_bound(), containing_elem.end_bound())
788 {
789 is_subset = false;
790 }
791 }
792
793 if is_subset {
794 SetRelation::Subset
795 } else if overlaps {
796 SetRelation::Overlapping
797 } else {
798 SetRelation::Disjoint
799 }
800 }
801
802 pub fn subset_of(&self, other: &Self) -> bool {
807 if self.segments.len() > 1
809 && self.segments.len() == other.segments.len()
810 && self.segments == other.segments
811 {
812 return true;
813 }
814
815 let mut containing_iter = other.segments.iter();
816 let mut subset_iter = self.segments.iter();
817 let Some(mut containing_elem) = containing_iter.next() else {
818 return subset_iter.next().is_none();
820 };
821
822 for subset_elem in subset_iter {
823 while !valid_segment(&subset_elem.start_bound(), &containing_elem.end_bound()) {
826 if let Some(containing_elem_) = containing_iter.next() {
827 containing_elem = containing_elem_;
828 } else {
829 return false;
830 };
831 }
832
833 let start_contained =
834 left_start_is_smaller(containing_elem.start_bound(), subset_elem.start_bound());
835
836 if !start_contained {
837 return false;
839 }
840
841 let end_contained =
842 left_end_is_smaller(subset_elem.end_bound(), containing_elem.end_bound());
843
844 if !end_contained {
845 return false;
847 }
848 }
849
850 true
851 }
852
853 pub fn simplify<'s, I, BV>(&self, versions: I) -> Self
864 where
865 I: Iterator<Item = BV> + 's,
866 BV: Borrow<V> + 's,
867 {
868 if self.as_singleton().is_some() {
870 return self.clone();
871 }
872
873 #[cfg(debug_assertions)]
874 let mut last: Option<BV> = None;
875 let version_locations = versions.scan(0, move |i, v| {
877 #[cfg(debug_assertions)]
878 {
879 if let Some(l) = last.as_ref() {
880 assert!(
881 l.borrow() <= v.borrow(),
882 "`simplify` `versions` argument incorrectly sorted"
883 );
884 }
885 }
886 while let Some(segment) = self.segments.get(*i) {
887 match within_bounds(v.borrow(), segment) {
888 Ordering::Less => return Some(None),
889 Ordering::Equal => return Some(Some(*i)),
890 Ordering::Greater => *i += 1,
891 }
892 }
893 #[cfg(debug_assertions)]
894 {
895 last = Some(v);
896 }
897 Some(None)
898 });
899 let mut kept_segments = group_adjacent_locations(version_locations).peekable();
900
901 if kept_segments.peek().is_none() {
903 return self.clone();
904 }
905
906 self.keep_segments(kept_segments)
907 }
908
909 fn keep_segments(
914 &self,
915 kept_segments: impl Iterator<Item = (Option<usize>, Option<usize>)>,
916 ) -> Ranges<V> {
917 let mut segments = SmallVec::new();
918 for (s, e) in kept_segments {
919 segments.push((
920 s.map_or(Unbounded, |s| self.segments[s].0.clone()),
921 e.map_or(Unbounded, |e| self.segments[e].1.clone()),
922 ));
923 }
924 Self { segments }.check_invariants()
925 }
926
927 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Bound<&V>, Bound<&V>)> {
929 self.segments
930 .iter()
931 .map(|(start, end)| (start.as_ref(), end.as_ref()))
932 }
933}
934
935pub struct RangesIter<V>(smallvec::IntoIter<[Interval<V>; 1]>);
937
938impl<V> Iterator for RangesIter<V> {
939 type Item = Interval<V>;
940
941 fn next(&mut self) -> Option<Self::Item> {
942 self.0.next()
943 }
944
945 fn size_hint(&self) -> (usize, Option<usize>) {
946 (self.0.len(), Some(self.0.len()))
947 }
948}
949
950impl<V> ExactSizeIterator for RangesIter<V> {}
951
952impl<V> DoubleEndedIterator for RangesIter<V> {
953 fn next_back(&mut self) -> Option<Self::Item> {
954 self.0.next_back()
955 }
956}
957
958impl<V> IntoIterator for Ranges<V> {
959 type Item = (Bound<V>, Bound<V>);
960 type IntoIter = RangesIter<V>;
962
963 fn into_iter(self) -> Self::IntoIter {
964 RangesIter(self.segments.into_iter())
965 }
966}
967
968impl<V: Ord> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
969 fn from_iter<T: IntoIterator<Item = (Bound<V>, Bound<V>)>>(iter: T) -> Self {
974 let mut segments: SmallVec<[Interval<V>; 1]> = SmallVec::new();
991
992 for segment in iter {
993 if !valid_segment(&segment.start_bound(), &segment.end_bound()) {
994 continue;
995 }
996 let insertion_point = segments.partition_point(|elem: &Interval<V>| {
998 cmp_bounds_start(elem.start_bound(), segment.start_bound())
999 .unwrap()
1000 .is_lt()
1001 });
1002 let previous_overlapping = insertion_point > 0
1004 && !end_before_start_with_gap(
1005 &segments[insertion_point - 1].end_bound(),
1006 &segment.start_bound(),
1007 );
1008
1009 let next_overlapping = insertion_point < segments.len()
1012 && !end_before_start_with_gap(
1013 &segment.end_bound(),
1014 &segments[insertion_point].start_bound(),
1015 );
1016
1017 match (previous_overlapping, next_overlapping) {
1018 (true, true) => {
1019 let mut following = segments.remove(insertion_point);
1042 while insertion_point < segments.len()
1043 && !end_before_start_with_gap(
1044 &segment.end_bound(),
1045 &segments[insertion_point].start_bound(),
1046 )
1047 {
1048 following = segments.remove(insertion_point);
1049 }
1050
1051 if cmp_bounds_end(segment.end_bound(), following.end_bound())
1053 .unwrap()
1054 .is_lt()
1055 {
1056 segments[insertion_point - 1].1 = following.1;
1057 } else {
1058 segments[insertion_point - 1].1 = segment.1;
1059 }
1060 }
1061 (true, false) => {
1062 if cmp_bounds_end(
1077 segments[insertion_point - 1].end_bound(),
1078 segment.end_bound(),
1079 )
1080 .unwrap()
1081 .is_lt()
1082 {
1083 segments[insertion_point - 1].1 = segment.1;
1084 }
1085 }
1086 (false, true) => {
1087 while insertion_point + 1 < segments.len()
1111 && !end_before_start_with_gap(
1112 &segment.end_bound(),
1113 &segments[insertion_point + 1].start_bound(),
1114 )
1115 {
1116 segments.remove(insertion_point);
1119 }
1120
1121 if cmp_bounds_end(segments[insertion_point].end_bound(), segment.end_bound())
1123 .unwrap()
1124 .is_lt()
1125 {
1126 segments[insertion_point].1 = segment.1;
1127 }
1128 segments[insertion_point].0 = segment.0;
1129 }
1130 (false, false) => {
1131 segments.insert(insertion_point, segment);
1140 }
1141 }
1142 }
1143
1144 Self { segments }.check_invariants()
1145 }
1146}
1147
1148impl<V: Display + Eq> Display for Ranges<V> {
1151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1152 if self.segments.is_empty() {
1153 write!(f, "∅")?;
1154 } else {
1155 for (idx, segment) in self.segments.iter().enumerate() {
1156 if idx > 0 {
1157 write!(f, " | ")?;
1158 }
1159 match segment {
1160 (Unbounded, Unbounded) => write!(f, "*")?,
1161 (Unbounded, Included(v)) => write!(f, "<={v}")?,
1162 (Unbounded, Excluded(v)) => write!(f, "<{v}")?,
1163 (Included(v), Unbounded) => write!(f, ">={v}")?,
1164 (Included(v), Included(b)) => {
1165 if v == b {
1166 write!(f, "=={v}")?
1167 } else {
1168 write!(f, ">={v}, <={b}")?
1169 }
1170 }
1171 (Included(v), Excluded(b)) => write!(f, ">={v}, <{b}")?,
1172 (Excluded(v), Unbounded) => write!(f, ">{v}")?,
1173 (Excluded(v), Included(b)) => write!(f, ">{v}, <={b}")?,
1174 (Excluded(v), Excluded(b)) => write!(f, ">{v}, <{b}")?,
1175 };
1176 }
1177 }
1178 Ok(())
1179 }
1180}
1181
1182#[cfg(feature = "serde")]
1185impl<'de, V: serde::Deserialize<'de>> serde::Deserialize<'de> for Ranges<V> {
1186 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1187 #[derive(serde::Deserialize)]
1192 #[serde(untagged)]
1193 enum EitherInterval<V> {
1194 B(Bound<V>, Bound<V>),
1195 D(V, Option<V>),
1196 }
1197
1198 let bounds: SmallVec<[EitherInterval<V>; 2]> =
1199 serde::Deserialize::deserialize(deserializer)?;
1200
1201 let mut segments = SmallVec::new();
1202 for i in bounds {
1203 match i {
1204 EitherInterval::B(l, r) => segments.push((l, r)),
1205 EitherInterval::D(l, Some(r)) => segments.push((Included(l), Excluded(r))),
1206 EitherInterval::D(l, None) => segments.push((Included(l), Unbounded)),
1207 }
1208 }
1209
1210 Ok(Ranges { segments })
1211 }
1212}
1213
1214#[cfg(any(feature = "proptest", test))]
1217pub fn proptest_strategy() -> impl Strategy<Value = Ranges<u32>> {
1218 (
1219 any::<bool>(),
1220 prop::collection::vec(any::<(u32, bool)>(), 0..10),
1221 )
1222 .prop_map(|(start_unbounded, deltas)| {
1223 let mut start = if start_unbounded {
1224 Some(Unbounded)
1225 } else {
1226 None
1227 };
1228 let mut largest: u32 = 0;
1229 let mut last_bound_was_inclusive = false;
1230 let mut segments = SmallVec::new();
1231 for (delta, inclusive) in deltas {
1232 largest = match largest.checked_add(delta) {
1234 Some(s) => s,
1235 None => {
1236 continue;
1238 }
1239 };
1240
1241 let current_bound = if inclusive {
1242 Included(largest)
1243 } else {
1244 Excluded(largest)
1245 };
1246
1247 if let Some(start_bound) = start.take() {
1250 if delta == 0 && !(matches!(start_bound, Included(_)) && inclusive) {
1253 start = Some(start_bound);
1254 continue;
1255 }
1256 last_bound_was_inclusive = inclusive;
1257 segments.push((start_bound, current_bound));
1258 } else {
1259 if delta == 0 && (last_bound_was_inclusive || inclusive) {
1263 continue;
1264 }
1265 start = Some(current_bound);
1266 }
1267 }
1268
1269 if let Some(start_bound) = start {
1272 segments.push((start_bound, Unbounded));
1273 }
1274
1275 Ranges { segments }.check_invariants()
1276 })
1277}
1278
1279#[cfg(test)]
1280pub mod tests {
1281 use proptest::prelude::*;
1282
1283 use super::*;
1284
1285 fn version_strat() -> impl Strategy<Value = u32> {
1286 any::<u32>()
1287 }
1288
1289 proptest! {
1290
1291 #[cfg(feature = "serde")]
1294 #[test]
1295 fn serde_round_trip(range in proptest_strategy()) {
1296 let s = ron::ser::to_string(&range).unwrap();
1297 let r = ron::de::from_str(&s).unwrap();
1298 assert_eq!(range, r);
1299 }
1300
1301 #[test]
1304 fn negate_is_different(range in proptest_strategy()) {
1305 assert_ne!(range.complement(), range);
1306 }
1307
1308 #[test]
1309 fn double_negate_is_identity(range in proptest_strategy()) {
1310 assert_eq!(range.complement().complement(), range);
1311 }
1312
1313 #[test]
1314 fn negate_contains_opposite(range in proptest_strategy(), version in version_strat()) {
1315 assert_ne!(range.contains(&version), range.complement().contains(&version));
1316 }
1317
1318 #[test]
1321 fn intersection_is_symmetric(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1322 assert_eq!(r1.intersection(&r2), r2.intersection(&r1));
1323 }
1324
1325 #[test]
1326 fn intersection_with_any_is_identity(range in proptest_strategy()) {
1327 assert_eq!(Ranges::full().intersection(&range), range);
1328 }
1329
1330 #[test]
1331 fn intersection_with_none_is_none(range in proptest_strategy()) {
1332 assert_eq!(Ranges::empty().intersection(&range), Ranges::empty());
1333 }
1334
1335 #[test]
1336 fn intersection_is_idempotent(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1337 assert_eq!(r1.intersection(&r2).intersection(&r2), r1.intersection(&r2));
1338 }
1339
1340 #[test]
1341 fn intersection_is_associative(r1 in proptest_strategy(), r2 in proptest_strategy(), r3 in proptest_strategy()) {
1342 assert_eq!(r1.intersection(&r2).intersection(&r3), r1.intersection(&r2.intersection(&r3)));
1343 }
1344
1345 #[test]
1346 fn intesection_of_complements_is_none(range in proptest_strategy()) {
1347 assert_eq!(range.complement().intersection(&range), Ranges::empty());
1348 }
1349
1350 #[test]
1351 fn intesection_contains_both(r1 in proptest_strategy(), r2 in proptest_strategy(), version in version_strat()) {
1352 assert_eq!(r1.intersection(&r2).contains(&version), r1.contains(&version) && r2.contains(&version));
1353 }
1354
1355 #[test]
1358 fn union_of_complements_is_any(range in proptest_strategy()) {
1359 assert_eq!(range.complement().union(&range), Ranges::full());
1360 }
1361
1362 #[test]
1363 fn union_contains_either(r1 in proptest_strategy(), r2 in proptest_strategy(), version in version_strat()) {
1364 assert_eq!(r1.union(&r2).contains(&version), r1.contains(&version) || r2.contains(&version));
1365 }
1366
1367 #[test]
1368 fn is_disjoint_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1369 let disjoint_def = r1.intersection(&r2) == Ranges::empty();
1370 assert_eq!(r1.is_disjoint(&r2), disjoint_def);
1371 }
1372
1373 #[test]
1374 fn subset_of_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1375 let disjoint_def = r1.intersection(&r2) == r1;
1376 assert_eq!(r1.subset_of(&r2), disjoint_def);
1377 }
1378
1379 #[test]
1380 fn relation_through_subset_and_disjoint(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1381 let relation_def = if r1.subset_of(&r2) {
1382 SetRelation::Subset
1383 } else if r1.is_disjoint(&r2) {
1384 SetRelation::Disjoint
1385 } else {
1386 SetRelation::Overlapping
1387 };
1388 assert_eq!(r1.relation(&r2), relation_def);
1389 }
1390
1391 #[test]
1392 fn union_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1393 let union_def = r1
1394 .complement()
1395 .intersection(&r2.complement())
1396 .complement()
1397 .check_invariants();
1398 assert_eq!(r1.union(&r2), union_def);
1399 }
1400
1401 #[test]
1404 fn always_contains_exact(version in version_strat()) {
1405 assert!(Ranges::<u32>::singleton(version).contains(&version));
1406 }
1407
1408 #[test]
1409 fn contains_negation(range in proptest_strategy(), version in version_strat()) {
1410 assert_ne!(range.contains(&version), range.complement().contains(&version));
1411 }
1412
1413 #[test]
1414 fn contains_intersection(range in proptest_strategy(), version in version_strat()) {
1415 assert_eq!(range.contains(&version), range.intersection(&Ranges::singleton(version)) != Ranges::empty());
1416 }
1417
1418 #[test]
1419 fn contains_bounding_range(range in proptest_strategy(), version in version_strat()) {
1420 if range.contains(&version) {
1421 assert!(range.bounding_range().map(|b| b.contains(&version)).unwrap_or(false));
1422 }
1423 }
1424
1425 #[test]
1426 fn from_range_bounds(range in any::<(Bound<u32>, Bound<u32>)>(), version in version_strat()) {
1427 let rv: Ranges<_> = Ranges::<u32>::from_range_bounds(range);
1428 assert_eq!(range.contains(&version), rv.contains(&version));
1429 }
1430
1431 #[test]
1432 fn from_range_bounds_round_trip(range in any::<(Bound<u32>, Bound<u32>)>()) {
1433 let rv: Ranges<u32> = Ranges::from_range_bounds(range);
1434 let rv2: Ranges<u32> = rv.bounding_range().map(Ranges::from_range_bounds::<_, u32>).unwrap_or_else(Ranges::empty);
1435 assert_eq!(rv, rv2);
1436 }
1437
1438 #[test]
1439 fn contains(range in proptest_strategy(), versions in proptest::collection::vec(version_strat(), ..30)) {
1440 for v in versions {
1441 assert_eq!(range.contains(&v), range.segments.iter().any(|s| RangeBounds::contains(s, &v)));
1442 }
1443 }
1444
1445 #[test]
1446 fn contains_many(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1447 versions.sort();
1448 assert_eq!(versions.len(), range.contains_many(versions.iter()).count());
1449 for (a, b) in versions.iter().zip(range.contains_many(versions.iter())) {
1450 assert_eq!(range.contains(a), b);
1451 }
1452 }
1453
1454 #[test]
1455 fn simplify(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1456 versions.sort();
1457 let simp = range.simplify(versions.iter());
1458
1459 for v in versions {
1460 assert_eq!(range.contains(&v), simp.contains(&v));
1461 }
1462 assert!(simp.segments.len() <= range.segments.len())
1463 }
1464
1465 #[test]
1466 fn from_iter_valid(segments in proptest::collection::vec(any::<(Bound<u32>, Bound<u32>)>(), ..30)) {
1467 let mut expected = Ranges::empty();
1468 for segment in &segments {
1469 expected = expected.union(&Ranges::from_range_bounds(*segment));
1470 }
1471 let actual = Ranges::from_iter(segments.clone());
1472 assert_eq!(expected, actual, "{segments:?}");
1473 }
1474 }
1475
1476 #[test]
1477 fn contains_many_can_take_owned() {
1478 let range: Ranges<u8> = Ranges::singleton(1);
1479 let versions = vec![1, 2, 3];
1480 assert_eq!(
1482 range.contains_many(versions.iter()).count(),
1483 range
1484 .contains_many(versions.iter().map(std::borrow::Cow::Borrowed))
1485 .count()
1486 );
1487 assert_eq!(
1489 range.contains_many(versions.iter()).count(),
1490 range.contains_many(versions.into_iter()).count()
1491 );
1492 }
1493
1494 #[test]
1495 fn contains_can_take_owned() {
1496 let range: Ranges<Box<u8>> = Ranges::singleton(1);
1497 let version = 1;
1498
1499 assert_eq!(range.contains(&Box::new(version)), range.contains(&version));
1500 let range: Ranges<String> = Ranges::singleton(1.to_string());
1501 let version = 1.to_string();
1502 assert_eq!(range.contains(&version), range.contains("1"));
1503 }
1504
1505 #[test]
1506 fn simplify_can_take_owned() {
1507 let range: Ranges<u8> = Ranges::singleton(1);
1508 let versions = vec![1, 2, 3];
1509 assert_eq!(
1511 range.simplify(versions.iter()),
1512 range.simplify(versions.iter().map(std::borrow::Cow::Borrowed))
1513 );
1514 assert_eq!(
1516 range.simplify(versions.iter()),
1517 range.simplify(versions.into_iter())
1518 );
1519 }
1520
1521 #[test]
1522 fn version_ord() {
1523 let versions: &[Ranges<u32>] = &[
1524 Ranges::strictly_lower_than(1u32),
1525 Ranges::lower_than(1u32),
1526 Ranges::singleton(1u32),
1527 Ranges::between(1u32, 3u32),
1528 Ranges::higher_than(1u32),
1529 Ranges::strictly_higher_than(1u32),
1530 Ranges::singleton(2u32),
1531 Ranges::singleton(2u32).union(&Ranges::singleton(3u32)),
1532 Ranges::singleton(2u32)
1533 .union(&Ranges::singleton(3u32))
1534 .union(&Ranges::singleton(4u32)),
1535 Ranges::singleton(2u32).union(&Ranges::singleton(4u32)),
1536 Ranges::singleton(3u32),
1537 ];
1538
1539 let mut versions_sorted = versions.to_vec();
1540 versions_sorted.sort();
1541 assert_eq!(versions_sorted, versions);
1542
1543 let mut version_reverse_sorted = versions.to_vec();
1545 version_reverse_sorted.reverse();
1546 version_reverse_sorted.sort();
1547 assert_eq!(version_reverse_sorted, versions);
1548 }
1549}