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 complement_bound<V>(bound: &Bound<V>) -> Option<Bound<&V>> {
534 match bound {
535 Included(version) => Some(Excluded(version)),
536 Excluded(version) => Some(Included(version)),
537 Unbounded => None,
538 }
539}
540
541fn end_before_start_with_gap<V: PartialOrd>(end: &Bound<V>, start: &Bound<V>) -> bool {
559 match (end, start) {
560 (_, Unbounded) => false,
561 (Unbounded, _) => false,
562 (Included(left), Included(right)) => left < right,
563 (Included(left), Excluded(right)) => left < right,
564 (Excluded(left), Included(right)) => left < right,
565 (Excluded(left), Excluded(right)) => left <= right,
566 }
567}
568
569fn left_start_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 (Included(l), Excluded(r)) => l <= r,
576 (Excluded(l), Included(r)) => l < r,
577 }
578}
579
580fn left_end_is_smaller<V: PartialOrd>(left: Bound<V>, right: Bound<V>) -> bool {
581 match (left, right) {
582 (_, Unbounded) => true,
583 (Unbounded, _) => false,
584 (Included(l), Included(r)) => l <= r,
585 (Excluded(l), Excluded(r)) => l <= r,
586 (Excluded(l), Included(r)) => l <= r,
587 (Included(l), Excluded(r)) => l < r,
588 }
589}
590
591fn group_adjacent_locations(
600 mut locations: impl Iterator<Item = Option<usize>>,
601) -> impl Iterator<Item = (Option<usize>, Option<usize>)> {
602 let mut seg = locations.next().flatten().map(|ver| (None, Some(ver)));
604 std::iter::from_fn(move || {
605 for ver in locations.by_ref() {
606 if let Some(ver) = ver {
607 seg = Some((seg.map_or(Some(ver), |(s, _)| s), Some(ver)));
609 } else {
610 if seg.is_some() {
612 return seg.take();
613 }
614 }
615 }
616 seg.take().map(|(s, _)| (s, None))
618 })
619}
620
621impl<V: Ord + Clone> Ranges<V> {
622 pub fn union(&self, other: &Self) -> Self {
624 let mut output = SmallVec::new();
625 let mut accumulator: Option<(&Bound<_>, &Bound<_>)> = None;
626 let mut left_iter = self.segments.iter().peekable();
627 let mut right_iter = other.segments.iter().peekable();
628 loop {
629 let smaller_interval = match (left_iter.peek(), right_iter.peek()) {
630 (Some((left_start, left_end)), Some((right_start, right_end))) => {
631 if left_start_is_smaller(left_start.as_ref(), right_start.as_ref()) {
632 left_iter.next();
633 (left_start, left_end)
634 } else {
635 right_iter.next();
636 (right_start, right_end)
637 }
638 }
639 (Some((left_start, left_end)), None) => {
640 left_iter.next();
641 (left_start, left_end)
642 }
643 (None, Some((right_start, right_end))) => {
644 right_iter.next();
645 (right_start, right_end)
646 }
647 (None, None) => break,
648 };
649
650 if let Some(accumulator_) = accumulator {
651 if end_before_start_with_gap(accumulator_.1, smaller_interval.0) {
652 output.push((accumulator_.0.clone(), accumulator_.1.clone()));
653 accumulator = Some(smaller_interval);
654 } else {
655 let accumulator_end = match (accumulator_.1, smaller_interval.1) {
656 (_, Unbounded) | (Unbounded, _) => &Unbounded,
657 (Included(l), Excluded(r) | Included(r)) if l == r => accumulator_.1,
658 (Included(l) | Excluded(l), Included(r) | Excluded(r)) => {
659 if l > r {
660 accumulator_.1
661 } else {
662 smaller_interval.1
663 }
664 }
665 };
666 accumulator = Some((accumulator_.0, accumulator_end));
667 }
668 } else {
669 accumulator = Some(smaller_interval)
670 }
671 }
672
673 if let Some(accumulator) = accumulator {
674 output.push((accumulator.0.clone(), accumulator.1.clone()));
675 }
676
677 Self { segments: output }.check_invariants()
678 }
679
680 pub fn intersection(&self, other: &Self) -> Self {
682 let mut output = SmallVec::new();
683 let mut left_iter = self.segments.iter().peekable();
684 let mut right_iter = other.segments.iter().peekable();
685 while let Some(((left_start, left_end), (right_start, right_end))) =
692 left_iter.peek().zip(right_iter.peek())
693 {
694 let left_end_is_smaller = left_end_is_smaller(left_end.as_ref(), right_end.as_ref());
696 let (other_start, end) = if left_end_is_smaller {
702 left_iter.next();
703 (right_start, left_end)
704 } else {
705 right_iter.next();
706 (left_start, right_end)
707 };
708 if !valid_segment(other_start, end) {
714 continue;
717 }
718 let start = match (left_start, right_start) {
719 (Included(l), Included(r)) => Included(std::cmp::max(l, r)),
720 (Excluded(l), Excluded(r)) => Excluded(std::cmp::max(l, r)),
721
722 (Included(i), Excluded(e)) | (Excluded(e), Included(i)) => {
723 if i <= e {
724 Excluded(e)
725 } else {
726 Included(i)
727 }
728 }
729 (s, Unbounded) | (Unbounded, s) => s.as_ref(),
730 };
731 output.push((start.cloned(), end.clone()))
734 }
735
736 Self { segments: output }.check_invariants()
737 }
738
739 pub fn difference(&self, other: &Self) -> Self {
745 let mut output = SmallVec::new();
746 let mut right_iter = other.segments.iter().peekable();
747 for (left_start, left_end) in &self.segments {
748 let mut current_start = left_start.as_ref();
751 loop {
752 while let Some((_, right_end)) = right_iter.peek() {
756 if valid_segment(¤t_start, &right_end.as_ref()) {
757 break;
758 }
759 right_iter.next();
760 }
761 let Some((right_start, right_end)) = right_iter.peek().copied() else {
762 output.push((current_start.cloned(), left_end.clone()));
764 break;
765 };
766 if !valid_segment(&right_start.as_ref(), &left_end.as_ref()) {
768 output.push((current_start.cloned(), left_end.clone()));
770 break;
771 }
772
773 if let Some(cut_end) = complement_bound(right_start) {
775 if valid_segment(¤t_start, &cut_end) {
776 output.push((current_start.cloned(), cut_end.cloned()));
777 }
778 }
779 let Some(next_start) = complement_bound(right_end) else {
780 return Self { segments: output }.check_invariants();
783 };
784 if valid_segment(&next_start, &left_end.as_ref()) {
788 current_start = next_start;
790 right_iter.next();
791 } else {
792 break;
795 }
796 }
797 }
798
799 Self { segments: output }.check_invariants()
800 }
801
802 pub fn is_disjoint(&self, other: &Self) -> bool {
807 let mut left_iter = self.segments.iter().peekable();
809 let mut right_iter = other.segments.iter().peekable();
810
811 while let Some((left, right)) = left_iter.peek().zip(right_iter.peek()) {
812 if !valid_segment(&right.start_bound(), &left.end_bound()) {
813 left_iter.next();
814 } else if !valid_segment(&left.start_bound(), &right.end_bound()) {
815 right_iter.next();
816 } else {
817 return false;
818 }
819 }
820
821 true
823 }
824
825 pub fn relation(&self, other: &Self) -> SetRelation {
830 if self.segments.len() > 1
832 && self.segments.len() == other.segments.len()
833 && self.segments == other.segments
834 {
835 return SetRelation::Subset;
836 }
837
838 let mut other_iter = other.segments.iter().peekable();
839 let mut is_subset = true;
840 let mut overlaps = false;
841
842 for subset_elem in &self.segments {
843 while other_iter.peek().is_some_and(|containing_elem| {
844 !valid_segment(&subset_elem.start_bound(), &containing_elem.end_bound())
845 }) {
846 other_iter.next();
847 }
848
849 let Some(containing_elem) = other_iter.peek() else {
850 is_subset = false;
851 break;
852 };
853
854 if !valid_segment(&containing_elem.start_bound(), &subset_elem.end_bound()) {
855 is_subset = false;
856 continue;
857 }
858
859 overlaps = true;
860 if !left_start_is_smaller(containing_elem.start_bound(), subset_elem.start_bound())
861 || !left_end_is_smaller(subset_elem.end_bound(), containing_elem.end_bound())
862 {
863 is_subset = false;
864 }
865 }
866
867 if is_subset {
868 SetRelation::Subset
869 } else if overlaps {
870 SetRelation::Overlapping
871 } else {
872 SetRelation::Disjoint
873 }
874 }
875
876 pub fn subset_of(&self, other: &Self) -> bool {
881 if self.segments.len() > 1
883 && self.segments.len() == other.segments.len()
884 && self.segments == other.segments
885 {
886 return true;
887 }
888
889 let mut containing_iter = other.segments.iter();
890 let mut subset_iter = self.segments.iter();
891 let Some(mut containing_elem) = containing_iter.next() else {
892 return subset_iter.next().is_none();
894 };
895
896 for subset_elem in subset_iter {
897 while !valid_segment(&subset_elem.start_bound(), &containing_elem.end_bound()) {
900 if let Some(containing_elem_) = containing_iter.next() {
901 containing_elem = containing_elem_;
902 } else {
903 return false;
904 };
905 }
906
907 let start_contained =
908 left_start_is_smaller(containing_elem.start_bound(), subset_elem.start_bound());
909
910 if !start_contained {
911 return false;
913 }
914
915 let end_contained =
916 left_end_is_smaller(subset_elem.end_bound(), containing_elem.end_bound());
917
918 if !end_contained {
919 return false;
921 }
922 }
923
924 true
925 }
926
927 pub fn widen_versions<BV>(&self, versions: &[BV]) -> Self
943 where
944 BV: Borrow<V>,
945 {
946 debug_assert!(
947 versions.is_sorted_by(|l, r| l.borrow() <= r.borrow()),
948 "`widen_versions` `versions` argument incorrectly sorted"
949 );
950 let mut segments: SmallVec<[Interval<V>; 1]> = SmallVec::new();
951 for segment in &self.segments {
952 let below =
955 versions.partition_point(|v| within_bounds(v.borrow(), segment) == Ordering::Less);
956 let start = if below == 0 {
957 Unbounded
958 } else {
959 Excluded(versions[below - 1].borrow().clone())
960 };
961 let not_above = below
962 + versions[below..]
963 .partition_point(|v| within_bounds(v.borrow(), segment) != Ordering::Greater);
964 let end = if not_above == versions.len() {
965 Unbounded
966 } else {
967 Excluded(versions[not_above].borrow().clone())
968 };
969 match segments.last_mut() {
971 Some(last) if !end_before_start_with_gap(&last.1, &start) => last.1 = end,
972 _ => segments.push((start, end)),
973 }
974 }
975 Self { segments }.check_invariants()
976 }
977
978 pub fn narrow_versions<BV>(&self, versions: &[BV]) -> Self
995 where
996 BV: Borrow<V>,
997 {
998 debug_assert!(
999 versions.is_sorted_by(|l, r| l.borrow() <= r.borrow()),
1000 "`narrow_versions` `versions` argument incorrectly sorted"
1001 );
1002 let mut segments: SmallVec<[Interval<V>; 1]> = SmallVec::new();
1003 for segment in &self.segments {
1004 let first =
1006 versions.partition_point(|v| within_bounds(v.borrow(), segment) == Ordering::Less);
1007 let last = first
1008 + versions[first..]
1009 .partition_point(|v| within_bounds(v.borrow(), segment) != Ordering::Greater);
1010 if first == last {
1011 segments.push(segment.clone());
1013 } else {
1014 let start = match &segment.0 {
1015 Unbounded => Unbounded,
1016 _ => Included(versions[first].borrow().clone()),
1017 };
1018 let end = match &segment.1 {
1019 Unbounded => Unbounded,
1020 _ => Included(versions[last - 1].borrow().clone()),
1021 };
1022 segments.push((start, end));
1023 }
1024 }
1025 Self { segments }.check_invariants()
1026 }
1027
1028 pub fn simplify<'s, I, BV>(&self, versions: I) -> Self
1039 where
1040 I: Iterator<Item = BV> + 's,
1041 BV: Borrow<V> + 's,
1042 {
1043 if self.as_singleton().is_some() {
1045 return self.clone();
1046 }
1047
1048 #[cfg(debug_assertions)]
1049 let mut last: Option<BV> = None;
1050 let version_locations = versions.scan(0, move |i, v| {
1052 #[cfg(debug_assertions)]
1053 {
1054 if let Some(l) = last.as_ref() {
1055 assert!(
1056 l.borrow() <= v.borrow(),
1057 "`simplify` `versions` argument incorrectly sorted"
1058 );
1059 }
1060 }
1061 while let Some(segment) = self.segments.get(*i) {
1062 match within_bounds(v.borrow(), segment) {
1063 Ordering::Less => return Some(None),
1064 Ordering::Equal => return Some(Some(*i)),
1065 Ordering::Greater => *i += 1,
1066 }
1067 }
1068 #[cfg(debug_assertions)]
1069 {
1070 last = Some(v);
1071 }
1072 Some(None)
1073 });
1074 let mut kept_segments = group_adjacent_locations(version_locations).peekable();
1075
1076 if kept_segments.peek().is_none() {
1078 return self.clone();
1079 }
1080
1081 self.keep_segments(kept_segments)
1082 }
1083
1084 fn keep_segments(
1089 &self,
1090 kept_segments: impl Iterator<Item = (Option<usize>, Option<usize>)>,
1091 ) -> Ranges<V> {
1092 let mut segments = SmallVec::new();
1093 for (s, e) in kept_segments {
1094 segments.push((
1095 s.map_or(Unbounded, |s| self.segments[s].0.clone()),
1096 e.map_or(Unbounded, |e| self.segments[e].1.clone()),
1097 ));
1098 }
1099 Self { segments }.check_invariants()
1100 }
1101
1102 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Bound<&V>, Bound<&V>)> {
1104 self.segments
1105 .iter()
1106 .map(|(start, end)| (start.as_ref(), end.as_ref()))
1107 }
1108}
1109
1110pub struct RangesIter<V>(smallvec::IntoIter<[Interval<V>; 1]>);
1112
1113impl<V> Iterator for RangesIter<V> {
1114 type Item = Interval<V>;
1115
1116 fn next(&mut self) -> Option<Self::Item> {
1117 self.0.next()
1118 }
1119
1120 fn size_hint(&self) -> (usize, Option<usize>) {
1121 (self.0.len(), Some(self.0.len()))
1122 }
1123}
1124
1125impl<V> ExactSizeIterator for RangesIter<V> {}
1126
1127impl<V> DoubleEndedIterator for RangesIter<V> {
1128 fn next_back(&mut self) -> Option<Self::Item> {
1129 self.0.next_back()
1130 }
1131}
1132
1133impl<V> IntoIterator for Ranges<V> {
1134 type Item = (Bound<V>, Bound<V>);
1135 type IntoIter = RangesIter<V>;
1137
1138 fn into_iter(self) -> Self::IntoIter {
1139 RangesIter(self.segments.into_iter())
1140 }
1141}
1142
1143impl<V: Ord> FromIterator<(Bound<V>, Bound<V>)> for Ranges<V> {
1144 fn from_iter<T: IntoIterator<Item = (Bound<V>, Bound<V>)>>(iter: T) -> Self {
1149 let mut segments: SmallVec<[Interval<V>; 1]> = SmallVec::new();
1166
1167 for segment in iter {
1168 if !valid_segment(&segment.start_bound(), &segment.end_bound()) {
1169 continue;
1170 }
1171 let insertion_point = segments.partition_point(|elem: &Interval<V>| {
1173 cmp_bounds_start(elem.start_bound(), segment.start_bound())
1174 .unwrap()
1175 .is_lt()
1176 });
1177 let previous_overlapping = insertion_point > 0
1179 && !end_before_start_with_gap(
1180 &segments[insertion_point - 1].end_bound(),
1181 &segment.start_bound(),
1182 );
1183
1184 let next_overlapping = insertion_point < segments.len()
1187 && !end_before_start_with_gap(
1188 &segment.end_bound(),
1189 &segments[insertion_point].start_bound(),
1190 );
1191
1192 match (previous_overlapping, next_overlapping) {
1193 (true, true) => {
1194 let mut following = segments.remove(insertion_point);
1217 while insertion_point < segments.len()
1218 && !end_before_start_with_gap(
1219 &segment.end_bound(),
1220 &segments[insertion_point].start_bound(),
1221 )
1222 {
1223 following = segments.remove(insertion_point);
1224 }
1225
1226 if cmp_bounds_end(segment.end_bound(), following.end_bound())
1228 .unwrap()
1229 .is_lt()
1230 {
1231 segments[insertion_point - 1].1 = following.1;
1232 } else {
1233 segments[insertion_point - 1].1 = segment.1;
1234 }
1235 }
1236 (true, false) => {
1237 if cmp_bounds_end(
1252 segments[insertion_point - 1].end_bound(),
1253 segment.end_bound(),
1254 )
1255 .unwrap()
1256 .is_lt()
1257 {
1258 segments[insertion_point - 1].1 = segment.1;
1259 }
1260 }
1261 (false, true) => {
1262 while insertion_point + 1 < segments.len()
1286 && !end_before_start_with_gap(
1287 &segment.end_bound(),
1288 &segments[insertion_point + 1].start_bound(),
1289 )
1290 {
1291 segments.remove(insertion_point);
1294 }
1295
1296 if cmp_bounds_end(segments[insertion_point].end_bound(), segment.end_bound())
1298 .unwrap()
1299 .is_lt()
1300 {
1301 segments[insertion_point].1 = segment.1;
1302 }
1303 segments[insertion_point].0 = segment.0;
1304 }
1305 (false, false) => {
1306 segments.insert(insertion_point, segment);
1315 }
1316 }
1317 }
1318
1319 Self { segments }.check_invariants()
1320 }
1321}
1322
1323impl<V: Display + Eq> Display for Ranges<V> {
1326 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1327 if self.segments.is_empty() {
1328 write!(f, "∅")?;
1329 } else {
1330 for (idx, segment) in self.segments.iter().enumerate() {
1331 if idx > 0 {
1332 write!(f, " | ")?;
1333 }
1334 match segment {
1335 (Unbounded, Unbounded) => write!(f, "*")?,
1336 (Unbounded, Included(v)) => write!(f, "<={v}")?,
1337 (Unbounded, Excluded(v)) => write!(f, "<{v}")?,
1338 (Included(v), Unbounded) => write!(f, ">={v}")?,
1339 (Included(v), Included(b)) => {
1340 if v == b {
1341 write!(f, "=={v}")?
1342 } else {
1343 write!(f, ">={v}, <={b}")?
1344 }
1345 }
1346 (Included(v), Excluded(b)) => write!(f, ">={v}, <{b}")?,
1347 (Excluded(v), Unbounded) => write!(f, ">{v}")?,
1348 (Excluded(v), Included(b)) => write!(f, ">{v}, <={b}")?,
1349 (Excluded(v), Excluded(b)) => write!(f, ">{v}, <{b}")?,
1350 };
1351 }
1352 }
1353 Ok(())
1354 }
1355}
1356
1357#[cfg(feature = "serde")]
1360impl<'de, V: serde::Deserialize<'de>> serde::Deserialize<'de> for Ranges<V> {
1361 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1362 #[derive(serde::Deserialize)]
1367 #[serde(untagged)]
1368 enum EitherInterval<V> {
1369 B(Bound<V>, Bound<V>),
1370 D(V, Option<V>),
1371 }
1372
1373 let bounds: SmallVec<[EitherInterval<V>; 2]> =
1374 serde::Deserialize::deserialize(deserializer)?;
1375
1376 let mut segments = SmallVec::new();
1377 for i in bounds {
1378 match i {
1379 EitherInterval::B(l, r) => segments.push((l, r)),
1380 EitherInterval::D(l, Some(r)) => segments.push((Included(l), Excluded(r))),
1381 EitherInterval::D(l, None) => segments.push((Included(l), Unbounded)),
1382 }
1383 }
1384
1385 Ok(Ranges { segments })
1386 }
1387}
1388
1389#[cfg(any(feature = "proptest", test))]
1392pub fn proptest_strategy() -> impl Strategy<Value = Ranges<u32>> {
1393 (
1394 any::<bool>(),
1395 prop::collection::vec(any::<(u32, bool)>(), 0..10),
1396 )
1397 .prop_map(|(start_unbounded, deltas)| {
1398 let mut start = if start_unbounded {
1399 Some(Unbounded)
1400 } else {
1401 None
1402 };
1403 let mut largest: u32 = 0;
1404 let mut last_bound_was_inclusive = false;
1405 let mut segments = SmallVec::new();
1406 for (delta, inclusive) in deltas {
1407 largest = match largest.checked_add(delta) {
1409 Some(s) => s,
1410 None => {
1411 continue;
1413 }
1414 };
1415
1416 let current_bound = if inclusive {
1417 Included(largest)
1418 } else {
1419 Excluded(largest)
1420 };
1421
1422 if let Some(start_bound) = start.take() {
1425 if delta == 0 && !(matches!(start_bound, Included(_)) && inclusive) {
1428 start = Some(start_bound);
1429 continue;
1430 }
1431 last_bound_was_inclusive = inclusive;
1432 segments.push((start_bound, current_bound));
1433 } else {
1434 if delta == 0 && (last_bound_was_inclusive || inclusive) {
1438 continue;
1439 }
1440 start = Some(current_bound);
1441 }
1442 }
1443
1444 if let Some(start_bound) = start {
1447 segments.push((start_bound, Unbounded));
1448 }
1449
1450 Ranges { segments }.check_invariants()
1451 })
1452}
1453
1454#[cfg(test)]
1455pub mod tests {
1456 use proptest::prelude::*;
1457
1458 use super::*;
1459
1460 fn version_strat() -> impl Strategy<Value = u32> {
1461 any::<u32>()
1462 }
1463
1464 proptest! {
1465
1466 #[cfg(feature = "serde")]
1469 #[test]
1470 fn serde_round_trip(range in proptest_strategy()) {
1471 let s = ron::ser::to_string(&range).unwrap();
1472 let r = ron::de::from_str(&s).unwrap();
1473 assert_eq!(range, r);
1474 }
1475
1476 #[test]
1479 fn negate_is_different(range in proptest_strategy()) {
1480 assert_ne!(range.complement(), range);
1481 }
1482
1483 #[test]
1484 fn double_negate_is_identity(range in proptest_strategy()) {
1485 assert_eq!(range.complement().complement(), range);
1486 }
1487
1488 #[test]
1489 fn negate_contains_opposite(range in proptest_strategy(), version in version_strat()) {
1490 assert_ne!(range.contains(&version), range.complement().contains(&version));
1491 }
1492
1493 #[test]
1496 fn difference_is_intersection_with_complement(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1497 assert_eq!(r1.difference(&r2), r1.intersection(&r2.complement()));
1498 }
1499
1500 #[test]
1501 fn difference_contains(r1 in proptest_strategy(), r2 in proptest_strategy(), version in version_strat()) {
1502 assert_eq!(
1503 r1.difference(&r2).contains(&version),
1504 r1.contains(&version) && !r2.contains(&version)
1505 );
1506 }
1507
1508 #[test]
1511 fn intersection_is_symmetric(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1512 assert_eq!(r1.intersection(&r2), r2.intersection(&r1));
1513 }
1514
1515 #[test]
1516 fn intersection_with_any_is_identity(range in proptest_strategy()) {
1517 assert_eq!(Ranges::full().intersection(&range), range);
1518 }
1519
1520 #[test]
1521 fn intersection_with_none_is_none(range in proptest_strategy()) {
1522 assert_eq!(Ranges::empty().intersection(&range), Ranges::empty());
1523 }
1524
1525 #[test]
1526 fn intersection_is_idempotent(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1527 assert_eq!(r1.intersection(&r2).intersection(&r2), r1.intersection(&r2));
1528 }
1529
1530 #[test]
1531 fn intersection_is_associative(r1 in proptest_strategy(), r2 in proptest_strategy(), r3 in proptest_strategy()) {
1532 assert_eq!(r1.intersection(&r2).intersection(&r3), r1.intersection(&r2.intersection(&r3)));
1533 }
1534
1535 #[test]
1536 fn intesection_of_complements_is_none(range in proptest_strategy()) {
1537 assert_eq!(range.complement().intersection(&range), Ranges::empty());
1538 }
1539
1540 #[test]
1541 fn intesection_contains_both(r1 in proptest_strategy(), r2 in proptest_strategy(), version in version_strat()) {
1542 assert_eq!(r1.intersection(&r2).contains(&version), r1.contains(&version) && r2.contains(&version));
1543 }
1544
1545 #[test]
1548 fn union_of_complements_is_any(range in proptest_strategy()) {
1549 assert_eq!(range.complement().union(&range), Ranges::full());
1550 }
1551
1552 #[test]
1553 fn union_contains_either(r1 in proptest_strategy(), r2 in proptest_strategy(), version in version_strat()) {
1554 assert_eq!(r1.union(&r2).contains(&version), r1.contains(&version) || r2.contains(&version));
1555 }
1556
1557 #[test]
1558 fn is_disjoint_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1559 let disjoint_def = r1.intersection(&r2) == Ranges::empty();
1560 assert_eq!(r1.is_disjoint(&r2), disjoint_def);
1561 }
1562
1563 #[test]
1564 fn subset_of_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1565 let disjoint_def = r1.intersection(&r2) == r1;
1566 assert_eq!(r1.subset_of(&r2), disjoint_def);
1567 }
1568
1569 #[test]
1570 fn relation_through_subset_and_disjoint(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1571 let relation_def = if r1.subset_of(&r2) {
1572 SetRelation::Subset
1573 } else if r1.is_disjoint(&r2) {
1574 SetRelation::Disjoint
1575 } else {
1576 SetRelation::Overlapping
1577 };
1578 assert_eq!(r1.relation(&r2), relation_def);
1579 }
1580
1581 #[test]
1582 fn union_through_intersection(r1 in proptest_strategy(), r2 in proptest_strategy()) {
1583 let union_def = r1
1584 .complement()
1585 .intersection(&r2.complement())
1586 .complement()
1587 .check_invariants();
1588 assert_eq!(r1.union(&r2), union_def);
1589 }
1590
1591 #[test]
1594 fn always_contains_exact(version in version_strat()) {
1595 assert!(Ranges::<u32>::singleton(version).contains(&version));
1596 }
1597
1598 #[test]
1599 fn contains_negation(range in proptest_strategy(), version in version_strat()) {
1600 assert_ne!(range.contains(&version), range.complement().contains(&version));
1601 }
1602
1603 #[test]
1604 fn contains_intersection(range in proptest_strategy(), version in version_strat()) {
1605 assert_eq!(range.contains(&version), range.intersection(&Ranges::singleton(version)) != Ranges::empty());
1606 }
1607
1608 #[test]
1609 fn contains_bounding_range(range in proptest_strategy(), version in version_strat()) {
1610 if range.contains(&version) {
1611 assert!(range.bounding_range().map(|b| b.contains(&version)).unwrap_or(false));
1612 }
1613 }
1614
1615 #[test]
1616 fn from_range_bounds(range in any::<(Bound<u32>, Bound<u32>)>(), version in version_strat()) {
1617 let rv: Ranges<_> = Ranges::<u32>::from_range_bounds(range);
1618 assert_eq!(range.contains(&version), rv.contains(&version));
1619 }
1620
1621 #[test]
1622 fn from_range_bounds_round_trip(range in any::<(Bound<u32>, Bound<u32>)>()) {
1623 let rv: Ranges<u32> = Ranges::from_range_bounds(range);
1624 let rv2: Ranges<u32> = rv.bounding_range().map(Ranges::from_range_bounds::<_, u32>).unwrap_or_else(Ranges::empty);
1625 assert_eq!(rv, rv2);
1626 }
1627
1628 #[test]
1629 fn contains(range in proptest_strategy(), versions in proptest::collection::vec(version_strat(), ..30)) {
1630 for v in versions {
1631 assert_eq!(range.contains(&v), range.segments.iter().any(|s| RangeBounds::contains(s, &v)));
1632 }
1633 }
1634
1635 #[test]
1636 fn contains_many(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1637 versions.sort();
1638 assert_eq!(versions.len(), range.contains_many(versions.iter()).count());
1639 for (a, b) in versions.iter().zip(range.contains_many(versions.iter())) {
1640 assert_eq!(range.contains(a), b);
1641 }
1642 }
1643
1644 #[test]
1645 fn simplify(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1646 versions.sort();
1647 let simp = range.simplify(versions.iter());
1648
1649 for v in versions {
1650 assert_eq!(range.contains(&v), simp.contains(&v));
1651 }
1652 assert!(simp.segments.len() <= range.segments.len())
1653 }
1654
1655 #[test]
1656 fn widen_versions(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1657 versions.sort();
1658 let widened = range.widen_versions(&versions);
1659
1660 assert!(range.subset_of(&widened));
1662 for v in &versions {
1663 assert_eq!(range.contains(v), widened.contains(v));
1664 }
1665 assert_eq!(widened.widen_versions(&versions), widened);
1667 }
1668
1669 #[test]
1670 fn narrow_versions(range in proptest_strategy(), mut versions in proptest::collection::vec(version_strat(), ..30)) {
1671 versions.sort();
1672 let narrowed = range.narrow_versions(&versions);
1673
1674 assert!(narrowed.subset_of(&range));
1676 for v in &versions {
1677 assert_eq!(range.contains(v), narrowed.contains(v));
1678 }
1679 assert_eq!(narrowed.narrow_versions(&versions), narrowed);
1681 let round_trip = range.widen_versions(&versions).narrow_versions(&versions);
1683 for v in &versions {
1684 assert_eq!(range.contains(v), round_trip.contains(v));
1685 }
1686 }
1687
1688 #[test]
1689 fn from_iter_valid(segments in proptest::collection::vec(any::<(Bound<u32>, Bound<u32>)>(), ..30)) {
1690 let mut expected = Ranges::empty();
1691 for segment in &segments {
1692 expected = expected.union(&Ranges::from_range_bounds(*segment));
1693 }
1694 let actual = Ranges::from_iter(segments.clone());
1695 assert_eq!(expected, actual, "{segments:?}");
1696 }
1697 }
1698
1699 #[test]
1700 fn difference_ties_and_singletons() {
1701 fn check(left: Ranges<u32>, right: Ranges<u32>, expected: Ranges<u32>) {
1702 assert_eq!(left.difference(&right), expected, "{left} minus {right}");
1703 assert_eq!(
1704 left.difference(&right),
1705 left.intersection(&right.complement()),
1706 "{left} minus {right}"
1707 );
1708 }
1709
1710 check(
1712 Ranges::from_range_bounds(1u32..=5),
1713 Ranges::from_range_bounds(5u32..=9),
1714 Ranges::from_range_bounds(1u32..5),
1715 );
1716 check(
1717 Ranges::from_range_bounds(1u32..5),
1718 Ranges::from_range_bounds(5u32..=9),
1719 Ranges::from_range_bounds(1u32..5),
1720 );
1721 check(
1722 Ranges::from_range_bounds(1u32..=5),
1723 Ranges::from_range_bounds((Excluded(5u32), Included(9u32))),
1724 Ranges::from_range_bounds(1u32..=5),
1725 );
1726 check(
1727 Ranges::from_range_bounds(1u32..5),
1728 Ranges::from_range_bounds((Excluded(5u32), Excluded(9u32))),
1729 Ranges::from_range_bounds(1u32..5),
1730 );
1731
1732 check(
1734 Ranges::singleton(3u32),
1735 Ranges::from_range_bounds(1u32..=3),
1736 Ranges::empty(),
1737 );
1738 check(
1739 Ranges::from_range_bounds(1u32..=5),
1740 Ranges::singleton(3u32),
1741 Ranges::from_range_bounds(1u32..3)
1742 .union(&Ranges::from_range_bounds((Excluded(3u32), Included(5u32)))),
1743 );
1744
1745 check(
1747 Ranges::from_range_bounds(0u32..=10),
1748 Ranges::from_range_bounds((Excluded(2u32), Excluded(4u32)))
1749 .union(&Ranges::from_range_bounds((Excluded(4u32), Excluded(6u32)))),
1750 Ranges::from_range_bounds(0u32..=2)
1751 .union(&Ranges::singleton(4u32))
1752 .union(&Ranges::from_range_bounds(6u32..=10)),
1753 );
1754
1755 check(
1757 Ranges::from_range_bounds(0u32..=1)
1758 .union(&Ranges::from_range_bounds(5u32..=6))
1759 .union(&Ranges::from_range_bounds(8u32..=9)),
1760 Ranges::higher_than(5u32),
1761 Ranges::from_range_bounds(0u32..=1),
1762 );
1763
1764 check(Ranges::full(), Ranges::empty(), Ranges::full());
1766 check(Ranges::empty(), Ranges::full(), Ranges::empty());
1767 check(Ranges::full(), Ranges::full(), Ranges::empty());
1768 }
1769
1770 #[test]
1771 fn contains_many_can_take_owned() {
1772 let range: Ranges<u8> = Ranges::singleton(1);
1773 let versions = vec![1, 2, 3];
1774 assert_eq!(
1776 range.contains_many(versions.iter()).count(),
1777 range
1778 .contains_many(versions.iter().map(std::borrow::Cow::Borrowed))
1779 .count()
1780 );
1781 assert_eq!(
1783 range.contains_many(versions.iter()).count(),
1784 range.contains_many(versions.into_iter()).count()
1785 );
1786 }
1787
1788 #[test]
1789 fn contains_can_take_owned() {
1790 let range: Ranges<Box<u8>> = Ranges::singleton(1);
1791 let version = 1;
1792
1793 assert_eq!(range.contains(&Box::new(version)), range.contains(&version));
1794 let range: Ranges<String> = Ranges::singleton(1.to_string());
1795 let version = 1.to_string();
1796 assert_eq!(range.contains(&version), range.contains("1"));
1797 }
1798
1799 #[test]
1800 fn widen_versions_extends_to_neighboring_versions() {
1801 let versions = [1u32, 2, 3, 5, 9];
1802 assert_eq!(
1804 Ranges::singleton(3u32).widen_versions(&versions),
1805 Ranges::from_range_bounds((Excluded(2u32), Excluded(5u32)))
1806 );
1807 assert_eq!(
1809 Ranges::singleton(9u32).widen_versions(&versions),
1810 Ranges::strictly_higher_than(5u32)
1811 );
1812 let range: Ranges<u32> = Ranges::singleton(2u32).union(&Ranges::singleton(3u32));
1814 assert_eq!(
1815 range.widen_versions(&versions),
1816 Ranges::from_range_bounds((Excluded(1u32), Excluded(5u32)))
1817 );
1818 let range: Ranges<u32> = Ranges::singleton(1u32).union(&Ranges::singleton(3u32));
1820 assert_eq!(
1821 range.widen_versions(&versions),
1822 Ranges::strictly_lower_than(2u32)
1823 .union(&Ranges::from_range_bounds((Excluded(2u32), Excluded(5u32))))
1824 );
1825 }
1826
1827 #[test]
1828 fn narrow_versions_shrinks_to_contained_versions() {
1829 let versions = [1u32, 2, 3, 5, 9];
1830 assert_eq!(
1832 Ranges::from_range_bounds((Excluded(2u32), Excluded(5u32))).narrow_versions(&versions),
1833 Ranges::singleton(3u32)
1834 );
1835 assert_eq!(
1837 Ranges::strictly_higher_than(2u32).narrow_versions(&versions),
1838 Ranges::higher_than(3u32)
1839 );
1840 assert_eq!(
1841 Ranges::<u32>::full().narrow_versions(&versions),
1842 Ranges::full()
1843 );
1844 let range = Ranges::from_range_bounds((Excluded(5u32), Excluded(9u32)));
1846 assert_eq!(range.narrow_versions(&versions), range);
1847 }
1848
1849 #[test]
1850 fn simplify_can_take_owned() {
1851 let range: Ranges<u8> = Ranges::singleton(1);
1852 let versions = vec![1, 2, 3];
1853 assert_eq!(
1855 range.simplify(versions.iter()),
1856 range.simplify(versions.iter().map(std::borrow::Cow::Borrowed))
1857 );
1858 assert_eq!(
1860 range.simplify(versions.iter()),
1861 range.simplify(versions.into_iter())
1862 );
1863 }
1864
1865 #[test]
1866 fn version_ord() {
1867 let versions: &[Ranges<u32>] = &[
1868 Ranges::strictly_lower_than(1u32),
1869 Ranges::lower_than(1u32),
1870 Ranges::singleton(1u32),
1871 Ranges::between(1u32, 3u32),
1872 Ranges::higher_than(1u32),
1873 Ranges::strictly_higher_than(1u32),
1874 Ranges::singleton(2u32),
1875 Ranges::singleton(2u32).union(&Ranges::singleton(3u32)),
1876 Ranges::singleton(2u32)
1877 .union(&Ranges::singleton(3u32))
1878 .union(&Ranges::singleton(4u32)),
1879 Ranges::singleton(2u32).union(&Ranges::singleton(4u32)),
1880 Ranges::singleton(3u32),
1881 ];
1882
1883 let mut versions_sorted = versions.to_vec();
1884 versions_sorted.sort();
1885 assert_eq!(versions_sorted, versions);
1886
1887 let mut version_reverse_sorted = versions.to_vec();
1889 version_reverse_sorted.reverse();
1890 version_reverse_sorted.sort();
1891 assert_eq!(version_reverse_sorted, versions);
1892 }
1893}