Skip to content

Commit f64c499

Browse files
committed
Avoid loss of data in Range.simplify (#13)
* Add `Range.is_singleton` * Do not simplify singletons * Do not return null sets * Tweak docs
1 parent bba6006 commit f64c499

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

src/range.rs

+26-8
Original file line numberDiff line numberDiff line change
@@ -419,21 +419,26 @@ impl<V: Ord + Clone> Range<V> {
419419
Self { segments: output }.check_invariants()
420420
}
421421

422-
/// Returns a simpler Range that contains the same versions
422+
/// Returns a simpler Range that contains the same versions.
423423
///
424-
/// For every one of the Versions provided in versions the existing range and
425-
/// the simplified range will agree on whether it is contained.
424+
/// For every one of the Versions provided in versions the existing range and the simplified range will agree on whether it is contained.
426425
/// The simplified version may include or exclude versions that are not in versions as the implementation wishes.
427-
/// For example:
428-
/// - If all the versions are contained in the original than the range will be simplified to `full`.
429-
/// - If none of the versions are contained in the original than the range will be simplified to `empty`.
430426
///
431-
/// If versions are not sorted the correctness of this function is not guaranteed.
427+
/// If none of the versions are contained in the original than the range will be returned unmodified.
428+
/// If the range includes a single version, it will be returned unmodified.
429+
/// If all the versions are contained in the original than the range will be simplified to `full`.
430+
///
431+
/// If the given versions are not sorted the correctness of this function is not guaranteed.
432432
pub fn simplify<'v, I>(&self, versions: I) -> Self
433433
where
434434
I: Iterator<Item = &'v V> + 'v,
435435
V: 'v,
436436
{
437+
// Do not simplify singletons
438+
if self.is_singleton() {
439+
return self.clone();
440+
}
441+
437442
// Return the segment index in the range for each version in the range, None otherwise
438443
let version_locations = versions.scan(0, move |i, v| {
439444
while let Some(segment) = self.segments.get(*i) {
@@ -445,7 +450,13 @@ impl<V: Ord + Clone> Range<V> {
445450
}
446451
Some(None)
447452
});
448-
let kept_segments = group_adjacent_locations(version_locations);
453+
let mut kept_segments = group_adjacent_locations(version_locations).peekable();
454+
455+
// Do not return null sets
456+
if kept_segments.peek().is_none() {
457+
return self.clone();
458+
}
459+
449460
self.keep_segments(kept_segments)
450461
}
451462

@@ -466,6 +477,13 @@ impl<V: Ord + Clone> Range<V> {
466477
}
467478
Self { segments }.check_invariants()
468479
}
480+
481+
pub fn is_singleton(&self) -> bool {
482+
match self.segments.as_slice() {
483+
[(Included(v1), Included(v2))] => v1 == v2,
484+
_ => false,
485+
}
486+
}
469487
}
470488

471489
impl<T: Debug + Display + Clone + Eq + Ord> VersionSet for Range<T> {

0 commit comments

Comments
 (0)