Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(corelib): add RangeBounds and Bound #7006

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion corelib/src/ops.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod range;
// `RangeOp` is used internally by the compiler.
#[allow(unused_imports)]
use range::RangeOp;
pub use range::{Range, RangeIterator, RangeTrait};
pub use range::{Bound, Range, RangeBounds, RangeIterator, RangeTrait};

mod function;
pub use function::{Fn, FnOnce};
96 changes: 96 additions & 0 deletions corelib/src/ops/range.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,99 @@ impl SierraRangeIntoIterator<
}
}
}

/// An endpoint of a range of keys.
///
/// # Examples
///
/// `Bound`s are range endpoints:
///
/// ```
/// use core::ops::{Bounds, RangeBounds};
///
/// assert_eq!((1..12).start_bound(), Bound::Included(@1));
/// assert_eq!((1..12).end_bound(), Bound::Excluded(@12));
/// ```
#[derive(Clone, Drop, Debug, PartialEq)]
pub enum Bound<T> {
/// An inclusive bound.
Included: T,
/// An exclusive bound.
Excluded: T,
/// An infinite endpoint. Indicates that there is no bound in this direction.
Unbounded,
}


/// `RangeBounds` is implemented by Cairo's built-in range types, produced
/// by range syntax like `a..b`
pub trait RangeBounds<T> {
type Item;
//BUG: adding a trait bound at this level crashes the compiler
// impl ItemPartialOrd: PartialOrd<@Self::Item>;

/// Start index bound.
///
/// Returns the start value as a `Bound`.
///
/// # Examples
///
/// ```
/// use core::ops::{Bounds, RangeBounds};
///
/// assert!( (3_u8..5).start_bound() == Bound::Included(@3));
/// ```
fn start_bound(self: @T) -> Bound<@Self::Item>;

/// End index bound.
///
/// Returns the end value as a `Bound`.
///
/// # Examples
///
/// ```
/// assert!( (3_u8..5).end_bound() == Bound::Excluded(@5));
/// ```
fn end_bound(self: @T) -> Bound<@Self::Item>;

/// Returns `true` if `item` is contained in the range.
///
/// # Examples
///
/// ```
/// use core::ops::RangeBounds;
///
/// assert!( (3_u8..5).contains(@4));
/// assert!(!(3_u8..5).contains(@2));
/// ```
fn contains(self: @T, item: @Self::Item) -> bool;
}

impl RangeBoundsRangeImpl<T, +Destruct<T>, +PartialOrd<@T>> of RangeBounds<Range<T>> {
type Item = T;

#[inline]
fn start_bound(self: @Range<T>) -> Bound<@T> {
Bound::Included(self.start)
}

#[inline]
fn end_bound(self: @Range<T>) -> Bound<@T> {
Bound::Excluded(self.end)
}

//BUG: adding this as a default trait impl crashes the compiler
#[inline]
fn contains(self: @Range<T>, item: @T) -> bool {
(match Self::start_bound(self) {
Bound::Included(start) => start <= item,
Bound::Excluded(start) => start < item,
Bound::Unbounded => true,
})
&& (match Self::end_bound(self) {
Bound::Included(end) => item <= end,
Bound::Excluded(end) => item < end,
Bound::Unbounded => true,
})
}
}
12 changes: 11 additions & 1 deletion corelib/src/test/range_test.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::ops::RangeTrait;
use core::ops::{Bound, RangeBounds, RangeTrait};

#[test]
fn test_range_is_empty() {
Expand All @@ -11,3 +11,13 @@ fn test_range_is_empty() {
fn test_range_format() {
assert!(format!("{:?}", 1..5) == "1..5");
}

#[test]
fn test_range_bounds() {
assert!((3_u8..5).start_bound() == Bound::Included(@3));
assert!((3_u8..5).end_bound() == Bound::Excluded(@5));

assert!(!(3_u8..5).contains(@2));
assert!((3_u8..5).contains(@4));
assert!(!(3_u8..5).contains(@5));
}