Skip to content

Commit

Permalink
Merge branch 'main' into feat/iter_adapter_zip
Browse files Browse the repository at this point in the history
  • Loading branch information
julio4 authored Jan 15, 2025
2 parents 3e881f4 + 9a3f075 commit 3fd2bda
Show file tree
Hide file tree
Showing 18 changed files with 369 additions and 180 deletions.
77 changes: 35 additions & 42 deletions corelib/src/internal/bounded_int.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -113,56 +113,49 @@ extern fn bounded_int_constrain<T, const BOUNDARY: felt252, impl H: ConstrainHel
value: T,
) -> Result<H::LowT, H::HighT> implicits(RangeCheck) nopanic;

/// A helper trait for trimming a `BoundedInt` instance.
pub trait TrimHelper<T, const TRIMMED_VALUE: felt252> {
/// A helper trait for trimming a `BoundedInt` instance min value.
pub trait TrimMinHelper<T> {
type Target;
}
/// A helper trait for trimming a `BoundedInt` instance max value.
pub trait TrimMaxHelper<T> {
type Target;
}
mod trim_impl {
pub impl Impl<
T, const TRIMMED_VALUE: felt252, const MIN: felt252, const MAX: felt252,
> of super::TrimHelper<T, TRIMMED_VALUE> {
pub impl Min<T, const MIN: felt252, const MAX: felt252> of super::TrimMinHelper<T> {
type Target = super::BoundedInt<MIN, MAX>;
}
pub impl Max<T, const MIN: felt252, const MAX: felt252> of super::TrimMaxHelper<T> {
type Target = super::BoundedInt<MIN, MAX>;
}
}
impl U8TrimBelow = trim_impl::Impl<u8, 0, 1, 0xff>;
impl U8TrimAbove = trim_impl::Impl<u8, 0xff, 0, 0xfe>;
impl I8TrimBelow = trim_impl::Impl<i8, -0x80, -0x7f, 0x7f>;
impl I8TrimAbove = trim_impl::Impl<i8, 0x7f, -0x80, 0x7e>;
impl U16TrimBelow = trim_impl::Impl<u16, 0, 1, 0xffff>;
impl U16TrimAbove = trim_impl::Impl<u16, 0xffff, 0, 0xfffe>;
impl I16TrimBelow = trim_impl::Impl<i16, -0x8000, -0x7fff, 0x7fff>;
impl I16TrimAbove = trim_impl::Impl<i16, 0x7fff, -0x8000, 0x7ffe>;
impl U32TrimBelow = trim_impl::Impl<u32, 0, 1, 0xffffffff>;
impl U32TrimAbove = trim_impl::Impl<u32, 0xffffffff, 0, 0xfffffffe>;
impl I32TrimBelow = trim_impl::Impl<i32, -0x80000000, -0x7fffffff, 0x7fffffff>;
impl I32TrimAbove = trim_impl::Impl<i32, 0x7fffffff, -0x80000000, 0x7ffffffe>;
impl U64TrimBelow = trim_impl::Impl<u64, 0, 1, 0xffffffffffffffff>;
impl U64TrimAbove = trim_impl::Impl<u64, 0xffffffffffffffff, 0, 0xfffffffffffffffe>;
impl I64TrimBelow =
trim_impl::Impl<i64, -0x8000000000000000, -0x7fffffffffffffff, 0x7fffffffffffffff>;
impl I64TrimAbove =
trim_impl::Impl<i64, 0x7fffffffffffffff, -0x8000000000000000, 0x7ffffffffffffffe>;
impl U128TrimBelow = trim_impl::Impl<u128, 0, 1, 0xffffffffffffffffffffffffffffffff>;
impl U128TrimAbove =
trim_impl::Impl<
u128, 0xffffffffffffffffffffffffffffffff, 0, 0xfffffffffffffffffffffffffffffffe,
>;
impl U8TrimBelow = trim_impl::Min<u8, 1, 0xff>;
impl U8TrimAbove = trim_impl::Max<u8, 0, 0xfe>;
impl I8TrimBelow = trim_impl::Min<i8, -0x7f, 0x7f>;
impl I8TrimAbove = trim_impl::Max<i8, -0x80, 0x7e>;
impl U16TrimBelow = trim_impl::Min<u16, 1, 0xffff>;
impl U16TrimAbove = trim_impl::Max<u16, 0, 0xfffe>;
impl I16TrimBelow = trim_impl::Min<i16, -0x7fff, 0x7fff>;
impl I16TrimAbove = trim_impl::Max<i16, -0x8000, 0x7ffe>;
impl U32TrimBelow = trim_impl::Min<u32, 1, 0xffffffff>;
impl U32TrimAbove = trim_impl::Max<u32, 0, 0xfffffffe>;
impl I32TrimBelow = trim_impl::Min<i32, -0x7fffffff, 0x7fffffff>;
impl I32TrimAbove = trim_impl::Max<i32, -0x80000000, 0x7ffffffe>;
impl U64TrimBelow = trim_impl::Min<u64, 1, 0xffffffffffffffff>;
impl U64TrimAbove = trim_impl::Max<u64, 0, 0xfffffffffffffffe>;
impl I64TrimBelow = trim_impl::Min<i64, -0x7fffffffffffffff, 0x7fffffffffffffff>;
impl I64TrimAbove = trim_impl::Max<i64, -0x8000000000000000, 0x7ffffffffffffffe>;
impl U128TrimBelow = trim_impl::Min<u128, 1, 0xffffffffffffffffffffffffffffffff>;
impl U128TrimAbove = trim_impl::Max<u128, 0, 0xfffffffffffffffffffffffffffffffe>;
impl I128TrimBelow =
trim_impl::Impl<
i128,
-0x80000000000000000000000000000000,
-0x7fffffffffffffffffffffffffffffff,
0x7fffffffffffffffffffffffffffffff,
>;
trim_impl::Min<i128, -0x7fffffffffffffffffffffffffffffff, 0x7fffffffffffffffffffffffffffffff>;
impl I128TrimAbove =
trim_impl::Impl<
i128,
0x7fffffffffffffffffffffffffffffff,
-0x80000000000000000000000000000000,
0x7ffffffffffffffffffffffffffffffe,
>;
trim_impl::Max<i128, -0x80000000000000000000000000000000, 0x7ffffffffffffffffffffffffffffffe>;

extern fn bounded_int_trim<T, const TRIMMED_VALUE: felt252, impl H: TrimHelper<T, TRIMMED_VALUE>>(
extern fn bounded_int_trim_min<T, impl H: TrimMinHelper<T>>(
value: T,
) -> core::internal::OptionRev<H::Target> nopanic;
extern fn bounded_int_trim_max<T, impl H: TrimMaxHelper<T>>(
value: T,
) -> core::internal::OptionRev<H::Target> nopanic;

Expand Down Expand Up @@ -272,5 +265,5 @@ impl MulMinusOneNegateHelper<T, impl H: MulHelper<T, MinusOne>> of NegateHelper<
pub use {
bounded_int_add as add, bounded_int_constrain as constrain, bounded_int_div_rem as div_rem,
bounded_int_is_zero as is_zero, bounded_int_mul as mul, bounded_int_sub as sub,
bounded_int_trim as trim,
bounded_int_trim_max as trim_max, bounded_int_trim_min as trim_min,
};
94 changes: 94 additions & 0 deletions corelib/src/iter/traits/iterator.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,100 @@ pub trait Iterator<T> {
enumerated_iterator(self)
}

/// Folds every element into an accumulator by applying an operation,
/// returning the final result.
///
/// `fold()` takes two arguments: an initial value, and a closure with two
/// arguments: an 'accumulator', and an element. The closure returns the value that
/// the accumulator should have for the next iteration.
///
/// The initial value is the value the accumulator will have on the first
/// call.
///
/// After applying this closure to every element of the iterator, `fold()`
/// returns the accumulator.
///
/// Folding is useful whenever you have a collection of something, and want
/// to produce a single value from it.
///
/// Note: `fold()`, and similar methods that traverse the entire iterator,
/// might not terminate for infinite iterators, even on traits for which a
/// result is determinable in finite time.
///
/// Note: `fold()` combines elements in a *left-associative* fashion. For associative
/// operators like `+`, the order the elements are combined in is not important, but for
/// non-associative operators like `-` the order will affect the final result.
///
/// # Note to Implementors
///
/// Several of the other (forward) methods have default implementations in
/// terms of this one, so try to implement this explicitly if it can
/// do something better than the default `for` loop implementation.
///
/// In particular, try to have this call `fold()` on the internal parts
/// from which this iterator is composed.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let mut iter = array![1, 2, 3].into_iter();
///
/// // the sum of all of the elements of the array
/// let sum = iter.fold(0, |acc, x| acc + x);
///
/// assert_eq!(sum, 6);
/// ```
///
/// Let's walk through each step of the iteration here:
///
/// | element | acc | x | result |
/// |---------|-----|---|--------|
/// | | 0 | | |
/// | 1 | 0 | 1 | 1 |
/// | 2 | 1 | 2 | 3 |
/// | 3 | 3 | 3 | 6 |
///
/// And so, our final result, `6`.
///
/// It's common for people who haven't used iterators a lot to
/// use a `for` loop with a list of things to build up a result. Those
/// can be turned into `fold()`s:
///
/// ```
/// let mut numbers = array![1, 2, 3, 4, 5].span();
///
/// let mut result = 0;
///
/// // for loop:
/// for i in numbers{
/// result = result + (*i);
/// };
///
/// // fold:
/// let mut numbers_iter = numbers.into_iter();
/// let result2 = numbers_iter.fold(0, |acc, x| acc + (*x));
///
/// // they're the same
/// assert_eq!(result, result2);
/// ```
fn fold<
B,
F,
+core::ops::Fn<F, (B, Self::Item)>[Output: B],
+Destruct<T>,
+Destruct<F>,
+Destruct<B>,
>(
ref self: T, init: B, f: F,
) -> B {
match Self::next(ref self) {
Option::None => init,
Option::Some(x) => Self::fold(ref self, f(init, x), f),
}
}

/// 'Zips up' two iterators into a single iterator of pairs.
///
/// `zip()` returns a new iterator that will iterate over two other
Expand Down
106 changes: 44 additions & 62 deletions corelib/src/test/integer_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2161,81 +2161,63 @@ mod bounded_int {
#[test]
fn test_trim() {
use core::internal::OptionRev;
assert!(bounded_int::trim::<u8, 0>(0) == OptionRev::None);
assert!(bounded_int::trim::<u8, 0>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<u8, 0xff>(0xff) == OptionRev::None);
assert!(bounded_int::trim::<u8, 0xff>(0xfe) == OptionRev::Some(0xfe));
assert!(bounded_int::trim::<i8, -0x80>(-0x80) == OptionRev::None);
assert!(bounded_int::trim::<i8, -0x80>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<i8, 0x7f>(0x7f) == OptionRev::None);
assert!(bounded_int::trim::<i8, 0x7f>(1) == OptionRev::Some(1));

assert!(bounded_int::trim::<u16, 0>(0) == OptionRev::None);
assert!(bounded_int::trim::<u16, 0>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<u16, 0xffff>(0xffff) == OptionRev::None);
assert!(bounded_int::trim::<u16, 0xffff>(0xfffe) == OptionRev::Some(0xfffe));
assert!(bounded_int::trim::<i16, -0x8000>(-0x8000) == OptionRev::None);
assert!(bounded_int::trim::<i16, -0x8000>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<i16, 0x7fff>(0x7fff) == OptionRev::None);
assert!(bounded_int::trim::<i16, 0x7fff>(1) == OptionRev::Some(1));

assert!(bounded_int::trim::<u32, 0>(0) == OptionRev::None);
assert!(bounded_int::trim::<u32, 0>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<u32, 0xffffffff>(0xffffffff) == OptionRev::None);
assert!(bounded_int::trim::<u32, 0xffffffff>(0xfffffffe) == OptionRev::Some(0xfffffffe));
assert!(bounded_int::trim::<i32, -0x80000000>(-0x80000000) == OptionRev::None);
assert!(bounded_int::trim::<i32, -0x80000000>(1) == OptionRev::Some(1));
assert!(bounded_int::trim::<i32, 0x7fffffff>(0x7fffffff) == OptionRev::None);
assert!(bounded_int::trim::<i32, 0x7fffffff>(1) == OptionRev::Some(1));

assert!(bounded_int::trim::<u64, 0>(0) == OptionRev::None);
assert!(bounded_int::trim::<u64, 0>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_min::<u8>(0) == OptionRev::None);
assert!(bounded_int::trim_min::<u8>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<u8>(0xff) == OptionRev::None);
assert!(bounded_int::trim_max::<u8>(0xfe) == OptionRev::Some(0xfe));
assert!(bounded_int::trim_min::<i8>(-0x80) == OptionRev::None);
assert!(bounded_int::trim_min::<i8>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<i8>(0x7f) == OptionRev::None);
assert!(bounded_int::trim_max::<i8>(1) == OptionRev::Some(1));

assert!(bounded_int::trim_min::<u16>(0) == OptionRev::None);
assert!(bounded_int::trim_min::<u16>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<u16>(0xffff) == OptionRev::None);
assert!(bounded_int::trim_max::<u16>(0xfffe) == OptionRev::Some(0xfffe));
assert!(bounded_int::trim_min::<i16>(-0x8000) == OptionRev::None);
assert!(bounded_int::trim_min::<i16>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<i16>(0x7fff) == OptionRev::None);
assert!(bounded_int::trim_max::<i16>(1) == OptionRev::Some(1));

assert!(bounded_int::trim_min::<u32>(0) == OptionRev::None);
assert!(bounded_int::trim_min::<u32>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<u32>(0xffffffff) == OptionRev::None);
assert!(bounded_int::trim_max::<u32>(0xfffffffe) == OptionRev::Some(0xfffffffe));
assert!(bounded_int::trim_min::<i32>(-0x80000000) == OptionRev::None);
assert!(bounded_int::trim_min::<i32>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<i32>(0x7fffffff) == OptionRev::None);
assert!(bounded_int::trim_max::<i32>(1) == OptionRev::Some(1));

assert!(bounded_int::trim_min::<u64>(0) == OptionRev::None);
assert!(bounded_int::trim_min::<u64>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<u64>(0xffffffffffffffff) == OptionRev::None);
assert!(
bounded_int::trim::<u64, 0xffffffffffffffff>(0xffffffffffffffff) == OptionRev::None,
bounded_int::trim_max::<u64>(0xfffffffffffffffe) == OptionRev::Some(0xfffffffffffffffe),
);
assert!(
bounded_int::trim::<
u64, 0xffffffffffffffff,
>(0xfffffffffffffffe) == OptionRev::Some(0xfffffffffffffffe),
);
assert!(
bounded_int::trim::<i64, -0x8000000000000000>(-0x8000000000000000) == OptionRev::None,
);
assert!(bounded_int::trim::<i64, -0x8000000000000000>(1) == OptionRev::Some(1));
assert!(
bounded_int::trim::<i64, 0x7fffffffffffffff>(0x7fffffffffffffff) == OptionRev::None,
);
assert!(bounded_int::trim::<i64, 0x7fffffffffffffff>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_min::<i64>(-0x8000000000000000) == OptionRev::None);
assert!(bounded_int::trim_min::<i64>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_max::<i64>(0x7fffffffffffffff) == OptionRev::None);
assert!(bounded_int::trim_max::<i64>(1) == OptionRev::Some(1));

assert!(bounded_int::trim::<u128, 0>(0) == OptionRev::None);
assert!(bounded_int::trim::<u128, 0>(1) == OptionRev::Some(1));
assert!(bounded_int::trim_min::<u128>(0) == OptionRev::None);
assert!(bounded_int::trim_min::<u128>(1) == OptionRev::Some(1));
assert!(
bounded_int::trim::<
u128, 0xffffffffffffffffffffffffffffffff,
>(0xffffffffffffffffffffffffffffffff) == OptionRev::None,
bounded_int::trim_max::<u128>(0xffffffffffffffffffffffffffffffff) == OptionRev::None,
);
assert!(
bounded_int::trim::<
u128, 0xffffffffffffffffffffffffffffffff,
bounded_int::trim_max::<
u128,
>(
0xfffffffffffffffffffffffffffffffe,
) == OptionRev::Some(0xfffffffffffffffffffffffffffffffe),
);
assert!(
bounded_int::trim::<
i128, -0x80000000000000000000000000000000,
>(-0x80000000000000000000000000000000) == OptionRev::None,
);
assert!(
bounded_int::trim::<i128, -0x80000000000000000000000000000000>(1) == OptionRev::Some(1),
);
assert!(
bounded_int::trim::<
i128, 0x7fffffffffffffffffffffffffffffff,
>(0x7fffffffffffffffffffffffffffffff) == OptionRev::None,
bounded_int::trim_min::<i128>(-0x80000000000000000000000000000000) == OptionRev::None,
);
assert!(bounded_int::trim_min::<i128>(1) == OptionRev::Some(1));
assert!(
bounded_int::trim::<i128, 0x7fffffffffffffffffffffffffffffff>(1) == OptionRev::Some(1),
bounded_int::trim_max::<i128>(0x7fffffffffffffffffffffffffffffff) == OptionRev::None,
);
assert!(bounded_int::trim_max::<i128>(1) == OptionRev::Some(1));
}
}
9 changes: 9 additions & 0 deletions corelib/src/test/iter_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fn test_iter_adapter_map() {
assert_eq!(iter.next(), Option::None);
}

#[test]
fn test_iterator_enumerate() {
let mut iter = array!['a', 'b', 'c'].into_iter().enumerate();

Expand All @@ -34,3 +35,11 @@ fn test_iterator_zip() {
assert_eq!(iter.next(), Option::Some(((3, 6), 9)));
assert_eq!(iter.next(), Option::None);
}

#[test]
fn test_iter_adapter_fold() {
let mut iter = array![1, 2, 3].into_iter();
let sum = iter.fold(0, |acc, x| acc + x);

assert_eq!(sum, 6);
}
22 changes: 22 additions & 0 deletions corelib/src/test/language_features/const_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,25 @@ fn test_complex_consts() {
};
assert_eq!(IF_CONST_FALSE, 7);
}

mod const_starknet_consts {
pub extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<
(starknet::ContractAddress, starknet::ClassHash),
> nopanic;
}

#[test]
fn test_starknet_consts() {
assert!(
const_starknet_consts::const_as_box::<
struct2::Const<
(starknet::ContractAddress, starknet::ClassHash),
value::Const<starknet::ContractAddress, 1000>,
value::Const<starknet::ClassHash, 1001>,
>,
0,
>()
.unbox() == (1000.try_into().unwrap(), 1001.try_into().unwrap()),
);
}

Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ ExprBlock

//! > ==========================================================================

//! > Test if-let boolean opperators
//! > Test if-let boolean operators

//! > test_runner_name
test_partial_parser_tree(expect_diagnostics: false)
Expand Down
4 changes: 4 additions & 0 deletions crates/cairo-lang-semantic/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,9 @@ impl DiagnosticEntry for SemanticDiagnostic {
SemanticDiagnosticKind::RefClosureArgument => {
"Arguments to closure functions cannot be references".into()
}
SemanticDiagnosticKind::RefClosureParam => {
"Closure parameters cannot be references".into()
}
SemanticDiagnosticKind::MutableCapturedVariable => {
"Capture of mutable variables in a closure is not supported".into()
}
Expand Down Expand Up @@ -1422,6 +1425,7 @@ pub enum SemanticDiagnosticKind {
shadowed_function_name: SmolStr,
},
RefClosureArgument,
RefClosureParam,
MutableCapturedVariable,
NonTraitTypeConstrained {
identifier: SmolStr,
Expand Down
Loading

0 comments on commit 3fd2bda

Please sign in to comment.