Skip to content

Commit 3b8c3b6

Browse files
committed
feat: from and as RangeBounds
1 parent 27c1da7 commit 3b8c3b6

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/range.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
use std::cmp::Ordering;
1818
use std::fmt;
19+
use std::ops::{Bound, RangeBounds};
1920

2021
use crate::internal::small_vec::SmallVec;
2122
use crate::version::Version;
@@ -85,6 +86,31 @@ impl<V: Version> Range<V> {
8586
Self::none()
8687
}
8788
}
89+
90+
/// Construct a simple range from anything that impls `RangeBounds` like `v1..v2`
91+
pub fn from_range_bounds<R, IV>(bounds: R) -> Self
92+
where
93+
R: RangeBounds<IV>,
94+
for<'a> &'a IV: Into<V>,
95+
{
96+
let start = match bounds.start_bound() {
97+
Bound::Included(s) => s.into(),
98+
Bound::Excluded(s) => s.into().bump(),
99+
Bound::Unbounded => V::lowest(),
100+
};
101+
let end = match bounds.end_bound() {
102+
Bound::Included(e) => Some(e.into().bump()),
103+
Bound::Excluded(e) => Some(e.into()),
104+
Bound::Unbounded => None,
105+
};
106+
if end.is_some() && end.as_ref() <= Some(&start) {
107+
Self::none()
108+
} else {
109+
Self {
110+
segments: SmallVec::one((start, end)),
111+
}
112+
}
113+
}
88114
}
89115

90116
// Set operations.
@@ -260,6 +286,23 @@ impl<V: Version> Range<V> {
260286
pub fn lowest_version(&self) -> Option<V> {
261287
self.segments.first().map(|(start, _)| start).cloned()
262288
}
289+
290+
/// Conver to somthing that can be used with BTreeMap::range
291+
/// All versions contained in self, will be in the output,
292+
/// but there may be versions in the output that are not contained in self.
293+
/// returns None if the range is empty.
294+
pub fn bounding_range(&self) -> Option<(Bound<&V>, Bound<&V>)> {
295+
self.segments.first().map(|(start, _)| {
296+
let end = {
297+
self.segments
298+
.last()
299+
.and_then(|(_, l)| l.as_ref())
300+
.map(Bound::Excluded)
301+
.unwrap_or(Bound::Unbounded)
302+
};
303+
(Bound::Included(start), end)
304+
})
305+
}
263306
}
264307

265308
// REPORT ######################################################################
@@ -405,5 +448,25 @@ pub mod tests {
405448
fn contains_intersection(range in strategy(), version in version_strat()) {
406449
assert_eq!(range.contains(&version), range.intersection(&Range::exact(version)) != Range::none());
407450
}
451+
452+
#[test]
453+
fn contains_bounding_range(range in strategy(), version in version_strat()) {
454+
if range.contains(&version) {
455+
assert!(range.bounding_range().map(|b| b.contains(&version)).unwrap_or(false));
456+
}
457+
}
458+
459+
#[test]
460+
fn from_range_bounds(range in any::<(Bound<u32>, Bound<u32>)>(), version in version_strat()) {
461+
let rv: Range<NumberVersion> = Range::from_range_bounds(range);
462+
assert_eq!(range.contains(&version.0), rv.contains(&version));
463+
}
464+
465+
#[test]
466+
fn from_range_bounds_round_trip(range in any::<(Bound<u32>, Bound<u32>)>()) {
467+
let rv: Range<NumberVersion> = Range::from_range_bounds(range);
468+
let rv2: Range<NumberVersion> = rv.bounding_range().map(Range::from_range_bounds::<_, NumberVersion>).unwrap_or_else(Range::none);
469+
assert_eq!(rv, rv2);
470+
}
408471
}
409472
}

src/version.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ impl From<(u32, u32, u32)> for SemanticVersion {
8080
}
8181
}
8282

83+
// Convert a &(major, minor, patch) into a version.
84+
impl From<&(u32, u32, u32)> for SemanticVersion {
85+
fn from(tuple: &(u32, u32, u32)) -> Self {
86+
let (major, minor, patch) = *tuple;
87+
Self::new(major, minor, patch)
88+
}
89+
}
90+
91+
// Convert an &version into a version.
92+
impl From<&SemanticVersion> for SemanticVersion {
93+
fn from(v: &SemanticVersion) -> Self {
94+
*v
95+
}
96+
}
97+
8398
// Convert a version into a tuple (major, minor, patch).
8499
impl From<SemanticVersion> for (u32, u32, u32) {
85100
fn from(v: SemanticVersion) -> Self {
@@ -237,6 +252,20 @@ impl From<u32> for NumberVersion {
237252
}
238253
}
239254

255+
// Convert an &usize into a version.
256+
impl From<&u32> for NumberVersion {
257+
fn from(v: &u32) -> Self {
258+
Self(*v)
259+
}
260+
}
261+
262+
// Convert an &version into a version.
263+
impl From<&NumberVersion> for NumberVersion {
264+
fn from(v: &NumberVersion) -> Self {
265+
*v
266+
}
267+
}
268+
240269
// Convert a version into an usize.
241270
impl From<NumberVersion> for u32 {
242271
fn from(version: NumberVersion) -> Self {

0 commit comments

Comments
 (0)