From eea1418c9010aec9f5923d3fd4e073625c4dcd09 Mon Sep 17 00:00:00 2001 From: Eduardo Trujillo <ed@chromabits.com> Date: Sun, 16 Mar 2025 21:32:11 +0000 Subject: [PATCH] feat(rangeset): Add size methods and conversion from Vec --- src/rangeset.rs | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/rangeset.rs b/src/rangeset.rs index af804ff..49de772 100644 --- a/src/rangeset.rs +++ b/src/rangeset.rs @@ -1,9 +1,9 @@ -use std::collections::BTreeMap; +use std::{collections::BTreeMap, convert::TryFrom}; use thiserror::Error; /// Error type for [`RangeSet`] -#[derive(Clone, Error, Debug, PartialEq)] +#[derive(Clone, Error, Debug, PartialEq, Eq)] pub enum RangeSetError { /// Used when an invalid range is provided (e.g. End is before start). #[error("Invalid range provided")] @@ -14,7 +14,7 @@ pub enum RangeSetError { } /// A set of non-overlapping ranges. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RangeSet<RK: Ord + Copy> { ranges: BTreeMap<RK, RK>, // Maps start -> end } @@ -73,6 +73,16 @@ impl<RK: Ord + Copy> RangeSet<RK> { pub fn iter(&self) -> impl Iterator<Item = (RK, RK)> + '_ { self.ranges.iter().map(|(&s, &e)| (s, e)) } + + /// Returns the number of elements in the set. + pub fn len(&self) -> usize { + self.ranges.len() + } + + /// Returns whether this set is empty. + pub fn is_empty(&self) -> bool { + self.ranges.is_empty() + } } impl<RK: Copy + Ord> Default for RangeSet<RK> { @@ -81,8 +91,24 @@ impl<RK: Copy + Ord> Default for RangeSet<RK> { } } +impl<RK: Copy + Ord> TryFrom<Vec<(RK, RK)>> for RangeSet<RK> { + type Error = RangeSetError; + + fn try_from(value: Vec<(RK, RK)>) -> Result<Self, Self::Error> { + let mut range_set = RangeSet::new(); + + for range in value { + range_set.insert(range.0, range.1)?; + } + + Ok(range_set) + } +} + #[cfg(test)] mod tests { + use std::convert::TryInto; + use crate::rangeset::{RangeSet, RangeSetError}; #[test] @@ -107,4 +133,16 @@ mod tests { assert!(rs.remove(30, 40)); assert!(!rs.remove(30, 40)); } + + #[test] + fn test_try_from_vec() { + let range_set: RangeSet<u32> = vec![(0, 10), (100, 150)].try_into().unwrap(); + + assert_eq!(range_set.len(), 2); + + let invalid_result: Result<RangeSet<u32>, RangeSetError> = + vec![(10, 30), (11, 23)].try_into(); + + assert_eq!(invalid_result, Err(RangeSetError::RangeOverlap)) + } } -- GitLab