Skip to content

Commit

Permalink
refactor: replace Identity trait with Step (#19)
Browse files Browse the repository at this point in the history
* refactor: replace Identity trait with Step

* rename macro

* Apply suggestions from code review

Co-authored-by: dan <[email protected]>

---------

Co-authored-by: dan <[email protected]>
  • Loading branch information
sinui0 and themighty1 authored Feb 5, 2024
1 parent 371b954 commit 50b9102
Showing 1 changed file with 23 additions and 12 deletions.
35 changes: 23 additions & 12 deletions utils/src/range/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,14 @@ impl<T: Copy + Ord> RangeSet<T> {
}
}

impl<T: Copy + Ord + Identity<T> + Sub<Output = T>> RangeSet<T> {
impl<T: Copy + Ord + Step + Sub<Output = T>> RangeSet<T> {
/// Returns the maximum value in the set, or `None` if the set is empty.
pub fn max(&self) -> Option<T> {
// This should never underflow because of the invariant that a set
// never contains empty ranges.
self.ranges.last().map(|range| range.end - T::IDENTITY)
self.ranges
.last()
.map(|range| Step::backward(range.end, 1).expect("set is not empty"))
}

/// Splits the set into two at the provided value.
Expand Down Expand Up @@ -416,25 +418,34 @@ pub trait RangeUnion<Rhs> {
fn union(&self, other: &Rhs) -> Self::Output;
}

/// A type with an identity value.
// std::iter::Step is nightly-only, and we want users to be able to use `RangeSet::max` for custom
// types, so exposing this trait is a lesser evil.
pub trait Identity<T> {
/// The identity value for the type `T`.
const IDENTITY: T;
/// A type which successor and predecessor operations can be performed on.
///
/// Similar to `std::iter::Step`, but not nightly-only.
pub trait Step: Sized {
/// Steps forwards by `count` elements.
fn forward(start: Self, count: usize) -> Option<Self>;

/// Steps backwards by `count` elements.
fn backward(start: Self, count: usize) -> Option<Self>;
}

macro_rules! impl_identity {
macro_rules! impl_step {
($($ty:ty),+) => {
$(
impl Identity<$ty> for $ty {
const IDENTITY: $ty = 1;
impl Step for $ty {
fn forward(start: Self, count: usize) -> Option<Self> {
start.checked_add(count as Self)
}

fn backward(start: Self, count: usize) -> Option<Self> {
start.checked_sub(count as Self)
}
}
)*
};
}

impl_identity!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl_step!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

impl<T: Copy + Ord> RangeDisjoint<Range<T>> for Range<T> {
fn is_disjoint(&self, other: &Range<T>) -> bool {
Expand Down

0 comments on commit 50b9102

Please sign in to comment.