diff --git a/.github/workflows/bench-hyperfine.yml b/.github/workflows/bench-hyperfine.yml index 585c7422f6..5cee142d97 100644 --- a/.github/workflows/bench-hyperfine.yml +++ b/.github/workflows/bench-hyperfine.yml @@ -24,6 +24,8 @@ jobs: LLVM_SYS_191_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 + with: + submodules: true - name: check and free hdd space left run: | echo "Listing 20 largest packages" @@ -129,6 +131,7 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request[matrix.branch].sha }} + submodules: true - name: Fetch Rust cache uses: Swatinem/rust-cache@v2 @@ -162,6 +165,7 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request[matrix.branch].sha }} + submodules: true - name: Install Hyperfine uses: taiki-e/install-action@v2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 974fa6aaeb..4d9af8cebd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,8 @@ jobs: TABLEGEN_190_PREFIX: /usr/lib/llvm-19/ steps: - uses: actions/checkout@v4 + with: + submodules: true - uses: dtolnay/rust-toolchain@1.84.1 with: components: clippy, rustfmt @@ -116,6 +118,8 @@ jobs: RUST_LOG: cairo_native=debug,cairo_native_test=debug steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Install testing tools uses: taiki-e/install-action@v2 with: @@ -171,6 +175,8 @@ jobs: RUST_LOG: cairo_native=debug,cairo_native_test=debug steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Install testing tools uses: taiki-e/install-action@v2 with: @@ -194,6 +200,8 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + with: + submodules: true - name: check and free hdd space left run: | echo "Listing 20 largest packages" @@ -222,6 +230,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Retreive cached dependecies uses: Swatinem/rust-cache@v2 - name: Install dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6795dac18..153984ae90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Set env run: | echo "MLIR_SYS_190_PREFIX=${{ matrix.dep_base_dir }}" >> $GITHUB_ENV diff --git a/.github/workflows/starknet-blocks.yml b/.github/workflows/starknet-blocks.yml index 0aa901ceb0..591325c9f7 100644 --- a/.github/workflows/starknet-blocks.yml +++ b/.github/workflows/starknet-blocks.yml @@ -8,7 +8,6 @@ on: jobs: run-blocks: - if: false name: Run Blocks runs-on: ubuntu-latest env: @@ -33,7 +32,7 @@ jobs: with: repository: starkware-libs/starknet-replay path: starknet-replay - ref: 5e75e33d67de77fe68aba06e05571175c0976733 + ref: 4b896e523bd33da66b95c8b2afdb7423785e99d4 # We need native to use the linux deps ci action - name: Checkout Native @@ -46,8 +45,8 @@ jobs: repository: starkware-libs/sequencer path: sequencer # branch main-v0.14.2 - ref: 77a1a32b7b2c52edd9b634276e3bb28f5fbd750c - + ref: efa9bd7d9e33e44d0cea08bf67c7b413fb20c7cb + - name: Restore RPC Calls id: restore-rpc-calls uses: actions/cache/restore@v4.2.0 @@ -108,14 +107,14 @@ jobs: with: name: dump-${{matrix.block}}-${{matrix.runner}} path: starknet-replay/state_dumps/${{matrix.runner}} - + - name: Save RPC Calls uses: actions/cache/save@v4.2.0 if: ${{ always() && matrix.runner == 'vm' }} with: path: starknet-replay/cache key: ${{ steps.restore-rpc-calls.outputs.cache-primary-key }} - + compare-dumps: name: Compare Dumps needs: [run-blocks] diff --git a/.gitignore b/.gitignore index fcd6b7f290..fbafa6f19d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,10 +34,9 @@ cairo-*.tar *.ipynb cairo-native-stress-logs.jsonl - + .DS_Store bench_starknet_compilation_data -cairo test_data_artifacts/programs test_data_artifacts/contracts diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..40243cb3fa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "vendor/cairo"] + path = vendor/cairo + url = https://github.com/starkware-libs/cairo.git + branch = v2.16.0 diff --git a/Cargo.lock b/Cargo.lock index 15ec09d6b9..3d1751fa64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ dependencies = [ "postcard", "salsa", "serde", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", "tracing", ] @@ -695,7 +695,7 @@ dependencies = [ "salsa", "serde", "sha2", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", ] @@ -724,7 +724,7 @@ dependencies = [ "salsa", "serde", "sha3", - "starknet-types-core", + "starknet-types-core 0.2.4", "toml", "tracing", ] @@ -751,7 +751,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", ] @@ -829,7 +829,7 @@ dependencies = [ "itertools 0.14.0", "num-bigint", "num-traits", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", ] @@ -871,7 +871,7 @@ dependencies = [ "salsa", "serde", "serde_json", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", "typetag", ] @@ -896,7 +896,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", ] @@ -955,7 +955,7 @@ dependencies = [ "num-traits", "salsa", "serde", - "starknet-types-core", + "starknet-types-core 0.2.4", ] [[package]] @@ -979,7 +979,7 @@ dependencies = [ "num-traits", "rayon", "salsa", - "starknet-types-core", + "starknet-types-core 0.2.4", ] [[package]] @@ -1064,7 +1064,7 @@ dependencies = [ "sha2", "sierra-emu", "starknet-curve", - "starknet-types-core", + "starknet-types-core 1.0.0", "tempfile", "test-case", "thiserror", @@ -1092,7 +1092,7 @@ dependencies = [ "num-traits", "rayon", "scarb-metadata", - "starknet-types-core", + "starknet-types-core 1.0.0", "tracing", ] @@ -1211,7 +1211,7 @@ dependencies = [ "sha2", "sha3", "starknet-crypto", - "starknet-types-core", + "starknet-types-core 0.2.4", "thiserror", "tracing", "zip", @@ -3591,7 +3591,7 @@ dependencies = [ "smallvec", "starknet-crypto", "starknet-curve", - "starknet-types-core", + "starknet-types-core 1.0.0", "thiserror", "tracing", "tracing-subscriber", @@ -3703,7 +3703,7 @@ dependencies = [ "rfc6979", "sha2", "starknet-curve", - "starknet-types-core", + "starknet-types-core 0.2.4", "zeroize", ] @@ -3713,7 +3713,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c898ae81b6409532374cf237f1bd752d068b96c6ad500af9ebbd0d9bb712f6" dependencies = [ - "starknet-types-core", + "starknet-types-core 0.2.4", ] [[package]] @@ -3747,6 +3747,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "starknet-types-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a12690813e587969cb4a9e7d8ebdb069d4bb7ec8d03275c5f719310c8e1f07c" +dependencies = [ + "blake2", + "digest", + "generic-array", + "lambdaworks-crypto", + "lambdaworks-math", + "num-bigint", + "num-integer", + "num-traits", + "rand 0.9.2", + "serde", + "zeroize", +] + [[package]] name = "stats_alloc" version = "0.1.10" diff --git a/Cargo.toml b/Cargo.toml index b09eab30a5..6963e37ad3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ sierra-emu = { path = "debug_utils/sierra-emu", version = "0.9.0-rc.2" } smallvec = "1.13.2" starknet-crypto = "0.8.1" starknet-curve = "0.6.0" -starknet-types-core = { version = "0.2.3", features = ["hash"]} +starknet-types-core = { version = "1.0.0", features = ["hash"]} stats_alloc = "0.1.10" tempfile = "3.15.0" test-case = "3.3" @@ -106,6 +106,7 @@ description = "A compiler to convert Cairo's IR Sierra code to MLIR and execute readme = "README.md" keywords = ["starknet", "cairo", "compiler", "mlir"] categories = ["compilers"] +exclude = ["vendor/"] version.workspace = true edition.workspace = true license.workspace = true diff --git a/Makefile b/Makefile index 13e86b6249..26b838235c 100644 --- a/Makefile +++ b/Makefile @@ -188,10 +188,11 @@ install-scarb-macos: sed 's/zsh_completion_block/zsh_completions_block/g' | \ sh -s -- --version $(SCARB_VERSION) -.PHONY: pull-external-projects -pull-external-projects: - python3 ./scripts/pull_external_projects.py v${CAIRO_2_VERSION} + +test_data/e2e_sierra: vendor/cairo + python3 ./scripts/extract_e2e_sierra.py + .PHONY: compile-test-data -compile-test-data: +compile-test-data: test_data/e2e_sierra python3 ./scripts/compile_test_data.py diff --git a/corelib b/corelib new file mode 120000 index 0000000000..70ecb29f94 --- /dev/null +++ b/corelib @@ -0,0 +1 @@ +vendor/cairo/corelib \ No newline at end of file diff --git a/corelib/.tool-versions b/corelib/.tool-versions deleted file mode 100644 index 61d8e16c84..0000000000 --- a/corelib/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -scarb nightly-2024-12-22 diff --git a/corelib/Scarb.lock b/corelib/Scarb.lock deleted file mode 100644 index 6297bdc2c5..0000000000 --- a/corelib/Scarb.lock +++ /dev/null @@ -1,6 +0,0 @@ -# Code generated by scarb DO NOT EDIT. -version = 1 - -[[package]] -name = "core" -version = "2.16.0" diff --git a/corelib/Scarb.toml b/corelib/Scarb.toml deleted file mode 100644 index b119cd13b8..0000000000 --- a/corelib/Scarb.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "core" -version = "2.16.0" -edition = "2025_12" -experimental-features = [ - "associated_item_constraints", - "coupons", - "negative_impls", - "user_defined_inline_macros", -] - -# NOTE: This is non-public, unstable Scarb's field, which instructs resolver that this package does not -# depend on `core`, which is only true for this particular package. Nobody else should use it. -no-core = true - -[dev-dependencies] -cairo_test = "2.16.0" diff --git a/corelib/cairo_project.toml b/corelib/cairo_project.toml deleted file mode 100644 index 2bc4586cb3..0000000000 --- a/corelib/cairo_project.toml +++ /dev/null @@ -1,12 +0,0 @@ -[crate_roots] -core = "src" - -[config.global] -edition = "2025_12" -version = "2.16.0" - -[config.global.experimental_features] -associated_item_constraints = true -coupons = true -negative_impls = true -user_defined_inline_macros = true diff --git a/corelib/src/array.cairo b/corelib/src/array.cairo deleted file mode 100644 index b2dcbbe0f5..0000000000 --- a/corelib/src/array.cairo +++ /dev/null @@ -1,908 +0,0 @@ -//! A contiguous collection of elements of the same type in memory, written -//! `Array`. -//! -//! Arrays have *O*(1) indexing, *O*(1) push and *O*(1) pop -//! (from the front). -//! -//! Arrays can only be mutated by appending to the end or popping from the front. -//! -//! # Examples -//! -//! You can explicitly create an [`Array`] with [`ArrayTrait::new`]: -//! -//! ``` -//! let arr: Array = ArrayTrait::new(); -//! ``` -//! -//! ...or by using the `array!` macro: -//! -//! ``` -//! let arr: Array = array![]; -//! -//! let arr: Array = array![1, 2, 3, 4, 5]; -//! ``` -//! -//! You can [`append`] values onto the end of an array: -//! -//! ``` -//! let mut arr = array![1, 2]; -//! arr.append(3); -//! ``` -//! -//! Popping values from the front works like this: -//! -//! ``` -//! let mut arr = array![1, 2]; -//! let one = arr.pop_front(); // Returns Some(1) -//! ``` -//! -//! Arrays support indexing (through the [`IndexView`] trait): -//! -//! ``` -//! let arr = array![1, 2, 3]; -//! let three = arr[2]; // Returns a snapshot (@T) -//! ``` -//! -//! Arrays can be converted to [`Span`]s for read-only access: -//! -//! ``` -//! let arr = array![1, 2, 3]; -//! let span = arr.span(); -//! ``` -//! -//! A span can be manipulated without affecting the original array: -//! -//! ``` -//! let mut arr = array![1, 2, 3]; -//! let mut span = arr.span(); -//! span.pop_back(); -//! assert!(arr == array![1, 2, 3]); -//! ``` -//! -//! [`append`]: ArrayTrait::append - -use crate::RangeCheck; -use crate::box::BoxTrait; -#[allow(unused_imports)] -use crate::gas::withdraw_gas; -use crate::iter::Iterator; -use crate::metaprogramming::TypeEqual; -use crate::num::traits::CheckedSub; -#[allow(unused_imports)] -use crate::option::OptionTrait; -use crate::serde::Serde; -#[feature("deprecated-index-traits")] -use crate::traits::IndexView; -/// A collection of elements of the same type contiguous in memory. -pub extern type Array; - -impl ArrayDrop> of Drop>; - -extern fn array_new() -> Array nopanic; -extern fn array_append(ref arr: Array, value: T) nopanic; -extern fn array_pop_front(ref arr: Array) -> Option> nopanic; -extern fn array_pop_front_consume(arr: Array) -> Option<(Array, Box)> nopanic; -pub(crate) extern fn array_snapshot_pop_front(ref arr: @Array) -> Option> nopanic; -extern fn array_snapshot_pop_back(ref arr: @Array) -> Option> nopanic; -extern fn array_snapshot_multi_pop_front>( - ref arr: @Array, -) -> Option<@Box> implicits(RangeCheck) nopanic; -extern fn array_snapshot_multi_pop_back>( - ref arr: @Array, -) -> Option<@Box> implicits(RangeCheck) nopanic; -#[panic_with('Index out of bounds', array_at)] -extern fn array_get( - arr: @Array, index: usize, -) -> Option> implicits(RangeCheck) nopanic; -extern fn array_slice( - arr: @Array, start: usize, length: usize, -) -> Option<@Array> implicits(RangeCheck) nopanic; -extern fn array_len(arr: @Array) -> usize nopanic; - -/// Basic trait for the `Array` type. -#[generate_trait] -pub impl ArrayImpl of ArrayTrait { - /// Constructs a new, empty `Array`. - /// - /// # Examples - /// - /// ``` - /// let arr: Array = ArrayTrait::new(); - /// - /// let arr = ArrayTrait::::new(); - /// ``` - /// - /// It is also possible to use the `array!` macro to create a new array. - /// - /// ``` - /// let arr: Array = array![]; - /// ``` - #[inline] - fn new() -> Array nopanic { - array_new() - } - - /// Adds a value of type `T` to the end of the array. - /// - /// # Examples - /// - /// ``` - /// let mut arr: Array = array![1, 2]; - /// arr.append(3); - /// assert!(arr == array![1, 2, 3]); - /// ``` - #[inline] - fn append(ref self: Array, value: T) nopanic { - array_append(ref self, value) - } - - /// Adds a span to the end of the array. - /// - /// # Examples - /// - /// ``` - /// let mut arr: Array = array![]; - /// arr.append_span(array![1, 2, 3].span()); - /// assert!(arr == array![1, 2, 3]); - /// ``` - fn append_span<+Clone, +Drop>(ref self: Array, mut span: Span) { - match span.pop_front() { - Some(current) => { - self.append(current.clone()); - self.append_span(span); - }, - None => {}, - } - } - - /// Pops a value from the front of the array. - /// Returns `Some(value)` if the array is not empty, `None` otherwise. - /// - /// # Examples - /// - /// ``` - /// let mut arr = array![2, 3, 4]; - /// assert!(arr.pop_front() == Some(2)); - /// assert!(arr.pop_front() == Some(3)); - /// assert!(arr.pop_front() == Some(4)); - /// assert!(arr.pop_front().is_none()); - /// ``` - #[inline] - fn pop_front(ref self: Array) -> Option nopanic { - match array_pop_front(ref self) { - Some(x) => Some(x.unbox()), - None => None, - } - } - - /// Pops a value from the front of the array. - /// Returns an option containing the remaining array and the value removed if the array is - /// not empty, otherwise `None` and drops the array. - /// - /// # Examples - /// - /// ``` - /// let arr = array![2, 3, 4]; - /// assert!(arr.pop_front_consume() == Some((array![3, 4], 2))); - /// - /// let arr: Array = array![]; - /// assert!(arr.pop_front_consume().is_none()); - /// ``` - #[inline] - fn pop_front_consume(self: Array) -> Option<(Array, T)> nopanic { - match array_pop_front_consume(self) { - Some((arr, x)) => Some((arr, x.unbox())), - None => None, - } - } - - /// Returns an option containing a box of a snapshot of the element at the given 'index' - /// if the array contains this index, 'None' otherwise. - /// - /// Element at index 0 is the front of the array. - /// - /// # Examples - /// - /// ``` - /// let arr = array![2, 3, 4]; - /// assert!(arr.get(1).unwrap().unbox() == @3); - /// ``` - #[inline] - fn get(self: @Array, index: usize) -> Option> { - array_get(self, index) - } - - /// Returns a snapshot of the element at the given index. - /// - /// Element at index 0 is the front of the array. - /// - /// # Panics - /// - /// Panics if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// let mut arr: Array = array![3,4,5,6]; - /// assert!(arr.at(1) == @4); - /// ``` - fn at(self: @Array, index: usize) -> @T { - array_at(self, index).unbox() - } - - /// Returns the length of the array as a `usize` value. - /// - /// # Examples - /// - /// ``` - /// let arr = array![2, 3, 4]; - /// assert!(arr.len() == 3); - /// ``` - #[inline] - #[must_use] - fn len(self: @Array) -> usize { - array_len(self) - } - - /// Returns whether the array is empty or not. - /// - /// # Examples - /// - /// ``` - /// let mut arr = array![]; - /// assert!(arr.is_empty()); - /// arr.append(1); - /// assert!(!arr.is_empty()); - /// ``` - #[inline] - #[must_use] - fn is_empty(self: @Array) -> bool { - let mut snapshot = self; - match array_snapshot_pop_front(ref snapshot) { - Some(_) => false, - None => true, - } - } - - /// Returns a span of the array. - /// - /// # Examples - /// - /// ``` - /// let arr: Array = array![1, 2, 3]; - /// let span: Span = arr.span(); - /// ``` - #[inline] - #[must_use] - fn span(snapshot: @Array) -> Span { - Span { snapshot } - } -} - -impl ArrayDefault of Default> { - /// Returns a new empty array. - #[inline] - fn default() -> Array { - ArrayTrait::new() - } -} - -impl ArrayIndex of IndexView, usize, @T> { - /// Returns a snapshot of the element at the given index. - /// - /// # Examples - /// - /// ``` - /// let arr: @Array = @array![1, 2, 3]; - /// let element: @u8 = arr[0]; - /// assert!(element == @1); - /// ``` - fn index(self: @Array, index: usize) -> @T { - array_at(self, index).unbox() - } -} - -impl ArraySerde, +Drop> of Serde> { - /// Serializes an `Array` into an `Array`. - /// - /// # Examples - /// - /// ``` - /// let arr: Array = array![1, 2, 3]; - /// let mut output: Array = array![]; - /// arr.serialize(ref output); - /// assert!(output == array![3, 1, 2, 3]) - /// ``` - fn serialize(self: @Array, ref output: Array) { - self.len().serialize(ref output); - serialize_array_helper(self.span(), ref output); - } - - /// Deserializes a `Span` into an `Array` and returns an option of an `Array`. - /// - /// # Examples - /// - /// ``` - /// let mut span: Span = array![2, 0, 1].span(); - /// let arr: Array = Serde::deserialize(ref span).unwrap(); - /// assert!(arr == array![0, 1]); - /// ``` - fn deserialize(ref serialized: Span) -> Option> { - let length = *serialized.pop_front()?; - let mut arr = array![]; - deserialize_array_helper(ref serialized, arr, length) - } -} - -fn serialize_array_helper, +Drop>(mut input: Span, ref output: Array) { - match input.pop_front() { - Some(value) => { - value.serialize(ref output); - serialize_array_helper(input, ref output); - }, - None => {}, - } -} - -fn deserialize_array_helper, +Drop>( - ref serialized: Span, mut curr_output: Array, remaining: felt252, -) -> Option> { - if remaining == 0 { - return Some(curr_output); - } - curr_output.append(Serde::deserialize(ref serialized)?); - deserialize_array_helper(ref serialized, curr_output, remaining - 1) -} - -/// A span is a view into a contiguous collection of the same type - such as `Array`. -/// It is a structure with a single field that holds a snapshot of an array. -/// `Span` implements the `Copy` and the `Drop` traits. -pub struct Span { - /// The snapshot of the array. - pub(crate) snapshot: @Array, -} - -impl SpanCopy of Copy>; -impl SpanDrop of Drop>; - -impl ArrayIntoSpan> of Into, Span> { - fn into(self: Array) -> Span { - self.span() - } -} - -impl SpanIntoArray, +Clone> of Into, Array> { - /// Turns a span into an array. - /// - /// This needs to allocate a new memory segment for the returned array, and *O*(*n*) operations - /// to populate the array with the content of the span. - /// - /// # Examples - /// - /// ``` - /// let input: Span = array![1, 2, 3].span(); - /// let output: Array = input.into(); - /// assert!(input == output.span()); - /// ``` - fn into(self: Span) -> Array { - let mut arr = array![]; - arr.append_span(self); - arr - } -} - -impl SpanIntoArraySnap of Into, @Array> { - fn into(self: Span) -> @Array { - self.snapshot - } -} - -impl SpanFelt252Serde of Serde> { - /// Serializes a `Span` into an `Array`. - /// - /// # Examples - /// - /// ``` - /// let span: Span = array![1, 2, 3].span(); - /// let mut output: Array = array![]; - /// span.serialize(ref output); - /// assert!(output == array![3, 1, 2, 3].span()); - /// ``` - fn serialize(self: @Span, ref output: Array) { - (*self).len().serialize(ref output); - serialize_array_helper(*self, ref output) - } - - /// Deserializes a `Span` into an `Span` and returns an option of a - /// `Span`. - /// - /// # Examples - /// - /// ``` - /// let mut span: Span = array![2, 0, 1].span(); - /// let result: Span = Serde::deserialize(ref span).unwrap(); - /// assert!(result == array![0, 1]); - /// ``` - fn deserialize(ref serialized: Span) -> Option> { - let length: u32 = (*serialized.pop_front()?).try_into()?; - let res = array_slice(serialized.snapshot, 0, length)?; - let remaining = serialized.len().checked_sub(length)?; - serialized.snapshot = array_slice(serialized.snapshot, length, remaining)?; - Some(Span { snapshot: res }) - } -} - -impl SpanSerde, +Drop, -TypeEqual> of Serde> { - /// Serializes a `Span` into an `Array`. - /// - /// # Examples - /// - /// ``` - /// let span: Span = array![1, 2, 3].span(); - /// let mut output: Array = array![]; - /// span.serialize(ref output); - /// assert!(output == array![3, 1, 2, 3].span()); - /// ``` - fn serialize(self: @Span, ref output: Array) { - (*self).len().serialize(ref output); - serialize_array_helper(*self, ref output) - } - - /// Deserializes a `Span` into an `Span` and returns an option of a `Span`. - /// - /// # Examples - /// - /// ``` - /// let mut span: Span = array![2, 0, 1].span(); - /// let result: Span = Serde::deserialize(ref span).unwrap(); - /// assert!(result == array![0, 1].span()); - /// ``` - fn deserialize(ref serialized: Span) -> Option> { - let length = *serialized.pop_front()?; - let mut arr = array_new(); - Some(deserialize_array_helper(ref serialized, arr, length)?.span()) - } -} - -/// Basic trait for the `Span` type. -#[generate_trait] -pub impl SpanImpl of SpanTrait { - /// Pops a value from the front of the span. - /// Returns `Some(@value)` if the span is not empty, `None` otherwise. - /// - /// # Examples - /// - /// ``` - /// let mut span = array![1, 2, 3].span(); - /// assert!(span.pop_front() == Some(@1)); - /// ``` - #[inline] - fn pop_front(ref self: Span) -> Option<@T> nopanic { - let mut snapshot = self.snapshot; - let item = array_snapshot_pop_front(ref snapshot); - self = Span { snapshot }; - match item { - Some(x) => Some(x.unbox()), - None => None, - } - } - - /// Pops a value from the back of the span. - /// Returns `Some(@value)` if the span is not empty, `None` otherwise. - /// - /// # Examples - /// ``` - /// let mut span = array![1, 2, 3].span(); - /// assert!(span.pop_back() == Some(@3)); - /// ``` - #[inline] - fn pop_back(ref self: Span) -> Option<@T> { - let mut snapshot = self.snapshot; - let item = array_snapshot_pop_back(ref snapshot); - self = Span { snapshot }; - match item { - Some(x) => Some(x.unbox()), - None => None, - } - } - - /// Pops multiple values from the front of the span. - /// Returns an option containing a snapshot of a box that contains the values as a fixed-size - /// array if the action completed successfully, 'None' otherwise. - /// - /// # Examples - /// - /// ``` - /// let mut span = array![1, 2, 3].span(); - /// let result = *(span.multi_pop_front::<2>().unwrap()); - /// let unboxed_result = result.unbox(); - /// assert!(unboxed_result == [1, 2]); - /// ``` - fn multi_pop_front(ref self: Span) -> Option<@Box<[T; SIZE]>> { - array_snapshot_multi_pop_front(ref self.snapshot) - } - - /// Pops multiple values from the back of the span. - /// Returns an option containing a snapshot of a box that contains the values as a fixed-size - /// array if the action completed successfully, 'None' otherwise. - /// - /// # Examples - /// - /// ``` - /// let mut span = array![1, 2, 3].span(); - /// let result = *(span.multi_pop_back::<2>().unwrap()); - /// let unboxed_result = result.unbox(); - /// assert!(unboxed_result == [2, 3]); - /// ``` - fn multi_pop_back(ref self: Span) -> Option<@Box<[T; SIZE]>> { - array_snapshot_multi_pop_back(ref self.snapshot) - } - - /// Returns an option containing a box of a snapshot of the element at the given 'index' - /// if the span contains this index, 'None' otherwise. - /// - /// Element at index 0 is the front of the array. - /// - /// # Examples - /// - /// ``` - /// let span = array![2, 3, 4]; - /// assert!(span.get(1).unwrap().unbox() == @3); - /// ``` - #[inline] - fn get(self: Span, index: usize) -> Option> { - array_get(self.snapshot, index) - } - - /// Returns a snapshot of the element at the given index. - /// - /// Element at index 0 is the front of the array. - /// - /// # Panics - /// - /// Panics if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// let span = array![2, 3, 4].span(); - /// assert!(span.at(1) == @3); - /// ``` - #[inline] - fn at(self: Span, index: usize) -> @T { - array_at(self.snapshot, index).unbox() - } - - /// Returns a span containing values from the 'start' index, with - /// amount equal to 'length'. - /// - /// # Examples - /// - /// ``` - /// let span = array![1, 2, 3].span(); - /// assert!(span.slice(1, 2) == array![2, 3].span()); - /// ``` - #[inline] - fn slice(self: Span, start: usize, length: usize) -> Span { - Span { snapshot: array_slice(self.snapshot, start, length).expect('Index out of bounds') } - } - - /// Returns the length of the span as a `usize` value. - /// - /// # Examples - /// - /// ``` - /// let span = array![2, 3, 4].span(); - /// assert!(span.len() == 3); - /// ``` - #[inline] - #[must_use] - fn len(self: Span) -> usize { - array_len(self.snapshot) - } - - /// Returns whether the span is empty or not. - /// - /// # Examples - /// - /// ``` - /// let span: Span = array![].span(); - /// assert!(span.is_empty()); - /// let span = array![1, 2, 3].span(); - /// assert!(!span.is_empty()); - /// ``` - #[inline] - #[must_use] - fn is_empty(self: Span) -> bool { - let mut snapshot = self.snapshot; - match array_snapshot_pop_front(ref snapshot) { - Some(_) => false, - None => true, - } - } -} - -pub impl SpanIndex of IndexView, usize, @T> { - /// Returns a snapshot of the element at the given index. - /// - /// # Examples - /// - /// ``` - /// let span: @Span = @array![1, 2, 3].span(); - /// let element: @u8 = span[0]; - /// assert!(element == @1); - /// ``` - #[inline] - fn index(self: @Span, index: usize) -> @T { - array_at(self.snapshot, index).unbox() - } -} - -/// `ToSpanTrait` converts a data structure into a span of its data. -pub trait ToSpanTrait { - /// Returns a span pointing to the data in the input. - #[must_use] - fn span(self: @C) -> Span; -} - -impl ArrayToSpan of ToSpanTrait, T> { - /// Returns a `Span` corresponding to a view into an `Array`. - #[inline] - fn span(self: @Array) -> Span { - ArrayTrait::span(self) - } -} - -impl SnapIntoSpanWhereToSpanTrait> of Into<@C, Span> { - /// Returns a `Span` corresponding to a view into the given data structure. - fn into(self: @C) -> Span { - self.span() - } -} - -/// Returns a span from a box of a snapshot of a struct of members of the same type. -extern fn span_from_tuple>( - struct_like: Box<@T>, -) -> @Array nopanic; - -impl FixedSizeArrayBoxToSpan of ToSpanTrait, T> { - /// Returns a `Span` corresponding to a view into the given fixed-size array. - /// - /// # Examples - /// - /// ``` - /// let boxed_arr: Box<@[u32; 3]> = BoxTrait::new(@[1, 2, 3]); - /// let span: Span = (@boxed_arr).span(); - /// ``` - fn span(self: @Box<@[T; SIZE]>) -> Span { - Span { snapshot: span_from_tuple(*self) } - } -} - -impl FixedSizeArrayToSpan< - T, const SIZE: usize, -TypeEqual<[T; SIZE], [T; 0]>, -> of ToSpanTrait<[T; SIZE], T> { - /// Returns a `Span` corresponding to a view into the given fixed-size array. - /// - /// # Examples - /// - /// ``` - /// let arr: [u32; 3] = [1, 2, 3]; - /// let span = arr.span() - /// ``` - #[inline] - fn span(self: @[T; SIZE]) -> Span { - BoxTrait::new(self).span() - } -} - -impl EmptyFixedSizeArrayImpl> of ToSpanTrait<[T; 0], T> { - /// Returns a `Span` corresponding to a view into the given empty fixed-size array. - /// - /// # Examples - /// - /// ``` - /// let arr: [u32; 0] = []; - /// let span = arr.span(); - /// ``` - #[inline] - fn span(self: @[T; 0]) -> Span { - array![].span() - } -} - -/// Returns an option to a snapshot of a box of struct of members of the same type from a span. -extern fn tuple_from_span>( - span: @Array, -) -> Option<@Box> nopanic; - -impl SpanTryIntoFixedSizedArray< - T, const SIZE: usize, -TypeEqual<[T; SIZE], [T; 0]>, -> of TryInto, @Box<[T; SIZE]>> { - /// Returns an option of a snapshot of a box that contains a fixed-size array. - /// - /// # Examples - /// - /// ``` - /// let span = array![1, 2, 3].span(); - /// let result: Option<@Box<[felt252; 3]>> = span.try_into(); - /// ``` - #[inline] - fn try_into(self: Span) -> Option<@Box<[T; SIZE]>> { - tuple_from_span(self.snapshot) - } -} - -impl SpanTryIntoEmptyFixedSizedArray> of TryInto, @Box<[T; 0]>> { - /// Returns an option of a snapshot of a box that contains an empty fixed-size array if the span - /// is empty, and `None` otherwise. - /// - /// # Examples - /// - /// ``` - /// let span = array![].span(); - /// let result: Option<@Box<[felt252; 0]>> = span.try_into(); - /// ``` - #[inline] - fn try_into(self: Span) -> Option<@Box<[T; 0]>> { - if self.is_empty() { - Some(@BoxTrait::new([])) - } else { - None - } - } -} - -// TODO(spapini): Remove TDrop. It is necessary to get rid of response in case of panic. -impl ArrayTCloneImpl, +Drop> of Clone> { - fn clone(self: @Array) -> Array { - let mut response = array_new(); - let mut span = self.span(); - loop { - match span.pop_front() { - Some(v) => { response.append(v.clone()); }, - None => { break (); }, - } - } - response - } -} - -impl ArrayPartialEq> of PartialEq> { - fn eq(lhs: @Array, rhs: @Array) -> bool { - lhs.span() == rhs.span() - } -} - -impl SpanPartialEq> of PartialEq> { - fn eq(lhs: @Span, rhs: @Span) -> bool { - if (*lhs).len() != (*rhs).len() { - return false; - } - let mut lhs_span = *lhs; - let mut rhs_span = *rhs; - loop { - match lhs_span.pop_front() { - Some(lhs_v) => { if lhs_v != rhs_span.pop_front().unwrap() { - break false; - } }, - None => { break true; }, - } - } - } -} - -/// An iterator struct over a span collection. -pub struct SpanIter { - span: Span, -} - -impl SpanIterDrop of Drop>; -impl SpanIterCopy of Copy>; - -impl SpanIterator of Iterator> { - /// The type of the elements being iterated over. - type Item = @T; - /// Advances the iterator and returns the next value. Returns `None` when iteration is - /// finished. - fn next(ref self: SpanIter) -> Option<@T> { - self.span.pop_front() - } -} - -impl SpanIntoIterator of crate::iter::IntoIterator> { - type IntoIter = SpanIter; - fn into_iter(self: Span) -> Self::IntoIter { - SpanIter { span: self } - } -} - -impl SnapshotSpanIntoIterator of crate::iter::IntoIterator<@Span> { - type IntoIter = crate::array::SpanIter; - fn into_iter(self: @Span) -> Self::IntoIter { - (*self).into_iter() - } -} - -/// An iterator struct over an array collection. -#[derive(Drop)] -pub struct ArrayIter { - array: Array, -} - -impl ArrayIterClone, +Drop> of crate::clone::Clone> { - fn clone(self: @ArrayIter) -> ArrayIter { - ArrayIter { array: crate::clone::Clone::clone(@self.array) } - } -} - -impl ArrayIterator of Iterator> { - /// The type of the elements being iterated over. - type Item = T; - /// Advances the iterator and returns the next value. Returns `None` when iteration is - /// finished. - fn next(ref self: ArrayIter) -> Option { - self.array.pop_front() - } -} - -impl ArrayIntoIterator of crate::iter::IntoIterator> { - type IntoIter = ArrayIter; - fn into_iter(self: Array) -> Self::IntoIter { - ArrayIter { array: self } - } -} - -impl SnapshotArrayIntoIterator of crate::iter::IntoIterator<@Array> { - type IntoIter = SpanIter; - fn into_iter(self: @Array) -> Self::IntoIter { - self.span().into_iter() - } -} - -impl ArrayFromIterator> of crate::iter::FromIterator, T> { - fn from_iter< - I, - impl IntoIter: IntoIterator, - +core::metaprogramming::TypeEqual, - +Destruct, - +Destruct, - >( - iter: I, - ) -> Array { - let mut arr = array![]; - for elem in iter { - arr.append(elem); - } - arr - } -} - -impl ArrayExtend> of crate::iter::Extend, T> { - fn extend< - I, - impl IntoIter: IntoIterator, - +TypeEqual, - +Destruct, - +Destruct, - >( - ref self: Array, iter: I, - ) { - for elem in iter.into_iter() { - self.append(elem); - }; - } -} - -/// Information about a fixed-sized array. -trait FixedSizedArrayInfo { - /// The type of the elements in the array. - type Element; - /// The size of the array. - const SIZE: usize; -} - -impl FixedSizedArrayInfoImpl of FixedSizedArrayInfo<[T; SIZE]> { - type Element = T; - const SIZE: usize = SIZE; -} diff --git a/corelib/src/blake.cairo b/corelib/src/blake.cairo deleted file mode 100644 index c900ca43ee..0000000000 --- a/corelib/src/blake.cairo +++ /dev/null @@ -1,32 +0,0 @@ -/// State for Blake2s hash. -type Blake2sState = Box<[u32; 8]>; - -/// The input to the Blake2s compress function. -type Blake2sInput = Box<[u32; 16]>; - - -/// The blake2s compress function, which takes a state, a byte count, and a message, and returns a -/// new state. -/// `byte_count` should be the total number of bytes hashed after hashing the current `msg`. -/// -/// Message packing specification: -/// Each `msg[i]` encodes bytes the input block's `4*i..4*i+4` bytes as a little endian `u32`. -/// The returned `Blake2sState` words are the encoded state in little endian representation. -pub extern fn blake2s_compress( - state: Blake2sState, byte_count: u32, msg: Blake2sInput, -) -> Blake2sState nopanic; - - -/// A variant of `blake2s_compress` for the final block of the message. -/// -/// The input `msg` must always be exactly 16 `u32` elements, padded with zeros if necessary, -/// regardless of the value of `byte_count`. Using any padding scheme other than zero-padding -/// will produce a different hash output. -/// -/// Message packing specification: -/// Each `msg[i]` encodes bytes the input block's `4*i..4*i+4` bytes as a little endian `u32`. -/// Unused bytes in that word must be zero. -/// The returned `Blake2sState` words are the encoded state in little endian representation. -pub extern fn blake2s_finalize( - state: Blake2sState, byte_count: u32, msg: Blake2sInput, -) -> Blake2sState nopanic; diff --git a/corelib/src/boolean.cairo b/corelib/src/boolean.cairo deleted file mode 100644 index 6544868141..0000000000 --- a/corelib/src/boolean.cairo +++ /dev/null @@ -1,51 +0,0 @@ -//! Boolean operations. -//! -//! The `bool` type is a primitive type in Cairo representing a boolean value that can be either -//! `true` or `false`. This module provides trait implementations for boolean operations. -//! -//! # Examples -//! -//! Basic boolean operations: -//! -//! ``` -//! -//! let value = true; -//! assert!(value == true); -//! assert!(!value == false); -//! ``` -//! -//! Converting to optional values with [`BoolTrait::then_some`]: -//! -//! ``` -//! use core::boolean::BoolTrait; -//! -//! let bool_value = true; -//! let result = bool_value.then_some(42_u8); -//! assert!(result == Some(42)); -//! -//! let bool_value = false; -//! let result = bool_value.then_some(42_u8); -//! assert!(result == None); -//! ``` - -/// Basic trait for boolean operations. -/// Explicit import of `BoolTrait` is required with `use core::boolean::BoolTrait;`. -#[generate_trait] -pub impl BoolImpl> of BoolTrait { - /// Returns `Some(t)` if the `bool` is `true`, `None` otherwise. - /// - /// # Examples - /// - /// ``` - /// assert!(false.then_some(0) == None); - /// assert!(true.then_some(0) == Some(0)); - /// ``` - #[inline] - fn then_some(self: bool, t: T) -> Option nopanic { - if self { - Some(t) - } else { - None - } - } -} diff --git a/corelib/src/box.cairo b/corelib/src/box.cairo deleted file mode 100644 index c27c57d9f7..0000000000 --- a/corelib/src/box.cairo +++ /dev/null @@ -1,138 +0,0 @@ -//! `Box` is a smart pointer that allows for: -//! -//! * Storing values of arbitrary size while maintaining a fixed-size pointer -//! * Enabling recursive types that would otherwise have infinite size -//! * Moving large data structures efficiently by passing pointers instead of copying values -//! -//! # Examples -//! -//! Creating a new box with [`BoxTrait::new`]: -//! -//! ``` -//! let boxed = BoxTrait::new(42); -//! let unboxed = boxed.unbox(); -//! ``` -//! -//! Working with larger structures: -//! -//! ``` -//! let large_array = array![1, 2, 3, 4, 5]; -//! let boxed_array = BoxTrait::new(large_array); -//! ``` -//! -//! Creating a recursive data structure: -//! -//!``` -//! #[derive(Copy, Drop, Debug)] -//! enum BinaryTree { -//! Leaf: u32, -//! Node: (u32, Box, Box) -//! } -//! -//! let leaf = BinaryTree::Leaf(1); -//! let node = BinaryTree::Node((2, BoxTrait::new(leaf), BoxTrait::new(leaf))); -//! println!("{:?}", node); -//!``` -//! -//! NOTE: A `Box` is a smart pointer type that provides a way to store a value of type `T` in -//! Cairo VM's _boxed_ segment, leaving only a pointer in the execution segment. - -/// A `Box` is a type that points to a wrapped value. -/// It allows for cheap moving around of the value, as its size is small, and may wrap a large size. -pub extern type Box; - -impl BoxCopy> of Copy>; -impl BoxDrop> of Drop>; - - -// These functions must only be exposed in the corelib through the trait below, since calling them -// directly with tuples panics due to auto-unpacking of the tuple. -extern fn into_box(value: T) -> Box nopanic; -extern fn unbox(box: Box) -> T nopanic; -extern fn box_forward_snapshot(value: @Box) -> Box<@T> nopanic; - -/// Basic trait for the `Box` type. -pub trait BoxTrait { - /// Creates a new `Box` with the given value. - /// - /// Allocates space in the boxed segment for the provided value - /// and returns a `Box` that points to it. - /// # Examples - /// - /// ``` - /// let x = 42; - /// let boxed_x = BoxTrait::new(x); - /// ``` - fn new(value: T) -> Box nopanic; - /// Unboxes the given `Box` and returns the wrapped value. - /// - /// # Examples - /// - /// ``` - /// let boxed = BoxTrait::new(42); - /// assert!(boxed.unbox() == 42); - /// ``` - fn unbox(self: Box) -> T nopanic; - /// Converts the given snapshot of a `Box` into a `Box` of a snapshot. - /// Useful for structures that aren't copyable. - /// - /// # Examples - /// - /// ``` - /// let snap_boxed_arr = @BoxTraits::new(array![1, 2, 3]); - /// let boxed_snap_arr = snap_boxed_arr.as_snapshot(); - /// let snap_arr = boxed_snap_arr.unbox(); - /// ``` - fn as_snapshot(self: @Box) -> Box<@T> nopanic; -} -pub impl BoxImpl of BoxTrait { - #[inline] - #[must_use] - fn new(value: T) -> Box nopanic { - into_box(value) - } - - #[inline] - #[must_use] - fn unbox(self: Box) -> T nopanic { - unbox(self) - } - - #[must_use] - fn as_snapshot(self: @Box) -> Box<@T> nopanic { - box_forward_snapshot(self) - } -} - -impl BoxDeref of crate::ops::Deref> { - /// The target type after dereferencing. - type Target = T; - /// Takes a `Box`, dereferences it, and returns a value of type `T`. - /// - /// # Examples - /// - /// ``` - /// let boxed_value: Box = BoxTrait::new(1); - /// let value: u32 = boxed_value.deref(); - /// assert!(value == 1); - /// ``` - fn deref(self: Box) -> T { - self.unbox() - } -} - -impl BoxDebug> of crate::fmt::Debug> { - /// Formats a `Box` type, allowing to print `Box` instances for debugging purposes. - /// Boxed values are prefixed with `&` when formatted. - /// - /// # Examples - /// - /// ``` - /// let boxed_value: Box = BoxTrait::new(1); - /// println!("{:?}", boxed_value); // Result will be `&1` - /// ``` - fn fmt(self: @Box, ref f: crate::fmt::Formatter) -> Result<(), crate::fmt::Error> { - write!(f, "&")?; - TDebug::fmt(self.as_snapshot().unbox(), ref f) - } -} diff --git a/corelib/src/byte_array.cairo b/corelib/src/byte_array.cairo deleted file mode 100644 index 42508f9a0a..0000000000 --- a/corelib/src/byte_array.cairo +++ /dev/null @@ -1,1408 +0,0 @@ -//! `ByteArray` is designed to handle large sequences of bytes with operations like appending, -//! concatenation, and accessing individual bytes. It uses a structure that combines an `Array` of -//! `bytes31` for full words and a `felt252` for handling partial words, optimizing for both space -//! and performance. -//! -//! # Examples -//! -//! There are multiple ways to create a new `ByteArray`: -//! - From a string literal: -//! -//! ``` -//! let s = "Hello"; -//! ``` -//! -//! - Using the `format!` macro: -//! -//! ``` -//! let max_tps:u16 = 850; -//! let s = format!("Starknet's max TPS is: {}", max_tps); -//! ``` -//! -//! You can append bytes to an existing `ByteArray` with [`ByteArrayTrait::append_byte`]: -//! -//! ``` -//! let mut ba: ByteArray = ""; -//! ba.append_byte(0x41); // Appending a single byte 'A' -//! ``` -//! -//! You can create a new `ByteArray` from an existing one by concatenating with -//! `+`: -//! -//! ``` -//! let s = "Hello"; -//! let message = s + " world!"; -//! ``` -//! -//! Indexing operations are available on the `ByteArray` type as well: -//! -//! ``` -//! let mut ba: ByteArray = "ABC"; -//! let first_byte = ba[0] -//! assert!(first_byte == 0x41); -//! ``` - -use crate::array::{ArrayTrait, Span, SpanIter, SpanTrait}; -#[allow(unused_imports)] -use crate::bytes_31::{ - BYTES_IN_BYTES31, Bytes31Trait, POW_2_128, POW_2_8, U128IntoBytes31, U8IntoBytes31, - one_shift_left_bytes_u128, split_u128, u8_at_u256, -}; -use crate::clone::Clone; -use crate::cmp::min; -#[allow(unused_imports)] -use crate::integer::{U32TryIntoNonZero, u128_safe_divmod}; -#[feature("bounded-int-utils")] -use crate::internal::bounded_int::{self, BoundedInt, downcast, upcast}; -use crate::num::traits::CheckedSub; -#[allow(unused_imports)] -use crate::serde::Serde; -use crate::traits::{Into, TryInto}; -#[allow(unused_imports)] -use crate::zeroable::NonZeroIntoImpl; - -/// The number of bytes in [`ByteArray::pending_word`]. -type Bytes31Index = BoundedInt<0, { BYTES_IN_BYTES31_MINUS_ONE.into() }>; - -/// A magic constant for identifying serialization of `ByteArray` variables. An array of `felt252` -/// with this magic value as one of the `felt252` values indicates that a serialized `ByteArray` -/// should be expected immediately after it. This is currently used mainly for prints and panics. -pub const BYTE_ARRAY_MAGIC: felt252 = - 0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3; -const BYTES_IN_U128: usize = 16; -const BYTES_IN_BYTES31_MINUS_ONE: usize = BYTES_IN_BYTES31 - 1; - -/// Byte array type. -#[derive(Drop, Clone, PartialEq)] -pub struct ByteArray { - /// An array of full "words" of 31 bytes each. - /// The first byte of each word in the byte array is the most significant byte in the word. - pub(crate) data: Array, - /// A `felt252` that actually represents a `bytes31`, with fewer than 31 bytes. - /// It is represented as a `felt252` to improve performance when building the byte array. - /// The first byte is the most significant byte among the `pending_word_len` bytes in the word. - pub(crate) pending_word: felt252, - /// The number of bytes in `pending_word`. - /// Its value should be in the range [0, 30]. - pub(crate) pending_word_len: Bytes31Index, -} -impl ByteArrayDefault of Default { - fn default() -> ByteArray { - ByteArray { data: Default::default(), pending_word: 0, pending_word_len: 0 } - } -} -impl ByteArraySerde of Serde { - fn serialize(self: @ByteArray, ref output: Array) { - Serde::serialize(@self.data, ref output); - Serde::serialize(@self.pending_word, ref output); - Serde::serialize(@self.pending_word_len, ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - let data = Serde::deserialize(ref serialized)?; - let pending_word = Serde::deserialize(ref serialized)?; - let pending_word_len = Serde::deserialize(ref serialized)?; - if !is_valid_pending_word(pending_word, pending_word_len) { - return None; - } - Some(ByteArray { data, pending_word, pending_word_len }) - } -} - -pub(crate) impl ByteArrayStringLiteral of crate::string::StringLiteral; - -/// Functions associated with the `ByteArray` type. -#[generate_trait] -pub impl ByteArrayImpl of ByteArrayTrait { - /// Appends a single word of `len` bytes to the end of the `ByteArray`. - /// - /// This function assumes that: - /// 1. `word` could be validly converted to a `bytes31` which has no more than `len` bytes - /// of data. - /// 2. len <= BYTES_IN_BYTES31. - /// - /// If these assumptions are not met, it can corrupt the `ByteArray`. Thus, this should be a - /// private function. We could add masking/assertions, but it would be more expensive. - /// - /// # Examples - /// - /// ``` - /// let mut ba = ""; - /// ba.append_word('word', 4); - /// assert!(ba == "word"); - /// ``` - fn append_word(ref self: ByteArray, word: felt252, len: usize) { - let crate::internal::OptionRev::Some(len) = bounded_int::trim_min(len) else { - return; - }; - match downcast(len) { - Some(len) => self.append_word_ex(word, len), - None => crate::panic_with_felt252('bad append len'), - } - } - - /// Appends a `ByteArray` to the end of another `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// let mut ba: ByteArray = "1"; - /// ba.append(@"2"); - /// assert!(ba == "12"); - /// ``` - fn append(ref self: ByteArray, other: @ByteArray) { - self.append_from_parts(other.data.span(), other.pending_word, other.pending_word_len); - } - - /// Concatenates two `ByteArray`s and returns the result. - /// - /// The content of `left` is cloned in a new memory segment. - /// # Examples - /// - /// ``` - /// let ba = "1"; - /// let other_ba = "2"; - /// let result = ByteArrayTrait::concat(@ba, @other_ba); - /// assert!(result == "12"); - /// ``` - fn concat(left: @ByteArray, right: @ByteArray) -> ByteArray { - let mut result = left.clone(); - result.append(right); - result - } - - /// Appends a single byte to the end of the `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// let mut ba = ""; - /// ba.append_byte('A'); - /// assert!(ba == "A"); - /// ``` - fn append_byte(ref self: ByteArray, byte: u8) { - if self.pending_word_len == 0 { - self.pending_word = byte.into(); - self.pending_word_len = 1; - return; - } - - let new_pending = self.pending_word * POW_2_8.into() + byte.into(); - - if let Some(pending_word_len) = helpers::byte31_index_inc(self.pending_word_len) { - self.pending_word = new_pending; - self.pending_word_len = pending_word_len; - return; - } - - // self.pending_word_len == 30 - self.append_bytes31(new_pending); - self.pending_word = 0; - self.pending_word_len = 0; - } - - /// Returns the length of the `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = "byte array"; - /// let len = ba.len(); - /// assert!(len == 10); - /// ``` - #[must_use] - fn len(self: @ByteArray) -> usize { - helpers::calc_bytearray_len(self) - } - - /// Returns the byte at the given index of `self`, or `None` if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = "byte array"; - /// let byte = ba.at(0).unwrap(); - /// assert!(byte == 98); - /// ``` - fn at(self: @ByteArray, index: usize) -> Option { - let (word_index, index_in_word) = len_parts(index); - let index_in_word: usize = upcast(index_in_word); - if word_index == self.data.len() { - // Index is in pending word. - if index_in_word >= upcast(self.pending_word_len) { - return None; - } - // index_in_word is from MSB, we need index from LSB. - return Some( - u8_at_u256( - (self.pending_word).into(), upcast(self.pending_word_len) - 1 - index_in_word, - ), - ); - } - - let data_word: bytes31 = *self.data.get(word_index)?.deref(); - // index_in_word is from MSB, we need index from LSB. - Some(data_word.at(BYTES_IN_BYTES31 - 1 - index_in_word)) - } - - /// Returns a `ByteArray` with the reverse order of `self`. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = "123"; - /// let rev_ba = ba.rev(); - /// assert!(rev_ba == "321"); - /// ``` - fn rev(self: @ByteArray) -> ByteArray { - let mut result = Default::default(); - - result.append_word_rev(self.pending_word, upcast(self.pending_word_len)); - - let mut data = self.data.span(); - while let Some(current_word) = data.pop_back() { - result.append_word_rev((*current_word).into(), BYTES_IN_BYTES31); - } - result - } - - /// Appends the reverse of the given word to the end of `self`. - /// - /// This function assumes that: - /// 1. len < 31 - /// 2. word is validly convertible to bytes31 of length `len`. - /// - /// # Examples - /// - /// ``` - /// let mut ba: ByteArray = ""; - /// ba.append_word_rev('123', 3); - /// assert!(ba == "321"); - /// ``` - fn append_word_rev(ref self: ByteArray, word: felt252, len: usize) { - let mut index = 0; - - let u256 { low, high } = word.into(); - let low_part_limit = min(len, BYTES_IN_U128); - loop { - if index == low_part_limit { - break; - } - self.append_byte(core::bytes_31::get_lsb(split_u128(low, index).high)); - index += 1; - } - if low_part_limit == BYTES_IN_U128 { - let mut index_in_high_part = 0; - let high_part_len = len - BYTES_IN_U128; - loop { - if index_in_high_part == high_part_len { - break; - } - self - .append_byte( - core::bytes_31::get_lsb(split_u128(high, index_in_high_part).high), - ); - index_in_high_part += 1; - } - } - } -} -/// Internal functions associated with the `ByteArray` type. -#[generate_trait] -impl InternalImpl of InternalTrait { - /// Internal implementation of `ByteArrayTrait::append_word`. - fn append_word_ex(ref self: ByteArray, word: felt252, len: BoundedInt<1, 31>) { - // The split index is the number of bytes left for the next word (new pending_word of the - // modified ByteArray). - let split_index = match helpers::append_word_info(self.pending_word_len, len) { - helpers::AppendWordInfo::InPending(pending_word_len) => { - self.pending_word = word + self.pending_word * pow256_felt252(len); - self.pending_word_len = pending_word_len; - return; - }, - helpers::AppendWordInfo::FilledPending(split_index) => split_index, - }; - - let shift_value = self.shift_value(); - let to_append = split_bytes31(word, split_index); - self.append_shifted(to_append, shift_value); - self.pending_word_len = split_index; - } - - /// Appends a split word to the end of `self`. - /// - /// `value` is the value to add to the byte array, including `high` and `low`. - /// `shift_value` is the shift for `self.pending_word`, before it is joined by the `high` part - /// of `value`. - /// - /// Note: this function doesn't update the new pending length of `self`. It's the caller's - /// responsibility. - #[inline] - fn append_shifted(ref self: ByteArray, value: U256Split, shift_value: felt252) { - self.append_bytes31(value.high + self.pending_word * shift_value); - self.pending_word = value.low; - } - - /// The value to shift the current pending word to add the remaining bytes to it. - #[inline] - fn shift_value(ref self: ByteArray) -> felt252 { - match self.pending_word_len { - 30 => 0x100, - 29 => 0x10000, - 28 => 0x1000000, - 27 => 0x100000000, - 26 => 0x10000000000, - 25 => 0x1000000000000, - 24 => 0x100000000000000, - 23 => 0x10000000000000000, - 22 => 0x1000000000000000000, - 21 => 0x100000000000000000000, - 20 => 0x10000000000000000000000, - 19 => 0x1000000000000000000000000, - 18 => 0x100000000000000000000000000, - 17 => 0x10000000000000000000000000000, - 16 => 0x1000000000000000000000000000000, - 15 => 0x100000000000000000000000000000000, - 14 => 0x10000000000000000000000000000000000, - 13 => 0x1000000000000000000000000000000000000, - 12 => 0x100000000000000000000000000000000000000, - 11 => 0x10000000000000000000000000000000000000000, - 10 => 0x1000000000000000000000000000000000000000000, - 9 => 0x100000000000000000000000000000000000000000000, - 8 => 0x10000000000000000000000000000000000000000000000, - 7 => 0x1000000000000000000000000000000000000000000000000, - 6 => 0x100000000000000000000000000000000000000000000000000, - 5 => 0x10000000000000000000000000000000000000000000000000000, - 4 => 0x1000000000000000000000000000000000000000000000000000000, - 3 => 0x100000000000000000000000000000000000000000000000000000000, - 2 => 0x10000000000000000000000000000000000000000000000000000000000, - 1 => 0x1000000000000000000000000000000000000000000000000000000000000, - 0 => 0x100000000000000000000000000000000000000000000000000000000000000, - _ => crate::panic_with_felt252('unreachable - no code generated'), - } - } - - /// Appends a `felt252` value assumed to be `bytes31`. - /// - /// Will append an error value in cases of invalid usage in order to avoid panic code. - fn append_bytes31(ref self: ByteArray, value: felt252) { - const ON_ERR: bytes31 = 'BA_ILLEGAL_USAGE'_u128.into(); - self.data.append(value.try_into().unwrap_or(ON_ERR)); - } - - /// Appends the `data` span and `pending_word` fields to the byte array. - #[inline] - fn append_from_parts( - ref self: ByteArray, - mut data: Span, - pending_word: felt252, - pending_word_len: Bytes31Index, - ) { - let Some(curr_pending_word_len) = helpers::index_non_zero(self.pending_word_len) else { - self.data.append_span(data); - self.pending_word = pending_word; - self.pending_word_len = pending_word_len; - return; - }; - let shift_value = self.shift_value(); - // self.pending_word_len is in [1, 30]. This is the split index for all the full words of - // `other`, as for each word, this is the number of bytes left for the next word. - match split_info(curr_pending_word_len) { - SplitInfo::Eq16(v) => { - while let Some(word) = data.pop_front() { - self.append_shifted(v.split_u256((*word).into()), shift_value); - } - }, - SplitInfo::Lt16(v) => { - while let Some(word) = data.pop_front() { - self.append_shifted(v.split_u256((*word).into()), shift_value); - } - }, - SplitInfo::Gt16(v) => { - while let Some(word) = data.pop_front() { - self.append_shifted(v.split_u256((*word).into()), shift_value); - } - }, - } - // Add the pending word of `other`. - if let Some(pending_word_len) = helpers::index_non_zero(pending_word_len) { - self.append_word_ex(pending_word, upcast(pending_word_len)); - } - } -} - -/// The value of a `u256` split into two parts at an index. -struct U256Split { - /// The higher part of the split. - high: felt252, - /// The lower part of the split. - low: felt252, -} - -/// Information for splitting a felt252 into 2 parts at an index. -enum SplitInfo { - /// The index is 16. - Eq16: Eq16SplitInfo, - /// The index is less than 16. - Lt16: Lt16SplitInfo, - /// The index is more than 16. - Gt16: Gt16SplitInfo, -} - -/// Helper struct for splitting a number at the 16th byte. -#[derive(Copy, Drop)] -struct Eq16SplitInfo {} - -/// Helper struct for splitting a number at an index lower than the 16th byte. -#[derive(Copy, Drop)] -struct Lt16SplitInfo { - /// The division value to extract the low word parts. - low_div: NonZero, - /// The shift value to mix the high word and the low word high part. - high_shift: felt252, -} - -/// Helper struct for splitting a number at an index greater than the 16th byte. -#[derive(Copy, Drop)] -struct Gt16SplitInfo { - /// The division value to extract the high word parts. - high_div: NonZero, -} - -trait SplitValue { - /// Splits a u256 into a `U256Split` according to the info on the split index. - fn split_u256(self: T, v: u256) -> U256Split; -} - -impl Lt16SplitInfoSplitValue of SplitValue { - fn split_u256(self: Lt16SplitInfo, v: u256) -> U256Split { - let (low_high, low_low) = DivRem::div_rem(v.low, self.low_div); - U256Split { high: v.high.into() * self.high_shift + low_high.into(), low: low_low.into() } - } -} - -impl Eq16SplitInfoSplitValue of SplitValue { - fn split_u256(self: Eq16SplitInfo, v: u256) -> U256Split { - U256Split { high: v.high.into(), low: v.low.into() } - } -} - -impl Gt16SplitInfoSplitValue of SplitValue { - fn split_u256(self: Gt16SplitInfo, v: u256) -> U256Split { - let (high_high, high_low) = DivRem::div_rem(v.high, self.high_div); - U256Split { high: high_high.into(), low: high_low.into() * POW_2_128 + v.low.into() } - } -} - -/// Extracts the split info from the given index. -fn split_info(split_index: BoundedInt<1, 30>) -> SplitInfo { - match helpers::nz_index_minus_one(split_index) { - 0 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x100, high_shift: 0x1000000000000000000000000000000 }, - ), - 1 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x10000, high_shift: 0x10000000000000000000000000000 }, - ), - 2 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x1000000, high_shift: 0x100000000000000000000000000 }, - ), - 3 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x100000000, high_shift: 0x1000000000000000000000000 }, - ), - 4 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x10000000000, high_shift: 0x10000000000000000000000 }, - ), - 5 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x1000000000000, high_shift: 0x100000000000000000000 }, - ), - 6 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x100000000000000, high_shift: 0x1000000000000000000 }, - ), - 7 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x10000000000000000, high_shift: 0x10000000000000000 }, - ), - 8 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x1000000000000000000, high_shift: 0x100000000000000 }, - ), - 9 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x100000000000000000000, high_shift: 0x1000000000000 }, - ), - 10 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x10000000000000000000000, high_shift: 0x10000000000 }, - ), - 11 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x1000000000000000000000000, high_shift: 0x100000000 }, - ), - 12 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x100000000000000000000000000, high_shift: 0x1000000 }, - ), - 13 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x10000000000000000000000000000, high_shift: 0x10000 }, - ), - 14 => SplitInfo::Lt16( - Lt16SplitInfo { low_div: 0x1000000000000000000000000000000, high_shift: 0x100 }, - ), - 15 => SplitInfo::Eq16(Eq16SplitInfo {}), - 16 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x100 }), - 17 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x10000 }), - 18 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x1000000 }), - 19 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x100000000 }), - 20 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x10000000000 }), - 21 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x1000000000000 }), - 22 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x100000000000000 }), - 23 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x10000000000000000 }), - 24 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x1000000000000000000 }), - 25 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x100000000000000000000 }), - 26 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x10000000000000000000000 }), - 27 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x1000000000000000000000000 }), - 28 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x100000000000000000000000000 }), - 29 => SplitInfo::Gt16(Gt16SplitInfo { high_div: 0x10000000000000000000000000000 }), - _ => crate::panic_with_felt252('unreachable - no code generated'), - } -} - -/// Returns `2^n` as `felt252`. -fn pow256_felt252(n: BoundedInt<1, 31>) -> felt252 { - // Matching on `n - 1` so we'd get a continuous match starting from 0, which is more efficient. - match helpers::nz_length_minus_one(n) { - 0 => 0x100, - 1 => 0x10000, - 2 => 0x1000000, - 3 => 0x100000000, - 4 => 0x10000000000, - 5 => 0x1000000000000, - 6 => 0x100000000000000, - 7 => 0x10000000000000000, - 8 => 0x1000000000000000000, - 9 => 0x100000000000000000000, - 10 => 0x10000000000000000000000, - 11 => 0x1000000000000000000000000, - 12 => 0x100000000000000000000000000, - 13 => 0x10000000000000000000000000000, - 14 => 0x1000000000000000000000000000000, - 15 => 0x100000000000000000000000000000000, - 16 => 0x10000000000000000000000000000000000, - 17 => 0x1000000000000000000000000000000000000, - 18 => 0x100000000000000000000000000000000000000, - 19 => 0x10000000000000000000000000000000000000000, - 20 => 0x1000000000000000000000000000000000000000000, - 21 => 0x100000000000000000000000000000000000000000000, - 22 => 0x10000000000000000000000000000000000000000000000, - 23 => 0x1000000000000000000000000000000000000000000000000, - 24 => 0x100000000000000000000000000000000000000000000000000, - 25 => 0x10000000000000000000000000000000000000000000000000000, - 26 => 0x1000000000000000000000000000000000000000000000000000000, - 27 => 0x100000000000000000000000000000000000000000000000000000000, - 28 => 0x10000000000000000000000000000000000000000000000000000000000, - 29 => 0x1000000000000000000000000000000000000000000000000000000000000, - 30 => 0x100000000000000000000000000000000000000000000000000000000000000, - _ => crate::panic_with_felt252('unreachable - no code generated'), - } -} - -/// Validates that the data in a word is at most the given length. -pub(crate) fn is_valid_pending_word(word: felt252, len: Bytes31Index) -> bool { - let data: u256 = word.into(); - let bound: u256 = match len { - 0 => 0x1, - 1 => 0x100, - 2 => 0x10000, - 3 => 0x1000000, - 4 => 0x100000000, - 5 => 0x10000000000, - 6 => 0x1000000000000, - 7 => 0x100000000000000, - 8 => 0x10000000000000000, - 9 => 0x1000000000000000000, - 10 => 0x100000000000000000000, - 11 => 0x10000000000000000000000, - 12 => 0x1000000000000000000000000, - 13 => 0x100000000000000000000000000, - 14 => 0x10000000000000000000000000000, - 15 => 0x1000000000000000000000000000000, - 16 => 0x100000000000000000000000000000000, - 17 => 0x10000000000000000000000000000000000, - 18 => 0x1000000000000000000000000000000000000, - 19 => 0x100000000000000000000000000000000000000, - 20 => 0x10000000000000000000000000000000000000000, - 21 => 0x1000000000000000000000000000000000000000000, - 22 => 0x100000000000000000000000000000000000000000000, - 23 => 0x10000000000000000000000000000000000000000000000, - 24 => 0x1000000000000000000000000000000000000000000000000, - 25 => 0x100000000000000000000000000000000000000000000000000, - 26 => 0x10000000000000000000000000000000000000000000000000000, - 27 => 0x1000000000000000000000000000000000000000000000000000000, - 28 => 0x100000000000000000000000000000000000000000000000000000000, - 29 => 0x10000000000000000000000000000000000000000000000000000000000, - 30 => 0x1000000000000000000000000000000000000000000000000000000000000, - _ => crate::panic_with_felt252('unreachable - no code generated'), - }; - data < bound -} - -impl ByteArrayAdd of Add { - /// Concatenates two `ByteArray` and returns the resulting `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = "1"; - /// let other_ba: ByteArray = "2"; - /// let result = ba + other_ba; - /// assert!(result == "12") - /// ``` - #[inline] - fn add(lhs: ByteArray, rhs: ByteArray) -> ByteArray { - ByteArrayTrait::concat(@lhs, @rhs) - } -} - -#[feature("deprecated-op-assign-traits")] -impl ByteArrayAddEq of crate::traits::AddEq { - /// Appends a `ByteArray` to another `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// let mut ba: ByteArray = "1"; - /// let other_ba: ByteArray = "2"; - /// ba += other_ba; - /// assert!(ba == "12"); - /// ``` - #[inline] - fn add_eq(ref self: ByteArray, other: ByteArray) { - self.append(@other); - } -} - -#[feature("deprecated-index-traits")] -pub(crate) impl ByteArrayIndexView of crate::traits::IndexView { - fn index(self: @ByteArray, index: usize) -> u8 { - self.at(index).expect('Index out of bounds') - } -} - -/// An iterator struct over a ByteArray. -#[derive(Drop, Clone)] -pub struct ByteArrayIter { - inner: ByteSpanIter, -} - -impl ByteArrayIterator of crate::iter::Iterator { - type Item = u8; - - fn next(ref self: ByteArrayIter) -> Option { - self.inner.next() - } -} - -impl ByteArrayIntoIterator of crate::iter::IntoIterator { - type IntoIter = ByteArrayIter; - fn into_iter(self: ByteArray) -> Self::IntoIter { - ByteArrayIter { inner: self.span().into_iter() } - } -} - -impl ByteArrayFromIterator of crate::iter::FromIterator { - fn from_iter< - I, - impl IntoIter: IntoIterator, - +core::metaprogramming::TypeEqual, - +Destruct, - +Destruct, - >( - iter: I, - ) -> ByteArray { - let mut ba = Default::default(); - for byte in iter { - ba.append_byte(byte); - } - ba - } -} - -/// A view into a contiguous collection of a string type. -/// Currently implemented only for `ByteArray`, but will soon be implemented for other string types. -/// `Span` implements the `Copy` and the `Drop` traits. -#[derive(Copy, Drop)] -pub struct ByteSpan { - /// A span representing the array of all `bytes31` words in the byte-span, excluding the last - /// bytes_31 word that is stored in [Self::last_word]. - /// Invariant: every byte stored in `data` is part of the span except for the bytes appearing - /// before `first_char_start_offset` in the first word. - data: Span, - /// The offset of the first character in the first entry of [Self::data], for use in span - /// slices. When data is empty, this offset applies to remainder_word instead. - first_char_start_offset: Bytes31Index, - /// Contains the final bytes of the span when the end is either not in memory or isn't aligned - /// to a word boundary. - /// It is represented as a `felt252` to improve the performance of building the byte array, but - /// represents a `bytes31`. - /// The first byte is the most significant byte among the `pending_word_len` bytes in the word. - remainder_word: felt252, - /// The number of bytes in [Self::remainder_word]. - remainder_len: Bytes31Index, -} - - -#[generate_trait] -pub impl ByteSpanImpl of ByteSpanTrait { - /// Returns the length of the `ByteSpan`. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = "byte array"; - /// let span = ba.span(); - /// let len = span.len(); - /// assert!(len == 10); - /// ``` - #[must_use] - fn len(self: ByteSpan) -> usize { - helpers::calc_bytespan_len(self) - } - - /// Returns `true` if the `ByteSpan` has a length of 0. - /// - /// # Examples - /// - /// ``` - /// let ba: ByteArray = ""; - /// let span = ba.span(); - /// assert!(span.is_empty()); - /// - /// let ba2: ByteArray = "not empty"; - /// let span2 = ba2.span(); - /// assert!(!span2.is_empty()); - /// ``` - fn is_empty(self: ByteSpan) -> bool { - // No need to check offsets: when `slice` consumes the span it returns `Default::default()`. - self.remainder_len == 0 && self.data.len() == 0 - } - - /// Converts a `ByteSpan` into a `ByteArray`. - /// The cast includes trimming the start offset of the first word of the span (which is created - /// when slicing). - /// - /// Note: creating `ByteArray.data` from `Span` requires allocating a new memory - /// segment for the returned array, and *O*(*n*) operations to populate the array with the - /// content of the span (see also `SpanIntoArray`). - fn to_byte_array(mut self: ByteSpan) -> ByteArray { - let Some(first_word) = self.data.pop_front() else { - // Slice is included entirely in the remainder word. - let Some(pending_word_len) = helpers::index_checked_sub( - self.remainder_len, self.first_char_start_offset, - ) else { - return Default::default(); - }; - let pending_word = split_bytes31(self.remainder_word, pending_word_len).low; - return ByteArray { data: array![], pending_word, pending_word_len }; - }; - - let mut ba = Default::default(); - if let Some(nz_start_offset) = helpers::index_non_zero(self.first_char_start_offset) { - let n_bytes_to_append = helpers::complement_to_31(nz_start_offset); - let first_word_no_offset = split_bytes31_nz((*first_word).into(), n_bytes_to_append) - .low; - ba.append_word_ex(first_word_no_offset, upcast(n_bytes_to_append)); - } else { - ba.data.append(*first_word); - } - // Append the rest of the span parts, now that the first word was popped. - ba.append_from_parts(self.data, self.remainder_word, self.remainder_len); - ba - } - - /// Gets the element(s) at the given index. - /// Accepts ranges (returns Option), and single indices (returns Option). - #[feature("corelib-get-trait")] - fn get, +Drop>( - self: @ByteSpan, index: I, - ) -> Option { - TGet::get(self, index) - } -} - -impl ByteSpanDefault of Default { - fn default() -> ByteSpan { - ByteSpan { - data: [].span(), first_char_start_offset: 0, remainder_word: 0, remainder_len: 0, - } - } -} - -impl ByteSpanPartialEq of PartialEq { - fn eq(lhs: @ByteSpan, rhs: @ByteSpan) -> bool { - if (*lhs).len() != (*rhs).len() { - return false; - } - let mut lhs_iter = (*lhs).into_iter(); - let mut rhs_iter = (*rhs).into_iter(); - loop { - match lhs_iter.next() { - Some(lhs_byte) => if Some(lhs_byte) != rhs_iter.next() { - break false; - }, - None => { break true; }, - } - } - } -} - - -impl ByteSpanGetRange of crate::ops::Get> { - type Output = ByteSpan; - - /// Returns a slice for the given range `[start, end)`. - /// If span is consumed by the slice: returns the default object. - /// If out of bounds: returns `None`. - fn get(self: @ByteSpan, index: crate::ops::Range) -> Option { - let range = index; - if range.start == range.end { - return Some(Default::default()); - } - if range.start > range.end { - return None; - } - let (start_word, start_offset) = helpers::index_parts_with_offset_b31( - range.start, self.first_char_start_offset, - ); - let (end_word, end_offset) = helpers::index_parts_with_offset_b31( - range.end, self.first_char_start_offset, - ); - let data_slice_len = end_word.checked_sub(start_word)?; - - let remainder_with_end_offset_trimmed = if self.data.len() == end_word { - let offset = helpers::index_checked_sub(self.remainder_len, end_offset)?; - split_bytes31(self.remainder_word, offset).high - } else { - let word = self.data.get(end_word)?; - if let Some(end_offset) = helpers::index_non_zero(end_offset) { - split_bytes31_nz((**word).into(), helpers::complement_to_31(end_offset)).high - } else { - 0 - } - }; - - Some( - ByteSpan { - data: self.data.slice(start_word, data_slice_len), - first_char_start_offset: start_offset, - remainder_word: remainder_with_end_offset_trimmed, - remainder_len: end_offset, - }, - ) - } -} - -impl ByteSpanGetRangeInclusive of crate::ops::Get> { - type Output = ByteSpan; - - /// Returns a slice for the given range `[start, end]`. - /// If span is consumed by the slice: returns the default object. - /// If out of bounds: returns `None`. - fn get(self: @ByteSpan, index: crate::ops::RangeInclusive) -> Option { - let end_exclusive = crate::num::traits::CheckedAdd::checked_add(index.end, 1)?; - ByteSpanTrait::get(self, index.start..end_exclusive) - } -} - -impl ByteSpanGetUsize of crate::ops::Get { - type Output = u8; - - /// Returns the byte at the given index. - /// If out of bounds: returns `None`. - fn get(self: @ByteSpan, index: usize) -> Option { - helpers::byte_at(self, index) - } -} - -#[feature("byte-span")] -impl ByteSpanIndexViewRange of crate::ops::IndexView> { - type Target = ByteSpan; - - fn index(self: @ByteSpan, index: crate::ops::Range) -> ByteSpan { - crate::ops::Get::get(self, index).expect('Index out of bounds') - } -} - -#[feature("byte-span")] -impl ByteSpanIndexViewRangeInclusive of crate::ops::IndexView< - ByteSpan, crate::ops::RangeInclusive, -> { - type Target = ByteSpan; - - fn index(self: @ByteSpan, index: crate::ops::RangeInclusive) -> ByteSpan { - crate::ops::Get::get(self, index).expect('Index out of bounds') - } -} - -impl ByteSpanIndex of core::ops::index::IndexView { - type Target = u8; - - fn index(self: @ByteSpan, index: usize) -> u8 { - ByteSpanTrait::get(self, index).expect('Index out of bounds') - } -} - -/// Trait for types that can be converted into a `ByteSpan`. -#[unstable(feature: "byte-span")] -pub trait ToByteSpanTrait { - #[must_use] - /// Create a `ByteSpan` view object for the given type. - fn span(self: @C) -> ByteSpan; -} - -#[feature("byte-span")] -impl ByteArrayToByteSpan of ToByteSpanTrait { - fn span(self: @ByteArray) -> ByteSpan { - ByteSpan { - data: self.data.span(), - first_char_start_offset: 0, - remainder_word: self.pending_word, - remainder_len: downcast(self.pending_word_len).expect('In [0,30] by assumption'), - } - } -} - -#[feature("byte-span")] -impl ByteSpanToByteSpan of ToByteSpanTrait { - fn span(self: @ByteSpan) -> ByteSpan { - *self - } -} - -/// An iterator struct over a ByteSpan. -#[derive(Drop, Clone)] -pub struct ByteSpanIter { - /// Iterator over the full words. - data_iter: SpanIter, - /// The word currently being iterated over. - current_word: ShortString, - /// The last, partial word of the ByteSpan, is iterated over after all full words are consumed. - remainder: ShortString, -} - -impl ByteSpanIterator of crate::iter::Iterator { - type Item = u8; - - fn next(ref self: ByteSpanIter) -> Option { - if let Some(byte) = self.current_word.pop_first() { - return Some(byte); - } - - // Current word exhausted, try loading the next into current word from data or remainder. - match self.data_iter.next() { - Some(word) => { self.current_word = ShortString { data: (*word).into(), len: 31 }; }, - // No more words in data, try loading the remainder. - None => { - self.current_word = self.remainder; - self.remainder.len = 0; // Mark remainder as consumed. - }, - } - - self.current_word.pop_first() - } -} - -impl ByteSpanIntoIterator of crate::iter::IntoIterator { - type IntoIter = ByteSpanIter; - - /// Creates an iterator over the bytes in the `ByteSpan`. - fn into_iter(self: ByteSpan) -> Self::IntoIter { - let mut data_iter = self.data.into_iter(); - - // Get first word in data array if it exists, otherwise iterate on the remainder word. - let Some(first_word) = data_iter.next() else { - // On an empty data span, the remainder length is greater than or equal to the start - // offset. - let len = - match helpers::length_sub_offset( - upcast(self.remainder_len), self.first_char_start_offset, - ) { - Some(len) => len, - // Can't actually happen, as start offset is at most the remainder length. - None => 0, - }; - - return ByteSpanIter { - data_iter, - current_word: ShortString { data: self.remainder_word, len }, - remainder: Default::default(), - }; - }; - - let len = upcast(helpers::complement_to_31(self.first_char_start_offset)); - - ByteSpanIter { - data_iter, - current_word: ShortString { data: (*first_word).into(), len }, - remainder: ShortString { data: self.remainder_word, len: upcast(self.remainder_len) }, - } - } -} - - -/// Shifts a word right by `n_bytes`. -/// The input `bytes31` and the output `bytes31`s are represented using `felt252`s to improve -/// performance. -/// -/// Note: this function assumes that: -/// 1. `word` is validly convertible to a `bytes31` which has no more than `len` bytes of data. -/// 2. `index <= len`. -/// If these assumptions are not met, it can corrupt the `bytes31`. Thus, this should be a -/// private function. We could add masking/assertions, but it would be more expensive. -fn split_bytes31(value: felt252, split_index: Bytes31Index) -> U256Split { - let Some(split_index) = helpers::index_non_zero(split_index) else { - return U256Split { high: value, low: 0 }; - }; - split_bytes31_nz(value, split_index) -} - -/// For testing purposes only, leftover from the old implementation. -#[cfg(test)] -pub(crate) fn split_bytes31_for_testing( - value: felt252, split_index: Bytes31Index, -) -> (felt252, felt252) { - let word = split_bytes31(value, split_index); - (word.low.into(), word.high.into()) -} - -/// Same as `split_bytes31`, but `split_index` is bound to not be zero. -fn split_bytes31_nz(value: felt252, split_index: BoundedInt<1, 30>) -> U256Split { - let as_u256: u256 = value.into(); - match split_info(split_index) { - SplitInfo::Eq16(v) => v.split_u256(as_u256), - SplitInfo::Lt16(v) => v.split_u256(as_u256), - SplitInfo::Gt16(v) => v.split_u256(as_u256), - } -} -/// Representation of a `felt252` holding a string up to size 31, including length. -#[derive(Drop, Copy)] -struct ShortString { - /// The actual data. - data: felt252, - /// The actual length of the short string in bytes. - len: BoundedInt<0, 31>, -} - -#[generate_trait] -impl ShortStringImpl of ShortStringTrait { - /// Removes and returns the first byte from the string if it exists. - fn pop_first(ref self: ShortString) -> Option { - let len = helpers::length_non_zero(self.len)?; - let byte_position = helpers::nz_length_minus_one(len); - - // Strings are indexed by lsb, so the first char is at position (byte_count - 1). - let byte = u8_at_u256(self.data.into(), upcast(byte_position)); - - self.len = upcast(byte_position); - Some(byte) - } -} - -impl ShortStringDefault of Default { - fn default() -> ShortString { - ShortString { data: 0, len: 0 } - } -} - -mod helpers { - use core::num::traits::Bounded; - use crate::bytes_31::{BYTES_IN_BYTES31, Bytes31Trait, u8_at_u256}; - #[feature("bounded-int-utils")] - use crate::internal::bounded_int::{ - self, AddHelper, BoundedInt, ConstrainHelper, DivRemHelper, MulHelper, SubHelper, UnitInt, - downcast, upcast, - }; - use super::{BYTES_IN_BYTES31_MINUS_ONE, ByteSpan, Bytes31Index}; - - type BytesInBytes31Typed = UnitInt<{ BYTES_IN_BYTES31.into() }>; - - const U32_MAX_TIMES_B31: felt252 = Bounded::::MAX.into() * BYTES_IN_BYTES31.into(); - const BYTES_IN_BYTES31_UNIT_INT: BytesInBytes31Typed = downcast(BYTES_IN_BYTES31).unwrap(); - const NZ_BYTES_IN_BYTES31: NonZero = 31; - const BYTES_IN_BYTES31_MINUS_ONE_TYPED: UnitInt<{ BYTES_IN_BYTES31_MINUS_ONE.into() }> = 30; - const ONE_TYPED: UnitInt<1> = 1; - - impl U32ByB31 of MulHelper { - type Result = BoundedInt<0, U32_MAX_TIMES_B31>; - } - - impl B30AddU32ByB31 of AddHelper { - type Result = BoundedInt<0, { BYTES_IN_BYTES31_MINUS_ONE.into() + U32_MAX_TIMES_B31 }>; - } - - impl B30AddU32ByB31SubB30 of SubHelper { - type Result = - BoundedInt< - { -BYTES_IN_BYTES31_MINUS_ONE.into() }, - { BYTES_IN_BYTES31_MINUS_ONE.into() + U32_MAX_TIMES_B31 }, - >; - } - - // For byte_at: usize + BoundedInt<0,30> - impl UsizeAddBytes31Index of AddHelper { - type Result = - BoundedInt<0, { Bounded::::MAX.into() + BYTES_IN_BYTES31_MINUS_ONE.into() }>; - } - - // For byte_at: div_rem of (usize + BoundedInt<0,30>) by 31 - const USIZE_PLUS_30_DIV_31: felt252 = (Bounded::::MAX / 31 + 1).into(); - impl UsizePlusBytes31IndexDivRemB31 of DivRemHelper< - UsizeAddBytes31Index::Result, BytesInBytes31Typed, - > { - type DivT = BoundedInt<0, USIZE_PLUS_30_DIV_31>; - type RemT = Bytes31Index; - } - - // For byte_at: 30 - BoundedInt<0,30> - impl B30SubBytes31Index of SubHelper< - UnitInt<{ BYTES_IN_BYTES31_MINUS_ONE.into() }>, Bytes31Index, - > { - type Result = Bytes31Index; - } - - // For byte_at: BoundedInt<0,30> - 1 - impl Bytes31IndexSub1 of SubHelper> { - type Result = BoundedInt<-1, { BYTES_IN_BYTES31_MINUS_ONE.into() - 1 }>; - } - - // For byte_at: (BoundedInt<0,30> - 1) - BoundedInt<0,30> - impl Bytes31IndexMinus1SubBytes31Index of SubHelper { - type Result = - BoundedInt< - { -BYTES_IN_BYTES31_MINUS_ONE.into() - 1 }, - { BYTES_IN_BYTES31_MINUS_ONE.into() - 1 }, - >; - } - - // For byte_at: split BoundedInt<-31, 29> at 0. - impl ConstrainRemainderIndexAt0 of bounded_int::ConstrainHelper< - Bytes31IndexMinus1SubBytes31Index::Result, 0, - > { - type LowT = BoundedInt<{ -BYTES_IN_BYTES31_MINUS_ONE.into() - 1 }, -1>; - type HighT = BoundedInt<0, { BYTES_IN_BYTES31_MINUS_ONE.into() - 1 }>; - } - - /// Calculates the length of a `ByteSpan` in bytes. - pub fn calc_bytespan_len(span: ByteSpan) -> usize { - let data_bytes = bounded_int::mul(span.data.len(), BYTES_IN_BYTES31_UNIT_INT); - let span_bytes_unadjusted = bounded_int::add(span.remainder_len, data_bytes); - let span_bytes = bounded_int::sub(span_bytes_unadjusted, span.first_char_start_offset); - - downcast(span_bytes).unwrap() - } - - /// Calculates the length of a `ByteSpan` in bytes. - pub fn calc_bytearray_len(arr: @ByteArray) -> usize { - let data_bytes = bounded_int::mul(arr.data.len(), BYTES_IN_BYTES31_UNIT_INT); - let arr_bytes = bounded_int::add(arr.pending_word_len, data_bytes); - - downcast(arr_bytes).unwrap() - } - - impl DivRemU32ByB31 of bounded_int::DivRemHelper { - type DivT = BoundedInt<0, 0x8421084>; - type RemT = Bytes31Index; - } - - /// Returns the length of a `ByteArray` in full words and additional bytes in the pending word. - pub fn len_parts(length: usize) -> (usize, Bytes31Index) { - let (div, rem) = bounded_int::div_rem::<_, _, DivRemU32ByB31>(length, 31); - (upcast(div), rem) - } - /// Splits `index` (relative to `start_offset`) into a word index (divided by 31) and the byte - /// offset within that word. - pub fn index_parts_with_offset_b31( - index: usize, start_offset: Bytes31Index, - ) -> (usize, Bytes31Index) { - let absolute_index = bounded_int::add(index, start_offset); - let (word_idx_bounded, byte_offset) = bounded_int::div_rem( - absolute_index, NZ_BYTES_IN_BYTES31, - ); - (upcast(word_idx_bounded), byte_offset) - } - - impl TrimMaxBytes31Index of bounded_int::TrimMaxHelper { - type Target = BoundedInt<0, 29>; - } - impl AddBytes31Index of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 30>; - } - - /// Increments the index by one, or returns `None` if not in range. - pub fn byte31_index_inc(index: Bytes31Index) -> Option { - if let crate::internal::OptionRev::Some(trimmed) = bounded_int::trim_max(index) { - Some(upcast(bounded_int::add(trimmed, 1))) - } else { - None - } - } - - impl TrimMinShortStringCount of bounded_int::TrimMinHelper> { - type Target = BoundedInt<1, 31>; - } - - /// Returns the length if it is not zero, or `None` if it is. - pub fn length_non_zero(length: BoundedInt<0, 31>) -> Option> { - match bounded_int::trim_min(length) { - crate::internal::OptionRev::Some(trimmed) => Some(trimmed), - crate::internal::OptionRev::None => None, - } - } - - impl B31SubOffset of SubHelper, Bytes31Index> { - type Result = BoundedInt<-30, 31>; - } - - impl ConstrainB31SubOffsetPos of ConstrainHelper { - type LowT = BoundedInt<-30, -1>; - type HighT = BoundedInt<0, 31>; - } - - /// Subtracts `offset` from `length`, assumes `offset < length`. - pub fn length_sub_offset( - length: BoundedInt<0, 31>, offset: Bytes31Index, - ) -> Option> { - let diff = bounded_int::sub(length, offset); - bounded_int::constrain::<_, 0>(diff).err() - } - - /// The information about the new pending word length and the split index. - pub enum AppendWordInfo { - /// The new pending word length is less than 31, and fits in the current pending word. - InPending: Bytes31Index, - /// The new pending word length is greater than 31, and the current pending word is filled. - FilledPending: Bytes31Index, - } - - impl Bytes31IndexAdd of AddHelper> { - type Result = BoundedInt<1, 61>; - } - impl Constrain31Bytes31IndexAddResult of ConstrainHelper { - type LowT = BoundedInt<1, 30>; - type HighT = BoundedInt<31, 61>; - } - impl Sub31Bytes31IndexAddResult of SubHelper, BytesInBytes31Typed> { - type Result = Bytes31Index; - } - - /// Returns the information about the new pending word length and the split index. - pub fn append_word_info( - pending_bytes: Bytes31Index, new_word_bytes: BoundedInt<1, 31>, - ) -> AppendWordInfo { - let total_pending_bytes = bounded_int::add(pending_bytes, new_word_bytes); - match bounded_int::constrain::<_, 31>(total_pending_bytes) { - Ok(lt31) => AppendWordInfo::InPending(upcast(lt31)), - Err(ge31) => AppendWordInfo::FilledPending( - bounded_int::sub(ge31, BYTES_IN_BYTES31_UNIT_INT), - ), - } - } - - /// Impl for trimming the minimum value of a `Bytes31Index`. - impl TrimMinBytes31Index of bounded_int::TrimMinHelper { - type Target = BoundedInt<1, 30>; - } - - /// Returns the index if it is not zero, or `None` if it is. - #[inline(always)] - pub fn index_non_zero(index: Bytes31Index) -> Option> { - match bounded_int::trim_min::<_, TrimMinBytes31Index>(index) { - crate::internal::OptionRev::Some(index) => Some(index), - crate::internal::OptionRev::None => None, - } - } - - impl MinusOneBounded1To31 of SubHelper, UnitInt<1>> { - type Result = Bytes31Index; - } - - /// Returns the length minus one. - pub fn nz_length_minus_one(len: BoundedInt<1, 31>) -> Bytes31Index { - bounded_int::sub(len, 1) - } - - /// Returns the byte at the given index in the ByteSpan. - /// If out of bounds: returns `None`. - pub fn byte_at(self: @ByteSpan, index: usize) -> Option { - let (word_index, msb_index) = index_parts_with_offset_b31( - index, self.first_char_start_offset, - ); - - match self.data.get(word_index) { - Some(word) => { - // Convert from MSB to LSB indexing. - let lsb_index = bounded_int::sub(BYTES_IN_BYTES31_MINUS_ONE_TYPED, msb_index); - Some(word.at(upcast(lsb_index))) - }, - None => { - // Word index must equal data.len() for remainder word. - if word_index != self.data.len() { - return None; - } - - // Compute LSB index: remainder_len - 1 - msb_index. - let lsb_index_bounded = bounded_int::sub( - bounded_int::sub(self.remainder_len, ONE_TYPED), msb_index, - ); - - // Check if in bounds and extract non-negative index. - let Err(lsb_index) = bounded_int::constrain::<_, 0>(lsb_index_bounded) else { - return None; // Out of bounds: index >= remainder_len. - }; - Some(u8_at_u256((self.remainder_word).into(), upcast(lsb_index))) - }, - } - } - - impl MinusOneBounded1To30 of SubHelper, UnitInt<1>> { - type Result = BoundedInt<0, 29>; - } - - /// Returns the index minus one. - pub fn nz_index_minus_one(len: BoundedInt<1, 30>) -> BoundedInt<0, 29> { - bounded_int::sub(len, 1) - } - - - trait Complement31Helper { - type Result; - } - impl ComplementSubHelper> of SubHelper, T> { - type Result = H::Result; - } - mod complement { - pub impl Impl< - const MIN0: felt252, const MAX0: felt252, const MIN1: felt252, const MAX1: felt252, - > of super::Complement31Helper> { - type Result = super::BoundedInt; - } - } - impl ComplementNzLength = complement::Impl<1, 31, 0, 30>; - impl ComplementLength = complement::Impl<0, 31, 0, 31>; - impl ComplementNzIndex = complement::Impl<1, 30, 1, 30>; - impl ComplementIndex = complement::Impl<0, 30, 1, 31>; - - /// Returns `31 - v`. - pub fn complement_to_31>(v: T) -> H::Result { - bounded_int::sub(BYTES_IN_BYTES31_UNIT_INT, v) - } - - impl Bytes31IndexSubHelper of SubHelper { - type Result = BoundedInt<-30, 30>; - } - - impl IndexConstrainHelper of ConstrainHelper { - type LowT = BoundedInt<-30, -1>; - type HighT = BoundedInt<0, 30>; - } - - /// Returns the result of subtracting the second index from the first, or `None` if the result - /// is negative. - pub fn index_checked_sub(lhs: Bytes31Index, rhs: Bytes31Index) -> Option { - bounded_int::constrain::<_, 0>(bounded_int::sub(lhs, rhs)).err() - } -} -pub(crate) use helpers::len_parts; diff --git a/corelib/src/bytes_31.cairo b/corelib/src/bytes_31.cairo deleted file mode 100644 index 15d6b976e8..0000000000 --- a/corelib/src/bytes_31.cairo +++ /dev/null @@ -1,200 +0,0 @@ -//! Definitions and utilities for the `bytes31` type. -//! -//! The `bytes31` type is a compact, indexable 31-byte type. -//! -//! # Examples -//! -//! Creating a `bytes31` from a `felt252`: -//! ``` -//! let value: bytes31 = 0xaabb.try_into().unwrap(); -//! ``` -//! -//! Accessing a byte by index: -//! ``` -//! assert!(value[0] == 0xbb); -//! ``` - -use crate::RangeCheck; -#[allow(unused_imports)] -use crate::integer::{u128_safe_divmod, u128_to_felt252}; -use crate::num::traits::CheckedSub; -#[allow(unused_imports)] -use crate::option::OptionTrait; -use crate::traits::{Into, TryInto}; - -pub(crate) const BYTES_IN_BYTES31: usize = 31; -const BYTES_IN_U128: usize = 16; -pub(crate) const POW_2_128: felt252 = 0x100000000000000000000000000000000; -pub(crate) const POW_2_8: u128 = 0x100; - -/// Represents a 31-byte fixed-size byte type. -pub extern type bytes31; - -impl bytes31Copy of Copy; -impl bytes31Drop of Drop; - -pub(crate) extern fn bytes31_const() -> bytes31 nopanic; -extern fn bytes31_try_from_felt252(value: felt252) -> Option implicits(RangeCheck) nopanic; -extern fn bytes31_to_felt252(value: bytes31) -> felt252 nopanic; - -/// A trait for accessing a specific byte of a `bytes31` type. -#[generate_trait] -pub impl Bytes31Impl of Bytes31Trait { - /// Returns the byte at the given index (LSB's index is 0). - /// - /// Assumes that `index < BYTES_IN_BYTES31`. If the assumption is not met, the behavior is - /// undefined. - /// - /// # Examples - /// - /// ``` - /// let bytes: bytes31 = 1_u8.into(); - /// assert!(bytes.at(0) == 1); - /// ``` - fn at(self: @bytes31, index: usize) -> u8 { - u8_at_u256((*self).into(), index) - } -} - -#[feature("deprecated-index-traits")] -pub(crate) impl Bytes31IndexView of crate::traits::IndexView { - fn index(self: @bytes31, index: usize) -> u8 { - self.at(index) - } -} - -impl Bytes31BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 248 - } -} - -pub(crate) impl Bytes31IntoFelt252 of Into { - fn into(self: bytes31) -> felt252 { - bytes31_to_felt252(self) - } -} - -pub(crate) impl Bytes31IntoU256 of Into { - fn into(self: bytes31) -> u256 { - let as_felt: felt252 = self.into(); - as_felt.into() - } -} - -pub(crate) impl Felt252TryIntoBytes31 of TryInto { - fn try_into(self: felt252) -> Option { - bytes31_try_from_felt252(self) - } -} - -impl Bytes31Serde = crate::serde::into_felt252_based::SerdeImpl; - -pub(crate) impl U8IntoBytes31 of Into { - #[feature("bounded-int-utils")] - const fn into(self: u8) -> bytes31 { - crate::internal::bounded_int::upcast(self) - } -} - -impl U16IntoBytes31 of Into { - #[feature("bounded-int-utils")] - const fn into(self: u16) -> bytes31 { - crate::internal::bounded_int::upcast(self) - } -} - -impl U32IntoBytes31 of Into { - #[feature("bounded-int-utils")] - const fn into(self: u32) -> bytes31 { - crate::internal::bounded_int::upcast(self) - } -} - -impl U64IntoBytes31 of Into { - #[feature("bounded-int-utils")] - const fn into(self: u64) -> bytes31 { - crate::internal::bounded_int::upcast(self) - } -} - -pub(crate) impl U128IntoBytes31 of Into { - #[feature("bounded-int-utils")] - const fn into(self: u128) -> bytes31 { - crate::internal::bounded_int::upcast(self) - } -} - -/// Returns `1 << (8 * n_bytes)` as `u128`, where `n_bytes` must be < `BYTES_IN_U128`. -/// -/// Panics if `n_bytes >= BYTES_IN_U128`. -pub(crate) fn one_shift_left_bytes_u128(n_bytes: usize) -> u128 { - one_shift_left_bytes_u128_nz(n_bytes).into() -} - -/// Splits a u128 into two words as a `u256` - the `low` is the first `n_bytes` the `high` is the -/// rest. -pub(crate) fn split_u128(value: u128, n_bytes: usize) -> u256 { - let (high, low) = DivRem::div_rem(value, one_shift_left_bytes_u128_nz(n_bytes)); - u256 { low, high } -} - -/// Returns the `u8` at `index` if you look at `value` as an array of 32 `u8`s. -pub(crate) fn u8_at_u256(value: u256, index: usize) -> u8 { - get_lsb( - if let Some(rev_index) = index.checked_sub(BYTES_IN_U128) { - split_u128(value.high, rev_index).high - } else { - split_u128(value.low, index).high - }, - ) -} - -/// Same as `one_shift_left_bytes_u128` but returns `NonZero` value. -fn one_shift_left_bytes_u128_nz(n_bytes: usize) -> NonZero { - match n_bytes { - 0 => 0x1, - 1 => 0x100, - 2 => 0x10000, - 3 => 0x1000000, - 4 => 0x100000000, - 5 => 0x10000000000, - 6 => 0x1000000000000, - 7 => 0x100000000000000, - 8 => 0x10000000000000000, - 9 => 0x1000000000000000000, - 10 => 0x100000000000000000000, - 11 => 0x10000000000000000000000, - 12 => 0x1000000000000000000000000, - 13 => 0x100000000000000000000000000, - 14 => 0x10000000000000000000000000000, - 15 => 0x1000000000000000000000000000000, - _ => crate::panic_with_felt252('n_bytes too big'), - } -} - -impl Bytes31PartialEq of PartialEq { - fn eq(lhs: @bytes31, rhs: @bytes31) -> bool { - let lhs_as_felt252: felt252 = (*lhs).into(); - let rhs_as_felt252: felt252 = (*rhs).into(); - lhs_as_felt252 == rhs_as_felt252 - } -} - -mod helpers { - #[feature("bounded-int-utils")] - use core::internal::bounded_int::{BoundedInt, DivRemHelper, UnitInt, div_rem, upcast}; - - impl DivRemU128By256 of DivRemHelper> { - type DivT = BoundedInt<0, 0xffffffffffffffffffffffffffffff>; - type RemT = BoundedInt<0, 0xff>; - } - - /// Returns the least significant byte of the given u128. - pub fn get_lsb(value: u128) -> u8 { - let (_, res) = div_rem::<_, UnitInt<256>>(value, 256); - upcast(res) - } -} - -pub(crate) use helpers::get_lsb; diff --git a/corelib/src/circuit.cairo b/corelib/src/circuit.cairo deleted file mode 100644 index 1100c41c41..0000000000 --- a/corelib/src/circuit.cairo +++ /dev/null @@ -1,971 +0,0 @@ -//! Efficient modular arithmetic computations using arithmetic circuits. -//! -//! This module provides a type-safe way to perform modular arithmetic operations using -//! arithmetic circuits. It is particularly useful for implementing cryptographic algorithms -//! and other computations that require efficient modular arithmetic with large numbers. -//! -//! # Core Features -//! -//! - Modular arithmetic operations (add, subtract, multiply, inverse) -//! - Support for numbers up to 384 bits -//! - Type-safe circuit construction -//! - Efficient evaluation of complex expressions -//! -//! # Examples -//! -//! ## Basic Arithmetic -//! -//! Here's an example showing basic modular arithmetic operations: -//! -//! ``` -//! use core::circuit::{ -//! CircuitElement, EvalCircuitTrait, CircuitOutputsTrait, CircuitInput, CircuitModulus, -//! AddInputResultTrait, CircuitInputs, circuit_add, circuit_mul, -//! }; -//! -//! // Compute (a + b) * c mod p -//! let a = CircuitElement::> {}; -//! let b = CircuitElement::> {}; -//! let c = CircuitElement::> {}; -//! -//! let sum = circuit_add(a, b); -//! let result = circuit_mul(sum, c); -//! -//! // Evaluate with inputs [3, 6, 2] modulo 7 -//! let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap(); -//! let outputs = (result,) -//! .new_inputs() -//! .next([3, 0, 0, 0]) -//! .next([6, 0, 0, 0]) -//! .next([2, 0, 0, 0]) -//! .done() -//! .eval(modulus) -//! .unwrap(); -//! -//! // Result: (3 + 6) * 2 mod 7 = 4 -//! assert!(outputs.get_output(result) == 4.into()); -//! ``` -//! -//! # How It Works -//! -//! The module uses a type-based approach to construct and evaluate arithmetic circuits: -//! -//! 1. Circuit elements are created using `CircuitElement` where T defines their role (input or -//! gate) -//! 2. Basic operations combine elements into more complex expressions (chaining gates to create a -//! circuit) -//! 3. The final circuit is evaluated with specific input values and a modulus -//! -//! Operations are performed using a multi-limb representation for large numbers, -//! with each number represented as four 96-bit limbs allowing for values up to 384 bits. -//! -//! # Performance Considerations -//! -//! - Circuit evaluation is optimized for large modular arithmetic operations -//! - The multi-limb representation allows efficient handling of large numbers -//! - Circuit construction has zero runtime overhead due to type-based approach -//! -//! # Errors -//! -//! Circuit evaluation can fail in certain cases: -//! - When computing multiplicative inverses of non-invertible elements -//! - When the modulus is 0 or 1 -//! In that case the evaluation will return an Error. - -/// Creates a new circuit element representing addition modulo p of two input circuits. -/// -/// This function combines two circuit elements using modular addition, creating a new circuit -/// element that represents their sum modulo the circuit's modulus. -/// -/// # Arguments -/// -/// * `lhs` - Left-hand side circuit element -/// * `rhs` - Right-hand side circuit element -/// -/// # Returns -/// -/// A new circuit element representing `(lhs + rhs) mod p` -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let sum = circuit_add(a, b); -/// ``` -pub fn circuit_add, +CircuitElementTrait>( - lhs: CircuitElement, rhs: CircuitElement, -) -> CircuitElement> { - CircuitElement::> {} -} - -/// Creates a new circuit element representing subtraction modulo p of two input circuits. -/// -/// This function combines two circuit elements using modular subtraction, creating a new circuit -/// element that represents their difference modulo the circuit's modulus. -/// -/// # Arguments -/// -/// * `lhs` - Left-hand side circuit element (minuend) -/// * `rhs` - Right-hand side circuit element (subtrahend) -/// -/// # Returns -/// -/// A new circuit element representing `(lhs - rhs) mod p` -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let diff = circuit_sub(a, b); -/// ``` -pub fn circuit_sub, +CircuitElementTrait>( - lhs: CircuitElement, rhs: CircuitElement, -) -> CircuitElement> { - CircuitElement::> {} -} - -/// Creates a new circuit element representing the multiplicative inverse modulo p of an input -/// circuit. -/// -/// This function creates a new circuit element representing the multiplicative inverse of the input -/// element modulo the circuit's modulus. The operation will fail during evaluation if the input -/// is not invertible (not coprime with the modulus). -/// -/// # Arguments -/// -/// * `input` - Circuit element to compute the inverse of -/// -/// # Returns -/// -/// A new circuit element representing `input^(-1) mod p` -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let inv_a = circuit_inverse(a); -/// ``` -pub fn circuit_inverse>( - input: CircuitElement, -) -> CircuitElement> { - CircuitElement::> {} -} - -/// Creates a new circuit element representing multiplication modulo p of two input circuits. -/// -/// This function combines two circuit elements using modular multiplication, creating a new circuit -/// element that represents their product modulo the circuit's modulus. -/// -/// # Arguments -/// -/// * `lhs` - Left-hand side circuit element -/// * `rhs` - Right-hand side circuit element -/// -/// # Returns -/// -/// A new circuit element representing `(lhs * rhs) mod p` -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let product = circuit_mul(a, b); -/// ``` -pub fn circuit_mul, +CircuitElementTrait>( - lhs: CircuitElement, rhs: CircuitElement, -) -> CircuitElement> { - CircuitElement::> {} -} - -/// A 384-bit unsigned integer, used for circuit values. -#[derive(Copy, Drop, Debug, PartialEq)] -pub struct u384 { - /// The least significant 96 bits - pub limb0: u96, - /// Bits 96-191 - pub limb1: u96, - /// Bits 192-287 - pub limb2: u96, - /// The most significant 96 bits - pub limb3: u96, -} - -/// A 96-bit unsigned integer type used as the basic building block for multi-limb arithmetic. -#[feature("bounded-int-utils")] -pub type u96 = - crate::internal::bounded_int::BoundedInt<0, 79228162514264337593543950335>; - -/// Range check builtin for 96-bit operations. -pub extern type RangeCheck96; - -/// Builtin for modular addition operations. -pub extern type AddMod; - -/// Builtin for modular multiplication operations. -pub extern type MulMod; - -/// A type that can be used as a circuit modulus (a u384 that is not zero or one). -/// -/// The modulus defines the finite field over which the circuit operates. It must be: -/// - A 384-bit number (represented as four 96-bit limbs) -/// - Not zero or one -/// - Typically a prime number for cryptographic applications -pub extern type CircuitModulus; - -extern fn try_into_circuit_modulus(val: [u96; 4]) -> Option nopanic; - -impl U384TryIntoCircuitModulus of TryInto<[u96; 4], CircuitModulus> { - fn try_into(self: [u96; 4]) -> Option { - try_into_circuit_modulus(self) - } -} - -/// Converts 'T' into a 'U96Guarantee'. -/// 'T' must be a value that fits inside a u96, for example: u8, u96 or BoundedInt<0, 12>. -extern fn into_u96_guarantee(val: T) -> U96Guarantee nopanic; -extern fn u96_guarantee_verify(guarantee: U96Guarantee) implicits(RangeCheck96) nopanic; - -impl DestructU96Guarantee of Destruct { - fn destruct(self: U96Guarantee) nopanic { - u96_guarantee_verify(self); - } -} - -/// A value that is guaranteed to fit in a u96. -/// -/// The destructor of the type verifies that the value is indeed within the range of a u96. -extern type U96Guarantee; - -/// Expose the const required by the libfunc to allow the compiler const reusage. -#[feature("bounded-int-utils")] -pub type ConstZero = crate::internal::bounded_int::UnitInt<0>; -#[feature("bounded-int-utils")] -pub type ConstOne = crate::internal::bounded_int::UnitInt<1>; - -/// A type that creates a circuit from a tuple of outputs. -/// -/// This type represents a complete circuit instance, constructed from its output gates. -/// The type parameter `Outputs` defines the structure of the circuit's outputs. -pub extern type Circuit; - -/// Defines an input for a circuit. -/// -/// Represents an input signal in the circuit, indexed by `N`. Each input must be assigned -/// a value before circuit evaluation. -#[phantom] -pub extern type CircuitInput; - -/// Represents the action of adding two field elements in the circuits builtin. -/// -/// This gate computes `(lhs + rhs) mod p` where `p` is the circuit modulus. -#[phantom] -extern type AddModGate; - -/// Represents the action of multiplying two field elements in the circuits builtin. -/// -/// This gate computes `(lhs * rhs) mod p` where `p` is the circuit modulus. -#[phantom] -extern type MulModGate; - -/// Represents the action of computing the difference between two field elements in the circuits -/// builtin. -/// -/// This gate computes `(lhs - rhs) mod p` where `p` is the circuit modulus. -#[phantom] -extern type SubModGate; - -/// Represents the action of computing the inverse of a field element in the circuits builtin. -/// -/// This gate computes `x^(-1) mod p` where `p` is the circuit modulus. -/// The operation will fail if the input is not invertible (not coprime with the modulus). -#[phantom] -extern type InverseGate; - -/// Initializes the input data for running an instance of the circuit. -extern fn init_circuit_data() -> CircuitInputAccumulator implicits(RangeCheck96) nopanic; - -/// Returns the descriptor for the circuit. -extern fn get_circuit_descriptor() -> CircuitDescriptor nopanic; - -/// The result of filling an input in the circuit instance's data. -type EvalCircuitResult = - Result, (CircuitPartialOutputs, CircuitFailureGuarantee)>; - -extern fn eval_circuit( - descriptor: CircuitDescriptor, - data: CircuitData, - modulus: CircuitModulus, - zero: ConstZero, - one: ConstOne, -) -> EvalCircuitResult implicits(AddMod, MulMod) nopanic; - -/// Fill an input in the circuit instance's data. -extern fn add_circuit_input( - accumulator: CircuitInputAccumulator, value: [U96Guarantee; 4], -) -> AddInputResult nopanic; - -/// The result of filling an input in the circuit instance's data. -/// -/// This enum represents the state of input filling process, indicating whether -/// all inputs have been provided or more are needed. -pub enum AddInputResult { - /// All inputs have been filled and the circuit data is complete. - Done: CircuitData, - /// More inputs are needed to complete the circuit instance's data. - More: CircuitInputAccumulator, -} - -mod internal { - use crate::traits::PanicDestructForDestruct; - impl AddInputResultDrop of Drop>; - impl CircuitDataDrop of Drop>; - impl CircuitInputAccumulatorDrop of Drop>; - - pub impl PanicDestructAddInputResult = PanicDestructForDestruct>; - pub impl PanicDestructCircuitData = PanicDestructForDestruct>; - pub impl PanicDestructCircuitInputAccumulator = - PanicDestructForDestruct>; -} -impl PanicDestructAddInputResult = internal::PanicDestructAddInputResult; -impl PanicDestructCircuitData = internal::PanicDestructCircuitData; -impl PanicDestructCircuitInputAccumulator = internal::PanicDestructCircuitInputAccumulator; - -/// Type for accumulating inputs into the circuit instance's data. -extern type CircuitInputAccumulator; - -/// A type representing a circuit instance data with all the inputs added. -extern type CircuitData; - -/// A type representing a circuit instance where the outputs are filled. -extern type CircuitOutputs; - -/// A type representing a circuit instance where the outputs are partially filled as -/// the evaluation of one of the inverse gates failed. -/// The type is defined for future-compatibility, there is currently no libfunc to extract -/// the partial outputs. -extern type CircuitPartialOutputs; - -/// A type representing a circuit descriptor. -extern type CircuitDescriptor; - -impl CircuitDescriptorDrop of Drop>; -impl CircuitModulusCopy of Copy; -impl CircuitModulusDrop of Drop; -impl CircuitOutputsDrop of Drop>; -impl CircuitPartialOutputsDrop of Drop>; -impl CircuitOutputsCopy of Copy>; - -/// A wrapper for circuit elements, used to construct circuits. -/// -/// This type provides a generic wrapper around different circuit components (inputs, gates) -/// and enables composition of circuit elements through arithmetic operations. -/// The type parameter `T` defines the specific role of the element in the circuit. -pub struct CircuitElement {} -pub impl CircuitElementDrop of Drop>; -pub impl CircuitElementCopy of Copy>; - -/// A marker trait for keeping track of which types are valid circuit elements. -/// -/// This trait is implemented for all valid circuit components including inputs and gates. -/// It provides type safety when composing circuit elements. -pub trait CircuitElementTrait {} - -impl InputCircuitElement of CircuitElementTrait> {} -impl AddModCircuitElement< - Lhs, Rhs, +CircuitElementTrait, +CircuitElementTrait, -> of CircuitElementTrait> {} -impl SubModCircuitElement< - Lhs, Rhs, +CircuitElementTrait, +CircuitElementTrait, -> of CircuitElementTrait> {} -impl InverseCircuitElement< - Input, +CircuitElementTrait, -> of CircuitElementTrait> {} -impl MulModCircuitElement< - Lhs, Rhs, +CircuitElementTrait, +CircuitElementTrait, -> of CircuitElementTrait> {} - -/// A trait for defining a circuit's structure and behavior. -/// -/// This trait is used to define the structure of a circuit, including its inputs, -/// gates, and outputs. It provides the foundation for circuit evaluation. -/// The `CES` type parameter represents a tuple of `CircuitElement`s that together -/// define the circuit's structure. -pub trait CircuitDefinition { - /// The internal circuit type representing a tuple of `CircuitElement`s. - type CircuitType; -} - -impl CircuitDefinitionImpl< - T, impl Unwrap: UnwrapCircuitElement, +crate::metaprogramming::IsTuple, -> of CircuitDefinition { - type CircuitType = Circuit; -} - -/// Helper trait to get the unwrapped type of a `CircuitElement`, as well as the tuple of unwrapped -/// types from a tuple of `CircuitElement`s. -trait UnwrapCircuitElement { - type Unwrapped; -} - -/// Implementation for unwrapping a single `CircuitElement`. -impl UnwrapCircuitElementDirect of UnwrapCircuitElement> { - type Unwrapped = T; -} - -/// Implementation for unwrapping a basic tuple of `CircuitElement`s. -impl UnwrapCircuitElementBase< - T, impl UnwrapT: UnwrapCircuitElement, -> of UnwrapCircuitElement<(T,)> { - type Unwrapped = (UnwrapT::Unwrapped,); -} - -/// Implementation for unwrapping a tuple of `CircuitElement`s. -impl UnwrapCircuitElementNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - impl UnwrapHead: UnwrapCircuitElement, - impl UnwrapRest: UnwrapCircuitElement, - impl TEF: crate::metaprogramming::TupleExtendFront< - UnwrapRest::Unwrapped, UnwrapHead::Unwrapped, - >, -> of UnwrapCircuitElement { - type Unwrapped = TEF::Result; -} - -/// A trait for setting up instances of a circuit defined using `CircuitElement`s. -/// -/// This trait provides functionality to initialize and manage circuit inputs. -/// The `CES` type parameter represents a tuple of circuit elements (e.g., `(output,)`) -/// that define the circuit's structure. It is used in conjunction with -/// `AddInputResultTrait` to build circuit instances. -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let modulus = TryInto::<_, CircuitModulus>::try_into([2, 0, 0, 0]).unwrap(); -/// let circuit = (a,b).new_inputs() // returns AddInputResult::More, inputs are not yet filled -/// .next([10, 0, 0, 0]) -/// .next([11, 0, 0, 0]) -/// .done() -/// .eval(modulus) -/// .unwrap(); -/// assert!(circuit.get_output(a) == 0.into()); -/// assert!(circuit.get_output(b) == 1.into()); -/// ``` -#[generate_trait] -pub impl CircuitInputsImpl of CircuitInputs { - /// Initializes a new circuit instance with inputs. - /// - /// This function creates a new input accumulator for the circuit, which can then - /// be used to add input values sequentially. - /// - /// # Returns - /// - /// An `AddInputResult` that can be used to add input values to the circuit - #[inline] - fn new_inputs, +Drop>( - self: CES, - ) -> AddInputResult { - AddInputResult::More(init_circuit_data::()) - } -} - -/// A trait for getting the descriptor of a circuit. -#[generate_trait] -impl GetCircuitDescriptorImpl of GetCircuitDescriptor { - /// calls `get_circuit_descriptor` for the given circuit. - // Inlining to make sure possibly huge `C` won't be in a user function name. - #[inline] - fn get_descriptor, +Drop>( - self: CES, - ) -> CircuitDescriptor { - get_circuit_descriptor::() - } -} - -/// A trait for filling inputs in a circuit instance's data. -/// -/// This trait provides methods to add input values to a circuit instance and -/// finalize the input process. -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let modulus = TryInto::<_, CircuitModulus>::try_into([2, 0, 0, 0]).unwrap(); -/// let circuit = (a,b).new_inputs() -/// .next([10, 0, 0, 0]) // returns AddInputResult::More, inputs are not yet filled -/// .next([11, 0, 0, 0]) // returns AddInputResult::Done, inputs are filled -/// .done() // returns CircuitData, inputs are filled -/// .eval(modulus) -/// .unwrap(); -/// assert!(circuit.get_output(a) == 0.into()); -/// assert!(circuit.get_output(b) == 1.into()); -/// ``` -#[generate_trait] -pub impl AddInputResultImpl of AddInputResultTrait { - /// Adds an input value to the circuit instance. - /// - /// # Arguments - /// - /// * `value` - The value to add as input, must be convertible to circuit input value - /// - /// # Returns - /// - /// A new `AddInputResult` that can be used to add more inputs or finalize - /// - /// # Panics - /// - /// Panics if all inputs have already been filled - #[inline] - fn next, +Drop>( - self: AddInputResult, value: Value, - ) -> AddInputResult { - match self { - AddInputResult::More(accumulator) => add_circuit_input( - accumulator, value.into_circuit_input_value(), - ), - AddInputResult::Done(_) => core::panic_with_felt252('All inputs have been filled'), - } - } - - /// Finalizes the input process and returns the circuit data. - /// - /// # Returns - /// - /// The complete circuit data ready for evaluation - /// - /// # Panics - /// - /// Panics if not all required inputs have been filled - // Inlining to make sure possibly huge `C` won't be in a user function name. - #[inline] - fn done(self: AddInputResult) -> CircuitData { - match self { - AddInputResult::Done(data) => data, - AddInputResult::More(_) => core::panic_with_felt252('Not all inputs have been filled'), - } - } -} - -/// Trait for converting a value to a circuit input value. -trait IntoCircuitInputValue { - fn into_circuit_input_value(self: T) -> [U96Guarantee; 4]; -} - -impl U96sIntoCircuitInputValue of IntoCircuitInputValue<[u96; 4]> { - fn into_circuit_input_value(self: [u96; 4]) -> [U96Guarantee; 4] { - let [val0, val1, val2, val3] = self; - [ - into_u96_guarantee(val0), into_u96_guarantee(val1), into_u96_guarantee(val2), - into_u96_guarantee(val3), - ] - } -} - -impl U384IntoCircuitInputValue of IntoCircuitInputValue { - fn into_circuit_input_value(self: u384) -> [U96Guarantee; 4] { - [ - into_u96_guarantee(self.limb0), into_u96_guarantee(self.limb1), - into_u96_guarantee(self.limb2), into_u96_guarantee(self.limb3), - ] - } -} - -/// A trait for evaluating a circuit. -/// -/// This trait provides methods to evaluate a circuit with given inputs and modulus. -/// The evaluation can be done with or without an explicit circuit descriptor. -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let modulus = TryInto::<_, CircuitModulus>::try_into([2, 0, 0, 0]).unwrap(); -/// let circuit = (a,b).new_inputs() -/// .next([10, 0, 0, 0]) -/// .next([11, 0, 0, 0]) -/// .done() -/// .eval(modulus) // Performs the circuit evaluation with the given modulus and returns the -/// Result .unwrap(); -/// assert!(circuit.get_output(a) == 0.into()); -/// assert!(circuit.get_output(b) == 1.into()); -/// ``` -#[generate_trait] -pub impl EvalCircuitImpl of EvalCircuitTrait { - /// Evaluates the circuit with the given modulus. - /// - /// # Arguments - /// - /// * `modulus` - The modulus to use for arithmetic operations - /// - /// # Returns - /// - /// Result containing either the circuit outputs or a failure indication - // Inlining to make sure possibly huge `C` won't be in a user function name. - #[inline] - fn eval(self: CircuitData, modulus: CircuitModulus) -> crate::circuit::EvalCircuitResult { - self.eval_ex(get_circuit_descriptor::(), modulus) - } - - /// Evaluates the circuit with an explicit descriptor and modulus. - /// - /// # Arguments - /// - /// * `descriptor` - The circuit descriptor - /// * `modulus` - The modulus to use for arithmetic operations - /// - /// # Returns - /// - /// Result containing either the circuit outputs or a failure indication - // Inlining to make sure possibly huge `C` won't be in a user function name. - #[inline] - fn eval_ex( - self: CircuitData, descriptor: CircuitDescriptor, modulus: CircuitModulus, - ) -> crate::circuit::EvalCircuitResult { - eval_circuit::(descriptor, self, modulus, 0, 1) - } -} - -/// A trait for retrieving output values from a circuit evaluation. -/// -/// This trait provides methods to access the output values of a circuit after -/// successful evaluation. -/// -/// # Examples -/// -/// ``` -/// let a = CircuitElement::> {}; -/// let b = CircuitElement::> {}; -/// let modulus = TryInto::<_, CircuitModulus>::try_into([2, 0, 0, 0]).unwrap(); -/// let circuit = (a,b).new_inputs() -/// .next([10, 0, 0, 0]) -/// .next([11, 0, 0, 0]) -/// .done() -/// .eval(modulus) -/// .unwrap(); -/// let a_mod_2 = circuit.get_output(a); // Returns the output value of `a mod 2` -/// let b_mod_2 = circuit.get_output(b); // Returns the output value of `b mod 2` -/// assert!(a_mod_2 == 0.into()); -/// assert!(b_mod_2 == 1.into()); -/// ``` -pub trait CircuitOutputsTrait { - /// Gets the output value for a specific circuit element. - /// - /// # Arguments - /// - /// * `output` - The circuit element to get the output for - /// - /// # Returns - /// - /// The output value as a u384 - fn get_output(self: Outputs, output: OutputElement) -> u384; -} - -impl CircuitOutputsImpl< - C, Output, -> of CircuitOutputsTrait, CircuitElement> { - // Inlining to make sure possibly huge `C` won't be in a user function name. - #[inline] - fn get_output(self: CircuitOutputs, output: CircuitElement) -> u384 { - let (res, _) = get_circuit_output::(self); - res - } -} - -/// A type that is used to guarantee that the circuit evaluation has failed. -/// -/// The guarantee is verified by `circuit_failure_guarantee_verify`, which is the only way to -/// destruct this type. This way, one can trust that the guarantee holds although it has not yet -/// been verified. -extern type CircuitFailureGuarantee; - -/// A type that is used to guarantee that a u384 is less than another u384. -/// -/// The guarantee is verified by `u96_limbs_lt_guarantee_verify`, which is the only way to -/// destruct this type. This way, one can trust that the guarantee holds although it has not yet -/// been verified. -extern type U96LimbsLtGuarantee; - -/// Helper trait for finding the value of a const minus 1. -trait MinusOne { - const VALUE: usize; -} - -impl MinusOneImpl4 of MinusOne<4> { - const VALUE: usize = 3; -} - -impl MinusOneImpl3 of MinusOne<3> { - const VALUE: usize = 2; -} - -impl MinusOneImpl2 of MinusOne<2> { - const VALUE: usize = 1; -} - -/// Trait helper to convert a multi-limb guarantee to a `U96Guarantee` of the first pair of limbs -/// that differ. -trait IntoU96Guarantee { - fn into_u96_guarantee(self: U96LimbsLtGuarantee) -> U96Guarantee nopanic; -} - -impl IntoU96GuaranteeImplByNext< - const LIMB_COUNT: usize, impl MO: MinusOne, +IntoU96Guarantee, -> of IntoU96Guarantee { - fn into_u96_guarantee(self: U96LimbsLtGuarantee) -> U96Guarantee nopanic { - match u96_limbs_less_than_guarantee_verify(self) { - NextU96LessThanGuarantee::Next(next) => next.into_u96_guarantee(), - NextU96LessThanGuarantee::Final(guarantee) => guarantee, - } - } -} - -impl IntoU96GuaranteeImplFinal of IntoU96Guarantee<1> { - fn into_u96_guarantee(self: U96LimbsLtGuarantee<1>) -> U96Guarantee nopanic { - u96_single_limb_less_than_guarantee_verify(self) - } -} - -/// Enum representing the result of the verification of a multi-limb less than guarantee. -enum NextU96LessThanGuarantee { - Next: U96LimbsLtGuarantee, - Final: U96Guarantee, -} - -extern fn u96_limbs_less_than_guarantee_verify< - const LIMB_COUNT: usize, impl MO: MinusOne, ->( - guarantee: U96LimbsLtGuarantee, -) -> NextU96LessThanGuarantee nopanic; - -extern fn u96_single_limb_less_than_guarantee_verify( - guarantee: U96LimbsLtGuarantee<1>, -) -> U96Guarantee nopanic; - -impl DestructDestructU96LimbsLtGuarantee4 of Destruct> { - fn destruct(self: U96LimbsLtGuarantee<4>) nopanic { - self.into_u96_guarantee().destruct() - } -} - -/// Verifies the guarantee in order to drop it. -extern fn circuit_failure_guarantee_verify( - guarantee: CircuitFailureGuarantee, zero: ConstZero, one: ConstOne, -) -> U96LimbsLtGuarantee<4> implicits(RangeCheck96, MulMod) nopanic; - -pub impl DestructFailureGuarantee of Destruct { - fn destruct(self: CircuitFailureGuarantee) nopanic { - circuit_failure_guarantee_verify(self, 0, 1); - } -} - -/// Returns the value of the circuit output, and a guarantee that the output is less than the -/// modulus value. -extern fn get_circuit_output( - outputs: CircuitOutputs, -) -> (u384, U96LimbsLtGuarantee<4>) nopanic; - -/// Helper module to convert into `u384`. -#[feature("bounded-int-utils")] -mod conversions { - use crate::internal::bounded_int::{ - self, AddHelper, BoundedInt, DivRemHelper, MulHelper, UnitInt, downcast, upcast, - }; - use super::{u384, u96}; - - const POW128: felt252 = 0x100000000000000000000000000000000; - const POW96: felt252 = 0x1000000000000000000000000; - const POW96_TYPED: UnitInt = 0x1000000000000000000000000; - const NZ_POW96_TYPED: NonZero> = 0x1000000000000000000000000; - const POW64: felt252 = 0x10000000000000000; - const POW64_TYPED: UnitInt = 0x10000000000000000; - const NZ_POW64_TYPED: NonZero> = 0x10000000000000000; - const POW32: felt252 = 0x100000000; - const POW32_TYPED: UnitInt = 0x100000000; - const NZ_POW32_TYPED: NonZero> = 0x100000000; - - impl DivRemU128By96 of DivRemHelper> { - type DivT = BoundedInt<0, { POW32 - 1 }>; - type RemT = BoundedInt<0, { POW96 - 1 }>; - } - - impl DivRemU128By64 of DivRemHelper> { - type DivT = BoundedInt<0, { POW64 - 1 }>; - type RemT = BoundedInt<0, { POW64 - 1 }>; - } - - impl DivRemU96By32 of DivRemHelper> { - type DivT = BoundedInt<0, { POW64 - 1 }>; - type RemT = BoundedInt<0, { POW32 - 1 }>; - } - - impl DivRemU96By64 of DivRemHelper> { - type DivT = BoundedInt<0, { POW32 - 1 }>; - type RemT = BoundedInt<0, { POW64 - 1 }>; - } - - impl MulHelper64By32Impl of MulHelper, UnitInt> { - type Result = BoundedInt<0, { POW96 - POW32 }>; - } - - impl MulHelper32By96Impl of MulHelper, UnitInt> { - type Result = BoundedInt<0, { POW128 - POW96 }>; - } - - impl MulHelper64By64Impl of MulHelper, UnitInt> { - type Result = BoundedInt<0, { POW128 - POW64 }>; - } - - impl AddHelperTo96By32Impl of AddHelper< - BoundedInt<0, { POW96 - POW32 }>, BoundedInt<0, { POW32 - 1 }>, - > { - type Result = u96; - } - - impl AddHelperTo128By64Impl of AddHelper< - BoundedInt<0, { POW128 - POW64 }>, BoundedInt<0, { POW64 - 1 }>, - > { - type Result = BoundedInt<0, { POW128 - 1 }>; - } - - impl AddHelperTo128By96Impl of AddHelper, u96> { - type Result = BoundedInt<0, { POW128 - 1 }>; - } - - pub fn from_u128(value: u128) -> u384 { - let (limb1, limb0) = bounded_int::div_rem(value, NZ_POW96_TYPED); - u384 { limb0, limb1: upcast(limb1), limb2: 0, limb3: 0 } - } - - pub fn from_u256(value: u256) -> u384 { - let (limb1_low32, limb0) = bounded_int::div_rem(value.low, NZ_POW96_TYPED); - let (limb2, limb1_high64) = bounded_int::div_rem(value.high, NZ_POW64_TYPED); - let limb1 = bounded_int::add(bounded_int::mul(limb1_high64, POW32_TYPED), limb1_low32); - u384 { limb0, limb1, limb2: upcast(limb2), limb3: 0 } - } - - pub fn felt252_try_into_two_u96(value: felt252) -> Option<(u96, u96)> { - let v: u256 = value.into(); - let (limb1_low32, limb0) = bounded_int::div_rem(v.low, NZ_POW96_TYPED); - let limb1_high64: BoundedInt<0, { POW64 - 1 }> = downcast(v.high)?; - let limb1 = bounded_int::add(bounded_int::mul(limb1_high64, POW32_TYPED), limb1_low32); - Some((limb0, limb1)) - } - - pub fn try_into_u128(value: u384) -> Option { - if value.limb2 != 0 || value.limb3 != 0 { - return None; - } - let (limb1_high, limb1_low) = bounded_int::div_rem(value.limb1, NZ_POW32_TYPED); - if limb1_high != 0 { - return None; - } - Some(upcast(bounded_int::add(bounded_int::mul(limb1_low, POW96_TYPED), value.limb0))) - } - - pub fn try_into_u256(value: u384) -> Option { - if value.limb3 != 0 { - return None; - } - let (limb2_high, limb2_low) = bounded_int::div_rem(value.limb2, NZ_POW64_TYPED); - if limb2_high != 0 { - return None; - } - let (limb1_high, limb1_low) = bounded_int::div_rem(value.limb1, NZ_POW32_TYPED); - Some( - u256 { - high: upcast( - bounded_int::add(bounded_int::mul(limb2_low, POW64_TYPED), limb1_high), - ), - low: upcast( - bounded_int::add(bounded_int::mul(limb1_low, POW96_TYPED), value.limb0), - ), - }, - ) - } - - pub fn two_u96_into_felt252(limb0: u96, limb1: u96) -> felt252 { - limb0.into() + limb1.into() * POW96 - } -} - -impl U128IntoU384 of Into { - fn into(self: u128) -> u384 { - conversions::from_u128(self) - } -} - -impl U256IntoU384 of Into { - fn into(self: u256) -> u384 { - conversions::from_u256(self) - } -} - -impl Felt252IntoU384 of Into { - fn into(self: felt252) -> u384 { - conversions::from_u256(self.into()) - } -} - -impl U384TryIntoU128 of TryInto { - fn try_into(self: u384) -> Option { - conversions::try_into_u128(self) - } -} - -impl U384TryIntoU256 of TryInto { - fn try_into(self: u384) -> Option { - conversions::try_into_u256(self) - } -} - -impl U384Serde of Serde { - fn serialize(self: @u384, ref output: Array) { - output.append(conversions::two_u96_into_felt252(self.limb0, self.limb1)); - output.append(conversions::two_u96_into_felt252(self.limb2, self.limb3)); - } - - fn deserialize(ref serialized: Span) -> Option { - let [l01, l23] = (*serialized.multi_pop_front::<2>()?).unbox(); - let (limb0, limb1) = conversions::felt252_try_into_two_u96(l01)?; - let (limb2, limb3) = conversions::felt252_try_into_two_u96(l23)?; - - return Some(u384 { limb0, limb1, limb2, limb3 }); - } -} - -impl U384Zero of crate::num::traits::Zero { - fn zero() -> u384 { - u384 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 } - } - - fn is_zero(self: @u384) -> bool { - *self == Self::zero() - } - - fn is_non_zero(self: @u384) -> bool { - !self.is_zero() - } -} - -impl U384One of crate::num::traits::One { - fn one() -> u384 { - u384 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 } - } - - fn is_one(self: @u384) -> bool { - *self == Self::one() - } - - fn is_non_one(self: @u384) -> bool { - !self.is_one() - } -} diff --git a/corelib/src/clone.cairo b/corelib/src/clone.cairo deleted file mode 100644 index 5336cca62f..0000000000 --- a/corelib/src/clone.cairo +++ /dev/null @@ -1,129 +0,0 @@ -//! The `Clone` trait provides the ability to duplicate instances of types that cannot be -//! 'implicitly copied'. -//! -//! In Cairo, some simple types are "implicitly copyable": when you assign them or pass them as -//! arguments, the receiver will get a copy, leaving the original value in place. These types do not -//! require allocation to copy, and are not at risk of accessing un-allocated memory, so the -//! compiler considers them cheap and safe to copy. For other types, copies must be made explicitly, -//! by convention implementing the [`Clone`] trait and calling the [`Clone::clone`] method. -//! -//! # Examples -//! -//! ``` -//! let arr = array![1, 2, 3]; -//! let cloned_arr = arr.clone(); -//! assert!(arr == cloned_arr); -//! ``` -//! -//! You can use the `#[derive(Clone)]` attribute to automatically generate the -//! implementation for your type: -//! -//! ``` -//! #[derive(Clone, Drop)] -//! struct Sheep { -//! name: ByteArray, -//! age: u8, -//! } -//! -//! fn main() { -//! let dolly = Sheep { -//! name: "Dolly", -//! age: 6, -//! }; -//! -//! let cloned_sheep = dolly.clone(); // Famous cloned sheep! -//!} -//! ``` - -/// A common trait for the ability to explicitly duplicate an object. -/// -/// Differs from `Copy` in that `Copy` is implicit and inexpensive, while -/// `Clone` is always explicit and may or may not be expensive. -/// -/// Since `Clone` is more general than `Copy`, you can automatically make anything -/// `Copy` be `Clone` as well. -/// -/// ## Derivable -/// -/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of `Clone` calls `clone` on each field. -pub trait Clone { - /// Returns a copy of the value. - /// - /// # Examples - /// - /// ``` - /// let arr = array![1, 2, 3]; - /// assert!(arr == arr.clone()); - /// ``` - #[must_use] - fn clone(self: @T) -> T; -} - -// Implementation of `Clone` for types that are `Copy`. -impl TCopyClone> of Clone { - fn clone(self: @T) -> T { - *self - } -} - -// Implementation of `Clone` for tuples. -impl TupleClone< - T, - impl TSF: crate::metaprogramming::TupleSnapForward, - impl CH: CloneHelper, - -Copy, -> of Clone { - fn clone(self: @T) -> T { - CH::clone(TSF::snap_forward(self)) - } -} - -// Trait helper for implementing `Clone` for tuples. -// Provides a `clone` function for tuples of snapshots, and basic snapshots. -trait CloneHelper { - fn clone(value: T) -> Cloned; -} - -// An implementation of `CloneHelper` for a snapshot of any type with `Clone` -// implementation. -impl CloneHelperByClone> of CloneHelper<@T, T> { - fn clone(value: @T) -> T { - value.clone() - } -} - -// Base implementation of `CloneHelper` for tuples. -impl CloneHelperBaseTuple of CloneHelper<(), ()> { - fn clone(value: ()) -> () { - value - } -} - -// Base implementation of `CloneHelper` for fixed-sized arrays. -impl FixedSizedArrayCloneHelper of CloneHelper<[@T; 0], [T; 0]> { - fn clone(value: [@T; 0]) -> [T; 0] { - let [] = value; - [] - } -} - -// Recursive implementation of `CloneHelper` for tuple style structs. -impl TupleNextCloneHelper< - T, - impl TH: crate::metaprogramming::TupleSplit, - impl HeadNoSnap: crate::metaprogramming::SnapRemove, - impl RestNoSnap: crate::metaprogramming::SnapRemove, - impl HeadHelper: CloneHelper, - impl RestHelper: CloneHelper, - impl TEF: crate::metaprogramming::TupleExtendFront, - +Destruct, - +Drop, -> of CloneHelper { - fn clone(value: T) -> TEF::Result { - let (head, rest) = TH::split_head(value); - let head = HeadHelper::clone(head); - let rest = RestHelper::clone(rest); - TEF::extend_front(rest, head) - } -} diff --git a/corelib/src/cmp.cairo b/corelib/src/cmp.cairo deleted file mode 100644 index eea4b23471..0000000000 --- a/corelib/src/cmp.cairo +++ /dev/null @@ -1,72 +0,0 @@ -//! Utilities for comparing and ordering values. -//! This module contains functions that rely on the `PartialOrd` trait for comparing values. -//! -//! # Examples -//! -//! ``` -//! use core::cmp::{min, max, minmax}; -//! -//! assert!(min(10, 20) == 10); -//! assert!(max(10, 20) == 20); -//! -//! assert!(minmax(20, 10) == (10, 20)); -//! assert!(minmax(10, 20) == (10, 20)); -//! ``` - -/// Takes two comparable values `a` and `b` and returns -/// the smaller of the two values. -/// -/// # Examples -/// -/// ``` -/// use core::cmp::min; -/// -/// assert!(min(0, 1) == 0); -/// ``` -#[must_use] -pub fn min, +Drop, +Copy>(a: T, b: T) -> T { - if a > b { - b - } else { - a - } -} - -/// Takes two comparable values `a` and `b` and returns -/// the greater of the two values. -/// -/// # Examples -/// -/// ``` -/// use core::cmp::max; -/// -/// assert!(max(0, 1) == 1); -/// ``` -#[must_use] -pub fn max, +Drop, +Copy>(a: T, b: T) -> T { - if a > b { - a - } else { - b - } -} - -/// Takes two comparable values `a` and `b` and returns -/// a tuple with the smaller value and the greater value. -/// -/// # Examples -/// -/// ``` -/// use core::cmp::minmax; -/// -/// assert!(minmax(0, 1) == (0, 1)); -/// assert!(minmax(1, 0) == (0, 1)); -/// ``` -#[must_use] -pub fn minmax, +Drop, +Copy>(a: T, b: T) -> (T, T) { - if a > b { - (b, a) - } else { - (a, b) - } -} diff --git a/corelib/src/debug.cairo b/corelib/src/debug.cairo deleted file mode 100644 index 85cc101f52..0000000000 --- a/corelib/src/debug.cairo +++ /dev/null @@ -1,147 +0,0 @@ -//! Utilities related to printing of values at runtime. -//! The recommended way of printing values is by using the `Display` and `Debug` traits -//! available in the [`fmt`] module. The items in this module are not public, and are not -//! recommended for use. - -#[allow(unused_imports)] -use crate::array::ArrayTrait; -#[allow(unused_imports)] -use crate::option::Option; -use crate::traits::Into; - -pub(crate) extern fn print(message: Array) nopanic; - -fn print_felt252(message: felt252) { - print(array![message]); -} - -/// A trait for printing values for debugging purposes. -/// Accessible with prelude editions prior to `2024_07`. -/// -/// # Examples -/// -/// ``` -/// use core::debug::PrintTrait; -/// -/// 1.print(); -/// (1 == 2).print(); -/// -/// let mut arr = array![]; -/// arr.append('1234567890123456789012345678901'); -/// arr.append('Sca'); -/// arr.append('SomeVeryLongMessage'); -/// arr.print(); -/// ``` -pub(crate) trait PrintTrait { - fn print(self: T); -} - -pub(crate) impl Felt252PrintImpl of PrintTrait { - fn print(self: felt252) { - print_felt252(self); - } -} - -pub(crate) impl BoolPrintImpl of PrintTrait { - fn print(self: bool) { - if self { - 'true'.print(); - } else { - 'false'.print(); - } - } -} - -pub(crate) impl ContractAddressPrintImpl of PrintTrait { - fn print(self: starknet::ContractAddress) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U8PrintImpl of PrintTrait { - fn print(self: u8) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U16PrintImpl of PrintTrait { - fn print(self: u16) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U32PrintImpl of PrintTrait { - fn print(self: u32) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U64PrintImpl of PrintTrait { - fn print(self: u64) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U128PrintImpl of PrintTrait { - fn print(self: u128) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl U256PrintImpl of PrintTrait { - fn print(self: u256) { - Into::::into(self.low).print(); - Into::::into(self.high).print(); - } -} - -pub(crate) impl I8PrintImpl of PrintTrait { - fn print(self: i8) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl I16PrintImpl of PrintTrait { - fn print(self: i16) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl I32PrintImpl of PrintTrait { - fn print(self: i32) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl I64PrintImpl of PrintTrait { - fn print(self: i64) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl I128PrintImpl of PrintTrait { - fn print(self: i128) { - Into::<_, felt252>::into(self).print(); - } -} - -pub(crate) impl ArrayGenericPrintImpl of PrintTrait> { - fn print(mut self: Array) { - print(self); - } -} - -/// Prints a `ByteArray` as a string. -/// -/// # Examples -/// -/// ``` -/// let ba: ByteArray = "123"; -/// print_byte_array_as_string(@ba); -/// ``` -pub fn print_byte_array_as_string(self: @ByteArray) { - let mut serialized = array![crate::byte_array::BYTE_ARRAY_MAGIC]; - self.serialize(ref serialized); - print(serialized) -} - diff --git a/corelib/src/dict.cairo b/corelib/src/dict.cairo deleted file mode 100644 index bd726bfd65..0000000000 --- a/corelib/src/dict.cairo +++ /dev/null @@ -1,309 +0,0 @@ -//! A dictionary-like data structure that maps `felt252` keys to values of any type. -//! -//! The `Felt252Dict` provides efficient key-value storage with operations for inserting, -//! retrieving, and updating values. Each operation creates a new entry that can be validated -//! through a process called squashing. -//! -//! # Examples -//! -//! One can create a new dictionary using the [`Default::default`] method: -//! -//! ``` -//! use core::dict::Felt252Dict; -//! -//! let mut dict: Felt252Dict = Default::default(); -//! ``` -//! -//! ... then insert new values corresponding to a given key with the [`Felt252DictTrait::insert`] -//! method, and retrieve any value given a key with the [`Felt252DictTrait::get`] method. -//! -//! ``` -//! dict.insert(0, 10); -//! dict.insert(1, 20); -//! assert!(dict.get(0) == 10); -//! assert!(dict.get(1) == 20); -//! -//! dict.insert(0, 20); -//! assert!(dict.get(0) == 20); -//! ``` -//! -//! It is also possible to use the [`Felt252DictTrait::entry`] method to retrieve the last entry -//! given a certain key. -//! In this case, the method takes ownership of the dictionary and returns the entry to update. -//! After that, using the [`Felt252DictEntryTrait::finalize`] allows to create a new entry in the -//! dictionary. -//! Using `entry` and `finalize` methods can be very useful given that it does not require the type -//! in the dictionary to be copyable, meaning that we can use non-copyable types like arrays as -//! dictionary values. -//! -//! ``` -//! use core::dict::Felt252Dict; -//! -//! let mut dict: Felt252Dict = Default::default(); -//! dict.insert(0, 10); -//! -//! let (entry, prev_value) = dict.entry(0); -//! let new_value: u8 = 20; -//! dict = entry.finalize(new_value); -//! ``` - -#[feature("deprecated-index-traits")] -use crate::traits::{Default, Felt252DictValue, Index}; - -/// A dictionary that maps `felt252` keys to a value of any type. -pub extern type Felt252Dict; - -/// A dictionary in a squashed state. It cannot be mutated anymore. -pub extern type SquashedFelt252Dict; - -/// An intermediate type that is returned after calling the `entry` method that consumes ownership -/// of the dictionary. This ensures that the dictionary cannot be mutated until the entry is -/// finalized, which restores ownership of the dictionary. -pub extern type Felt252DictEntry; - -impl SquashedFelt252DictDrop> of Drop>; -use crate::gas::GasBuiltin; -use crate::{RangeCheck, SegmentArena}; - -pub(crate) extern fn felt252_dict_new() -> Felt252Dict implicits(SegmentArena) nopanic; - -extern fn felt252_dict_entry_get( - dict: Felt252Dict, key: felt252, -) -> (Felt252DictEntry, T) nopanic; - -extern fn felt252_dict_entry_finalize( - dict_entry: Felt252DictEntry, new_value: T, -) -> Felt252Dict nopanic; - -// Squashes the dictionary and returns a `SquashedFelt252Dict`. -// -// NOTE: Never use this libfunc directly. Use Felt252DictTrait::squash() instead. Using this -// libfunc directly will result in multiple unnecessary copies of the libfunc in the compiled CASM -// code. -pub(crate) extern fn felt252_dict_squash( - dict: Felt252Dict, -) -> SquashedFelt252Dict implicits(RangeCheck, GasBuiltin, SegmentArena) nopanic; - -extern fn squashed_felt252_dict_entries( - dict: SquashedFelt252Dict, -) -> Array<(felt252, T, T)> nopanic; - -/// Basic trait for the `Felt252Dict` type. -pub trait Felt252DictTrait { - /// Inserts the given value for the given key. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let mut dict: Felt252Dict = Default::default(); - /// dict.insert(0, 10); - /// ``` - fn insert<+Destruct>(ref self: Felt252Dict, key: felt252, value: T); - - /// Returns the value stored at the given key. If no value was previously inserted at this key, - /// returns the default value for type T. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let mut dict: Felt252Dict = Default::default(); - /// dict.insert(0, 10); - /// let value = dict.get(0); - /// assert!(value == 10); - /// ``` - fn get<+Copy>(ref self: Felt252Dict, key: felt252) -> T; - - /// Squashes a dictionary and returns the associated `SquashedFelt252Dict`. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let mut dict: Felt252Dict = Default::default(); - /// dict.insert(0, 10); - /// let squashed_dict = dict.squash(); - /// ``` - fn squash(self: Felt252Dict) -> SquashedFelt252Dict nopanic; - - /// Retrieves the last entry for a certain key. - /// This method takes ownership of the dictionary and returns the entry to update, - /// as well as the previous value at the given key. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let mut dict: Felt252Dict = Default::default(); - /// dict.insert(0, 10); - /// let (entry, prev_value) = dict.entry(0); - /// assert!(prev_value == 10); - /// ``` - #[must_use] - fn entry(self: Felt252Dict, key: felt252) -> (Felt252DictEntry, T) nopanic; -} - -impl Felt252DictImpl> of Felt252DictTrait { - #[inline] - fn insert<+Destruct>(ref self: Felt252Dict, key: felt252, value: T) { - let (entry, _prev_value) = felt252_dict_entry_get(self, key); - self = felt252_dict_entry_finalize(entry, value); - } - - #[inline] - fn get<+Copy>(ref self: Felt252Dict, key: felt252) -> T { - let (entry, value) = felt252_dict_entry_get(self, key); - self = felt252_dict_entry_finalize(entry, value); - value - } - - #[inline(never)] - fn squash(self: Felt252Dict) -> SquashedFelt252Dict nopanic { - felt252_dict_squash(self) - } - - #[inline] - fn entry(self: Felt252Dict, key: felt252) -> (Felt252DictEntry, T) nopanic { - felt252_dict_entry_get(self, key) - } -} - -/// Basic trait for the `Felt252DictEntryTrait` type. -pub trait Felt252DictEntryTrait { - /// Finalizes the changes made to a dictionary entry and gives back the ownership of the - /// dictionary. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252DictEntryTrait; - /// - /// // Create a dictionary that stores arrays - /// let mut dict: Felt252Dict>> = Default::default(); - /// - /// let a = array![1, 2, 3]; - /// dict.insert(0, NullableTrait::new(a)); - /// - /// let (entry, prev_value) = dict.entry(0); - /// let new_value = NullableTrait::new(array![4, 5, 6]); - /// dict = entry.finalize(new_value); - /// assert!(prev_value == a); - /// assert!(dict.get(0) == new_value); - /// ``` - fn finalize(self: Felt252DictEntry, new_value: T) -> Felt252Dict; -} - -impl Felt252DictEntryImpl> of Felt252DictEntryTrait { - #[inline] - fn finalize(self: Felt252DictEntry, new_value: T) -> Felt252Dict { - felt252_dict_entry_finalize(self, new_value) - } -} - -impl Felt252DictDefault of Default> { - /// Returns a new empty dictionary. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let dict: Felt252Dict = Default::default(); - /// ``` - #[inline] - fn default() -> Felt252Dict { - felt252_dict_new() - } -} - -impl Felt252DictDestruct, +Felt252DictValue> of Destruct> { - /// Allows the dictionary to go out of scope safely by ensuring it is squashed before going out - /// of scope. - /// A `Felt252Dict` cannot be "dropped" trivially because we need to ensure it is squashed - /// before the end of a program for soundness purposes. As such, `destruct` squashes the - /// dictionary, and the returned `SquashedFelt252Dict` is dropped trivially. - /// `destruct` is automatically called when a dictionary goes out of scope. - #[inline] - fn destruct(self: Felt252Dict) nopanic { - self.squash(); - } -} - -impl Felt252DictEntryDestruct, +Felt252DictValue> of Destruct> { - /// Allows the `Felt252DictEntry` to go out of scope safely by ensuring the dictionary it is - /// related to is squashed before going out of scope. - /// `destruct` is automatically called when a dictionary entry goes out of scope. - #[inline] - fn destruct(self: Felt252DictEntry) nopanic { - felt252_dict_entry_finalize(self, Felt252DictValue::zero_default()); - } -} - -/// Implementation of the `Index` trait for `Felt252Dict`. -/// Allows accessing dictionary elements using the index operator `[]`. -impl Felt252DictIndex< - T, +Felt252DictTrait, +Copy, +Destruct>, -> of Index, felt252, T> { - /// Takes a `felt252` index and returns the corresponding value. - /// - /// # Examples - /// - /// ``` - /// use core::dict::Felt252Dict; - /// - /// let mut dict: Felt252Dict = Default::default(); - /// dict.insert(0, 10); - /// - /// let value = dict[0]; - /// assert!(value == 10); - /// ``` - #[inline] - fn index(ref self: Felt252Dict, index: felt252) -> T { - self.get(index) - } -} - -impl Felt252DictFromIterator< - T, +Destruct, +Destruct>, +Felt252DictValue, -> of crate::iter::FromIterator, (felt252, T)> { - /// Constructs a `Felt252Dict` from an iterator of (felt252, T) key-value pairs. - /// If the iterator contains repeating keys, - /// only the last value in the iterator for each key will be kept. - fn from_iter< - I, - impl IntoIter: IntoIterator, - +core::metaprogramming::TypeEqual, - +Destruct, - +Destruct, - >( - iter: I, - ) -> Felt252Dict { - let mut dict = Default::default(); - for (key, value) in iter { - dict.insert(key, value); - } - dict - } -} - -/// Basic trait for the `SquashedFelt252Dict` type. -#[generate_trait] -pub impl SquashedFelt252DictImpl of SquashedFelt252DictTrait { - /// Returns an array of `(key, first_value, last_value)` tuples. - /// The first value is always 0. - /// - /// # Example - /// ``` - /// let squashed_dict = dict.squash(); - /// let entries = squashed_dict.into_entries(); - /// ``` - #[inline] - fn into_entries(self: SquashedFelt252Dict) -> Array<(felt252, T, T)> { - squashed_felt252_dict_entries(self) - } -} diff --git a/corelib/src/ec.cairo b/corelib/src/ec.cairo deleted file mode 100644 index d683583939..0000000000 --- a/corelib/src/ec.cairo +++ /dev/null @@ -1,428 +0,0 @@ -//! Functions and constructs related to elliptic curve operations on the STARK curve. -//! -//! This module provides implementations for various elliptic curve operations tailored for the -//! STARK curve. -//! -//! Curve information: -//! * Curve equation: y² ≡ x³ + α·x + β (mod p) -//! * α = 1 -//! * β = 0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89 -//! * p = 0x0800000000000011000000000000000000000000000000000000000000000001 = 2^251 + 17 * 2^192 + -//! 1 -//! Generator point: -//! * x = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca -//! * y = 0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f -//! -//! # Examples -//! -//! Creating points and basic operations: -//! -//! ``` -//! // Create a point from coordinates -//! let point = EcPointTrait::new( -//! x: 336742005567258698661916498343089167447076063081786685068305785816009957563, -//! y: 1706004133033694959518200210163451614294041810778629639790706933324248611779, -//! ).unwrap(); -//! -//! // Perform scalar multiplication -//! let result = point.mul(2); -//! -//! // Add points -//! let sum = point + result; -//! -//! // Subtract points -//! let diff = result - point; -//! ``` -//! -//! Using EC state for batch operations: -//! -//! ``` -//! let p = EcPointTrait::new_from_x(1).unwrap(); -//! let p_nz = p.try_into().unwrap(); -//! -//! // Initialize state -//! let mut state = EcStateTrait::init(); -//! -//! // Add points and scalar multiplications -//! state.add(p_nz); -//! state.add_mul(1, p_nz); -//! -//! // Get the final result -//! let _result = state.finalize(); -//! ``` - -use crate::RangeCheck; -#[allow(unused_imports)] -use crate::array::ArrayTrait; -#[allow(unused_imports)] -use crate::traits::{Into, TryInto}; -use crate::zeroable::IsZeroResult; - -pub mod stark_curve { - /// The STARK Curve is defined by the equation y² ≡ x³ + α·x + β (mod p). - pub const ALPHA: felt252 = 1; - /// The STARK Curve is defined by the equation y² ≡ x³ + α·x + β (mod p). - pub const BETA: felt252 = 0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89; - /// The order (number of points) of the STARK Curve. - pub const ORDER: felt252 = 0x800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f; - /// The x coordinate of the generator point used in the ECDSA signature. - pub const GEN_X: felt252 = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca; - /// The y coordinate of the generator point used in the ECDSA signature. - pub const GEN_Y: felt252 = 0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f; -} - -pub extern type EcOp; - -/// A point on the STARK curve. -/// -/// Points can be created using [`EcPointTrait::new`] or [`EcPointTrait::new_from_x`]. -/// The zero point represents the point at infinity. -pub extern type EcPoint; - -impl EcPointCopy of Copy; -impl EcPointDrop of Drop; - -/// A non-zero point on the STARK curve (cannot be the point at infinity). -pub type NonZeroEcPoint = NonZero; - -/// Returns the zero point of the curve ("the point at infinity"). -extern fn ec_point_zero() -> EcPoint nopanic; - -/// Constructs a non-zero point from its (x, y) coordinates. -/// Returns `None` if the point (x, y) is not on the curve. -extern fn ec_point_try_new_nz(x: felt252, y: felt252) -> Option nopanic; - -/// Constructs a non-zero point from its x coordinate. -/// Returns `None` if no point of form (x, _) is on the curve. -extern fn ec_point_from_x_nz(x: felt252) -> Option implicits(RangeCheck) nopanic; - -/// Unwraps a non-zero point into its (x, y) coordinates. -pub extern fn ec_point_unwrap(p: NonZeroEcPoint) -> (felt252, felt252) nopanic; - -/// Computes the negation of an elliptic curve point (-p). -extern fn ec_neg(p: EcPoint) -> EcPoint nopanic; - -/// Computes the negation of a non-zero elliptic curve point (-p). -extern fn ec_neg_nz(p: NonZeroEcPoint) -> NonZeroEcPoint nopanic; - -/// Checks whether the given `EcPoint` is the zero point. -extern fn ec_point_is_zero(p: EcPoint) -> IsZeroResult nopanic; - -/// Converts `EcPoint` to `NonZeroEcPoint`. -impl EcPointTryIntoNonZero of TryInto { - #[inline] - fn try_into(self: EcPoint) -> Option { - match ec_point_is_zero(self) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(p_nz) => Some(p_nz), - } - } -} - -/// Elliptic curve state. -/// -/// Use this to perform multiple point operations efficiently. -/// Initialize with [`EcStateTrait::init`], add points with [`EcStateTrait::add`] -/// or [`EcStateTrait::add_mul`], and finalize with [`EcStateTrait::finalize`]. -pub extern type EcState; - -impl EcStateDrop of Drop; - -mod internal { - impl EcStateCopy of Copy; - pub impl EcStateClone of Clone { - #[inline] - fn clone(self: @super::EcState) -> super::EcState { - *self - } - } -} - -impl EcStateClone = internal::EcStateClone; - -/// Initializes an EC computation with the zero point. -extern fn ec_state_init() -> EcState nopanic; - -/// Adds a point to the computation. -extern fn ec_state_add(ref s: EcState, p: NonZeroEcPoint) nopanic; - -/// Adds the product `p * scalar` to the state. -extern fn ec_state_add_mul( - ref s: EcState, scalar: felt252, p: NonZeroEcPoint, -) implicits(EcOp) nopanic; - -/// Finalizes the EC computation and returns the result (returns `None` if the result is the -/// zero point). -extern fn ec_state_try_finalize_nz(s: EcState) -> Option nopanic; - -#[generate_trait] -pub impl EcStateImpl of EcStateTrait { - /// Initializes an EC computation with the zero point. - /// - /// # Examples - /// - /// ``` - /// let mut state = EcStateTrait::init(); - /// ``` - #[must_use] - fn init() -> EcState nopanic { - ec_state_init() - } - - /// Adds a point to the computation. - /// - /// # Arguments - /// - /// * `p` - The non-zero point to add - #[inline] - fn add(ref self: EcState, p: NonZeroEcPoint) nopanic { - ec_state_add(ref self, :p); - } - - /// Subtracts a point to the computation. - /// - /// # Arguments - /// - /// * `p` - The non-zero point to subtract - #[inline] - fn sub(ref self: EcState, p: NonZeroEcPoint) { - ec_state_add(ref self, -p); - } - - /// Adds the product `p * scalar` to the state. - /// - /// # Arguments - /// - /// * `scalar` - The scalar to multiply the point by - /// * `p` - The non-zero point to multiply and add - #[inline] - fn add_mul(ref self: EcState, scalar: felt252, p: NonZeroEcPoint) nopanic { - ec_state_add_mul(ref self, :scalar, :p); - } - - /// Finalizes the EC computation and returns the result as a non-zero point. - /// - /// # Returns - /// - /// * `Option` - The resulting point, or None if the result is the zero point. - #[inline] - fn finalize_nz(self: EcState) -> Option nopanic { - ec_state_try_finalize_nz(self) - } - - /// Finalizes the EC computation and returns the result. - /// - /// Returns the zero point if the computation results in the point at infinity. - #[inline] - fn finalize(self: EcState) -> EcPoint { - match self.finalize_nz() { - Some(p_nz) => p_nz.into(), - None => ec_point_zero(), - } - } -} - -#[generate_trait] -pub impl EcPointImpl of EcPointTrait { - /// Creates a new EC point from its (x, y) coordinates. - /// - /// # Arguments - /// - /// * `x` - The x-coordinate of the point - /// * `y` - The y-coordinate of the point - /// - /// # Returns - /// - /// Returns `None` if the point (x, y) is not on the curve. - /// - /// # Examples - /// - /// ``` - /// let point = EcPointTrait::new( - /// x: 336742005567258698661916498343089167447076063081786685068305785816009957563, - /// y: 1706004133033694959518200210163451614294041810778629639790706933324248611779, - /// ).unwrap(); - /// ``` - #[inline] - fn new(x: felt252, y: felt252) -> Option { - Some(Self::new_nz(:x, :y)?.into()) - } - - /// Creates a new NonZero EC point from its (x, y) coordinates. - #[inline] - fn new_nz(x: felt252, y: felt252) -> Option { - ec_point_try_new_nz(:x, :y) - } - - /// Creates a new EC point from its x coordinate. - /// - /// # Arguments - /// - /// * `x` - The x-coordinate of the point - /// - /// # Returns - /// - /// Returns `None` if no point with the given x-coordinate exists on the curve. - /// - /// # Examples - /// - /// ``` - /// let valid = EcPointTrait::new_from_x(1); - /// assert!(valid.is_some()); - /// let invalid = EcPointTrait::new_from_x(0); - /// assert!(invalid.is_none()); - /// ``` - #[inline] - fn new_from_x(x: felt252) -> Option { - Some(Self::new_nz_from_x(:x)?.into()) - } - - /// Creates a new NonZero EC point from its x coordinate. - #[inline] - fn new_nz_from_x(x: felt252) -> Option { - ec_point_from_x_nz(:x) - } - - - /// Returns the coordinates of the EC point. - /// - /// # Returns - /// - /// A tuple containing the (x, y) coordinates of the point. - /// - /// # Examples - /// - /// ``` - /// let point_nz = EcPointTrait::new_nz_from_x(1).unwrap(); - /// let (x, _y) = point_nz.coordinates(); - /// assert!(x == 1); - /// ``` - fn coordinates(self: NonZeroEcPoint) -> (felt252, felt252) { - ec_point_unwrap(self) - } - - /// Returns the x coordinate of the EC point. - /// - /// # Panics - /// - /// Panics if the point is the point at infinity. - /// - /// # Examples - /// - /// ``` - /// let point_nz = EcPointTrait::new_nz_from_x(1).unwrap(); - /// let x = point_nz.x(); - /// assert!(x == 1); - /// ``` - fn x(self: NonZeroEcPoint) -> felt252 { - let (x, _) = self.coordinates(); - x - } - - /// Returns the y coordinate of the EC point. - /// - /// # Panics - /// - /// Panics if the point is the point at infinity. - /// - /// # Examples - /// - /// ``` - /// let gen_point = - /// EcPointTrait::new_nz_from_x(0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca).unwrap(); - /// let y = gen_point.y(); - /// assert!(y == 0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f); - /// ``` - fn y(self: NonZeroEcPoint) -> felt252 { - let (_, y) = self.coordinates(); - y - } - - /// Computes the product of an EC point by the given scalar. - /// - /// # Arguments - /// - /// * `scalar` - The scalar to multiply the point by - /// - /// # Returns - /// - /// The resulting point after scalar multiplication. - fn mul(self: EcPoint, scalar: felt252) -> EcPoint { - match self.try_into() { - Some(self_nz) => { - let mut state = EcStateTrait::init(); - state.add_mul(scalar, self_nz); - state.finalize() - }, - None => self, - } - } -} - -impl EcPointNeg of Neg { - fn neg(a: EcPoint) -> EcPoint { - ec_neg(a) - } -} - -#[cfg(sierra: "future")] -impl NonZeroEcPointNeg of Neg { - fn neg(a: NonZeroEcPoint) -> NonZeroEcPoint { - ec_neg_nz(a) - } -} - -// TODO(orizi): Remove this impl on next Sierra release. -#[cfg(not(sierra: "future"))] -impl NonZeroEcPointNeg of Neg { - fn neg(a: NonZeroEcPoint) -> NonZeroEcPoint { - let p: EcPoint = a.into(); - (-p).try_into().unwrap() - } -} - -impl EcPointAdd of Add { - /// Computes the sum of two points on the curve. - fn add(lhs: EcPoint, rhs: EcPoint) -> EcPoint { - let Some(lhs_nz) = lhs.try_into() else { - return rhs; - }; - let Some(rhs_nz) = rhs.try_into() else { - return lhs; - }; - let mut state = ec_state_init(); - state.add(lhs_nz); - state.add(rhs_nz); - - state.finalize() - } -} - -#[feature("deprecated-op-assign-traits")] -impl EcPointAddEq of crate::traits::AddEq { - #[inline] - fn add_eq(ref self: EcPoint, other: EcPoint) { - self = Add::add(self, other); - } -} - -impl EcPointSub of Sub { - /// Computes the difference between two points on the curve. - fn sub(lhs: EcPoint, rhs: EcPoint) -> EcPoint { - let nz_point: Option> = rhs.try_into(); - if nz_point.is_none() { - // lhs - 0 = lhs. - return lhs; - } - // lhs - rhs = lhs + (-rhs). - lhs + (-rhs) - } -} - -#[feature("deprecated-op-assign-traits")] -impl EcPointSubEq of crate::traits::SubEq { - #[inline] - fn sub_eq(ref self: EcPoint, other: EcPoint) { - self = Sub::sub(self, other); - } -} diff --git a/corelib/src/ecdsa.cairo b/corelib/src/ecdsa.cairo deleted file mode 100644 index 60b807e5a0..0000000000 --- a/corelib/src/ecdsa.cairo +++ /dev/null @@ -1,253 +0,0 @@ -//! Elliptic Curve Digital Signature Algorithm (ECDSA) for the STARK curve. -//! -//! This module provides implementations for ECDSA signature verification and public key recovery -//! specifically tailored for the STARK curve. -//! -//! Curve information: -//! * Curve equation: y² ≡ x³ + α·x + β (mod p) -//! * α = 1 -//! * β = 0x6f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89 -//! * p = 0x0800000000000011000000000000000000000000000000000000000000000001 = 2^251 + 17 * 2^192 + -//! 1 -//! Generator point: -//! * x = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca -//! * y = 0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f - -use crate::ec::{self, EcPointTrait, EcStateTrait}; -use crate::math; -#[allow(unused_imports)] -use crate::option::OptionTrait; -#[allow(unused_imports)] -use crate::traits::{Into, TryInto}; -#[allow(unused_imports)] -use crate::zeroable::IsZeroResult; - -/// Verifies an ECDSA signature against a message hash and public key. -/// -/// Note: the verification algorithm implemented by this function slightly deviates from the -/// standard ECDSA. -/// While this does not allow creating valid signatures if one does not possess the private key, -/// it means that the signature algorithm used should be modified accordingly. -/// This function validates that `s` and `r` are not 0 or equal to the curve order, -/// but does not check that `r, s < stark_curve::ORDER`, which should be checked by the caller. -/// Additionally, it does not prevent malleability attacks of using `s` as `stark_curve::ORDER - s`, -/// `stark_curve::ORDER + s` or `2 * stark_curve::ORDER - s` (when in felt252 range). -/// Those can be avoided by checking that `s <= stark_curve::ORDER / 2`. -/// -/// # Arguments -/// * `message_hash` - The hash of the signed message -/// * `public_key` - The x-coordinate of the signer's public key point on the STARK curve -/// * `signature_r` - The r component of the ECDSA signature (x-coordinate of point R) -/// * `signature_s` - The s component of the ECDSA signature -/// -/// # Returns -/// Returns `true` if the signature is valid, `false` otherwise. -/// -/// # Examples -/// -/// ``` -/// use core::ecdsa::check_ecdsa_signature; -/// -/// let message_hash = 0x2d6479c0758efbb5aa07d35ed5454d728637fceab7ba544d3ea95403a5630a8; -/// let pubkey = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca; -/// let r = 0x6ff7b413a8457ef90f326b5280600a4473fef49b5b1dcdfcd7f42ca7aa59c69; -/// let s = 0x23a9747ed71abc5cb956c0df44ee8638b65b3e9407deade65de62247b8fd77; -/// assert!(check_ecdsa_signature(message_hash, pubkey, r, s)); -/// ``` -// TODO(lior): Make this function nopanic once possible. -pub fn check_ecdsa_signature( - message_hash: felt252, public_key: felt252, signature_r: felt252, signature_s: felt252, -) -> bool { - if is_equivalent_to_zero(signature_s) || signature_r == ec::stark_curve::ORDER { - return false; - } - - // Check that the public key is the x coordinate of a point on the curve and get such a point. - let Some(public_key_point) = EcPointTrait::new_nz_from_x(public_key) else { - return false; - }; - - // Check that `r` is the x coordinate of a point on the curve and get such a point. - // Note that this ensures that `r != 0`. - let Some(signature_r_point) = EcPointTrait::new_nz_from_x(signature_r) else { - return false; - }; - - // Retrieve the generator point. - let Some(gen_point) = generator_point() else { - return false; - }; - - // Initialize an EC state. - let init_ec = EcStateTrait::init(); - - // To verify ECDSA, obtain: - // zG = z * G, where z is the message and G is a generator of the EC. - // rQ = r * Q, where Q.x = public_key. - // sR = s * R, where R.x = r. - // and check that: - // zG +/- rQ = +/- sR, or more efficiently that: - // (zG +/- rQ).x = sR.x. - - // Calculate `sR.x`. - let mut sR_state = init_ec.clone(); - sR_state.add_mul(signature_s, signature_r_point); - let Some(sR_nz) = sR_state.finalize_nz() else { - return false; - }; - let sR_x = sR_nz.x(); - - // Calculate a state with `z * G`. - let mut zG_state = init_ec.clone(); - zG_state.add_mul(message_hash, gen_point); - - // Calculate the point `r * Q`. - let mut rQ_state = init_ec; - rQ_state.add_mul(signature_r, public_key_point); - let Some(rQ) = rQ_state.finalize_nz() else { - // The zero case is not actually possible, as `signature_r` isn't 0. - return false; - }; - - // Check the `(zG + rQ).x = sR.x` case. - let mut zG_plus_eQ_state = zG_state.clone(); - zG_plus_eQ_state.add(rQ); - if let Some(pt) = zG_plus_eQ_state.finalize_nz() && pt.x() == sR_x { - return true; - } - - // Check the `(zG - rQ).x = sR.x` case. - let mut zG_minus_eQ_state = zG_state; - zG_minus_eQ_state.sub(rQ); - if let Some(pt) = zG_minus_eQ_state.finalize_nz() && pt.x() == sR_x { - return true; - } - - false -} - -/// Recovers the public key from an ECDSA signature and message hash. -/// -/// Given a valid ECDSA signature, the original message hash, and the y-coordinate parity of point -/// R, this function recovers the signer's public key. This is useful in scenarios where you need to -/// verify a message has been signed by a specific public key. -/// -/// # Arguments -/// * `message_hash` - The hash of the signed message -/// * `signature_r` - The r component of the ECDSA signature (x-coordinate of point R) -/// * `signature_s` - The s component of the ECDSA signature -/// * `y_parity` - The parity of the y-coordinate of point R (`true` for odd, `false` for even) -/// -/// # Returns -/// Returns `Some(public_key)` containing the x-coordinate of the recovered public key point if -/// the signature is valid, `None` otherwise. -/// -/// # Examples -/// -/// ``` -/// use core::ecdsa::recover_public_key; -/// -/// let message_hash = 0x503f4bea29baee10b22a7f10bdc82dda071c977c1f25b8f3973d34e6b03b2c; -/// let signature_r = 0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb; -/// let signature_s = 0x677ae6bba6daf00d2631fab14c8acf24be6579f9d9e98f67aa7f2770e57a1f5; -/// assert!( -/// recover_public_key(:message_hash, :signature_r, :signature_s, y_parity: false) -/// .unwrap() == 0x7b7454acbe7845da996377f85eb0892044d75ae95d04d3325a391951f35d2ec, -/// ) -/// ``` -pub fn recover_public_key( - message_hash: felt252, signature_r: felt252, signature_s: felt252, y_parity: bool, -) -> Option { - if is_equivalent_to_zero(signature_s) { - return None; - } - - let r_point = EcPointTrait::new_nz_from_x(signature_r)?; - let gen_point = generator_point()?; - - // a Valid signature should satisfy: - // zG + rQ = sR. - // Where: - // zG = z * G, z is the message and G is a generator of the EC. - // rQ = r * Q, Q.x = public_key. - // sR = s * R, where R.x = r and R.y is determined by y_parity. - // - // Hence: - // rQ = sR - zG. - // Q = (s/r)R - (z/r)G - // and we can recover the public key using: - // Q.x = ((s/r)R - (z/r)G).x. - let r_nz: u256 = signature_r.into(); - let r_nz = r_nz.try_into()?; - use ec::stark_curve::ORDER as ORD; - const ORD_U256: u256 = ORD.into(); - const ORD_NZ: NonZero = ORD_U256.try_into().unwrap(); - let r_inv = math::u256_inv_mod(r_nz, ORD_NZ)?.into(); - let s_div_r: felt252 = math::u256_mul_mod_n(signature_s.into(), r_inv, ORD_NZ).try_into()?; - let z_div_r: felt252 = math::u256_mul_mod_n(message_hash.into(), r_inv, ORD_NZ).try_into()?; - let mut state = EcStateTrait::init(); - let ord = ORD; - state.add_mul(ord - z_div_r, gen_point); - // Checking if the actual parity of the point's y is different from the requested, and if so, - // flipping the multiplier instead of negating the point to match the requested parity. - let y: u256 = r_point.y().into(); - let r_multiplier = if (y.low & 1 != 0) ^ y_parity { - ord - s_div_r - } else { - s_div_r - }; - state.add_mul(r_multiplier, r_point); - Some(state.finalize_nz()?.x()) -} - -/// Checks if `value == 0` (mod stark_curve::ORDER). -fn is_equivalent_to_zero(value: felt252) -> bool { - // Note that `2 * ec::stark_curve::ORDER` is larger than the felt252 PRIME. - value == 0 || value == ec::stark_curve::ORDER -} - -// TODO(orizi): Remove this function on next Sierra release. -/// Returns the generator point of the elliptic curve. -/// -/// Note: Cannot actually fail, as the generator point is always valid. -#[cfg(not(sierra: "future"))] -fn generator_point() -> Option { - EcPointTrait::new_nz(ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y) -} - -// TODO(orizi): Remove this function and use `generator::value()` directly on next Sierra release. -/// Returns the generator point of the elliptic curve. -/// -/// Note: Cannot actually fail, as the generator point is always valid. -#[cfg(sierra: "future")] -fn generator_point() -> Option { - Some(generator::value()) -} - -#[cfg(sierra: "future")] -mod generator { - use crate::ec; - - mod v { - /// Const type variant for the EcPoint type. - pub extern type Const; - } - - mod nz { - /// Non-zero const type variant for the EcPoint type. - pub extern type Const; - } - - /// Extern declaration for fetching the actual value. - extern fn const_as_immediate() -> NonZero nopanic; - - /// Returns the generator point of the elliptic curve. - pub fn value() -> ec::NonZeroEcPoint { - const_as_immediate::< - nz::Const< - ec::NonZeroEcPoint, - v::Const, - >, - >() - } -} diff --git a/corelib/src/felt_252.cairo b/corelib/src/felt_252.cairo deleted file mode 100644 index ae1576c041..0000000000 --- a/corelib/src/felt_252.cairo +++ /dev/null @@ -1,35 +0,0 @@ -//! Utilities for the `felt252` type. -//! -//! The implementations defined in this module can be accessed by using the traits directly. - -pub(crate) impl Felt252Zero of crate::num::traits::Zero { - const fn zero() -> felt252 { - 0 - } - - #[inline] - const fn is_zero(self: @felt252) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @felt252) -> bool { - !self.is_zero() - } -} - -pub(crate) impl Felt252One of crate::num::traits::One { - fn one() -> felt252 { - 1 - } - - #[inline] - fn is_one(self: @felt252) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @felt252) -> bool { - !self.is_one() - } -} diff --git a/corelib/src/fixed_size_array.cairo b/corelib/src/fixed_size_array.cairo deleted file mode 100644 index c0350a0ea4..0000000000 --- a/corelib/src/fixed_size_array.cairo +++ /dev/null @@ -1,498 +0,0 @@ -use crate::metaprogramming::{SnapRemove, TupleExtendFront, TupleSnapForward, TupleSplit}; -use crate::tuple::{DefaultNext, SerdeTuple, TuplePartialEq, TuplePartialEqHelper}; - -impl TupleSplitFixedSizedArraySized1 of TupleSplit<[T; 1]> { - type Head = T; - type Rest = [T; 0]; - fn split_head(self: [T; 1]) -> (T, [T; 0]) nopanic { - let [e0] = self; - (e0, []) - } - fn reconstruct(head: T, rest: [T; 0]) -> [T; 1] nopanic { - let [] = rest; - [head] - } -} - -impl TupleSplitFixedSizedArraySized2 of TupleSplit<[T; 2]> { - type Head = T; - type Rest = [T; 1]; - fn split_head(self: [T; 2]) -> (T, [T; 1]) nopanic { - let [e0, e1] = self; - (e0, [e1]) - } - fn reconstruct(head: T, rest: [T; 1]) -> [T; 2] nopanic { - let [e1] = rest; - [head, e1] - } -} - -impl TupleSplitFixedSizedArraySized3 of TupleSplit<[T; 3]> { - type Head = T; - type Rest = [T; 2]; - fn split_head(self: [T; 3]) -> (T, [T; 2]) nopanic { - let [e0, e1, e2] = self; - (e0, [e1, e2]) - } - fn reconstruct(head: T, rest: [T; 2]) -> [T; 3] nopanic { - let [e1, e2] = rest; - [head, e1, e2] - } -} - -impl TupleSplitFixedSizedArraySized4 of TupleSplit<[T; 4]> { - type Head = T; - type Rest = [T; 3]; - fn split_head(self: [T; 4]) -> (T, [T; 3]) nopanic { - let [e0, e1, e2, e3] = self; - (e0, [e1, e2, e3]) - } - fn reconstruct(head: T, rest: [T; 3]) -> [T; 4] nopanic { - let [e1, e2, e3] = rest; - [head, e1, e2, e3] - } -} - -impl TupleSplitFixedSizedArraySized5 of TupleSplit<[T; 5]> { - type Head = T; - type Rest = [T; 4]; - fn split_head(self: [T; 5]) -> (T, [T; 4]) nopanic { - let [e0, e1, e2, e3, e4] = self; - (e0, [e1, e2, e3, e4]) - } - fn reconstruct(head: T, rest: [T; 4]) -> [T; 5] nopanic { - let [e1, e2, e3, e4] = rest; - [head, e1, e2, e3, e4] - } -} - -impl TupleSplitFixedSizedArraySized6 of TupleSplit<[T; 6]> { - type Head = T; - type Rest = [T; 5]; - fn split_head(self: [T; 6]) -> (T, [T; 5]) nopanic { - let [e0, e1, e2, e3, e4, e5] = self; - (e0, [e1, e2, e3, e4, e5]) - } - fn reconstruct(head: T, rest: [T; 5]) -> [T; 6] nopanic { - let [e1, e2, e3, e4, e5] = rest; - [head, e1, e2, e3, e4, e5] - } -} - -impl TupleSplitFixedSizedArraySized7 of TupleSplit<[T; 7]> { - type Head = T; - type Rest = [T; 6]; - fn split_head(self: [T; 7]) -> (T, [T; 6]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6] = self; - (e0, [e1, e2, e3, e4, e5, e6]) - } - fn reconstruct(head: T, rest: [T; 6]) -> [T; 7] nopanic { - let [e1, e2, e3, e4, e5, e6] = rest; - [head, e1, e2, e3, e4, e5, e6] - } -} - -impl TupleSplitFixedSizedArraySized8 of TupleSplit<[T; 8]> { - type Head = T; - type Rest = [T; 7]; - fn split_head(self: [T; 8]) -> (T, [T; 7]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7]) - } - fn reconstruct(head: T, rest: [T; 7]) -> [T; 8] nopanic { - let [e1, e2, e3, e4, e5, e6, e7] = rest; - [head, e1, e2, e3, e4, e5, e6, e7] - } -} - -impl TupleSplitFixedSizedArraySized9 of TupleSplit<[T; 9]> { - type Head = T; - type Rest = [T; 8]; - fn split_head(self: [T; 9]) -> (T, [T; 8]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8]) - } - fn reconstruct(head: T, rest: [T; 8]) -> [T; 9] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8] - } -} - -impl TupleSplitFixedSizedArraySized10 of TupleSplit<[T; 10]> { - type Head = T; - type Rest = [T; 9]; - fn split_head(self: [T; 10]) -> (T, [T; 9]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9]) - } - fn reconstruct(head: T, rest: [T; 9]) -> [T; 10] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9] - } -} - -impl TupleSplitFixedSizedArraySized11 of TupleSplit<[T; 11]> { - type Head = T; - type Rest = [T; 10]; - fn split_head(self: [T; 11]) -> (T, [T; 10]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10]) - } - fn reconstruct(head: T, rest: [T; 10]) -> [T; 11] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] - } -} - -impl TupleSplitFixedSizedArraySized12 of TupleSplit<[T; 12]> { - type Head = T; - type Rest = [T; 11]; - fn split_head(self: [T; 12]) -> (T, [T; 11]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11]) - } - fn reconstruct(head: T, rest: [T; 11]) -> [T; 12] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] - } -} - -impl TupleSplitFixedSizedArraySized13 of TupleSplit<[T; 13]> { - type Head = T; - type Rest = [T; 12]; - fn split_head(self: [T; 13]) -> (T, [T; 12]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12]) - } - fn reconstruct(head: T, rest: [T; 12]) -> [T; 13] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] - } -} - -impl TupleSplitFixedSizedArraySized14 of TupleSplit<[T; 14]> { - type Head = T; - type Rest = [T; 13]; - fn split_head(self: [T; 14]) -> (T, [T; 13]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13]) - } - fn reconstruct(head: T, rest: [T; 13]) -> [T; 14] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] - } -} - -impl TupleSplitFixedSizedArraySized15 of TupleSplit<[T; 15]> { - type Head = T; - type Rest = [T; 14]; - fn split_head(self: [T; 15]) -> (T, [T; 14]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14]) - } - fn reconstruct(head: T, rest: [T; 14]) -> [T; 15] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] - } -} - -impl TupleSplitFixedSizedArraySized16 of TupleSplit<[T; 16]> { - type Head = T; - type Rest = [T; 15]; - fn split_head(self: [T; 16]) -> (T, [T; 15]) nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] = self; - (e0, [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15]) - } - fn reconstruct(head: T, rest: [T; 15]) -> [T; 16] nopanic { - let [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] = rest; - [head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] - } -} - - -impl TupleExtendFrontFixedSizedArraySize0 of TupleExtendFront<[T; 0], T> { - type Result = [T; 1]; - fn extend_front(value: [T; 0], element: T) -> [T; 1] nopanic { - let [] = value; - [element] - } -} - -impl TupleExtendFrontFixedSizedArraySize1 of TupleExtendFront<[T; 1], T> { - type Result = [T; 2]; - fn extend_front(value: [T; 1], element: T) -> [T; 2] nopanic { - let [e0] = value; - [element, e0] - } -} - -impl TupleExtendFrontFixedSizedArraySize2 of TupleExtendFront<[T; 2], T> { - type Result = [T; 3]; - fn extend_front(value: [T; 2], element: T) -> [T; 3] nopanic { - let [e0, e1] = value; - [element, e0, e1] - } -} - -impl TupleExtendFrontFixedSizedArraySize3 of TupleExtendFront<[T; 3], T> { - type Result = [T; 4]; - fn extend_front(value: [T; 3], element: T) -> [T; 4] nopanic { - let [e0, e1, e2] = value; - [element, e0, e1, e2] - } -} - -impl TupleExtendFrontFixedSizedArraySize4 of TupleExtendFront<[T; 4], T> { - type Result = [T; 5]; - fn extend_front(value: [T; 4], element: T) -> [T; 5] nopanic { - let [e0, e1, e2, e3] = value; - [element, e0, e1, e2, e3] - } -} - -impl TupleExtendFrontFixedSizedArraySize5 of TupleExtendFront<[T; 5], T> { - type Result = [T; 6]; - fn extend_front(value: [T; 5], element: T) -> [T; 6] nopanic { - let [e0, e1, e2, e3, e4] = value; - [element, e0, e1, e2, e3, e4] - } -} - -impl TupleExtendFrontFixedSizedArraySize6 of TupleExtendFront<[T; 6], T> { - type Result = [T; 7]; - fn extend_front(value: [T; 6], element: T) -> [T; 7] nopanic { - let [e0, e1, e2, e3, e4, e5] = value; - [element, e0, e1, e2, e3, e4, e5] - } -} - -impl TupleExtendFrontFixedSizedArraySize7 of TupleExtendFront<[T; 7], T> { - type Result = [T; 8]; - fn extend_front(value: [T; 7], element: T) -> [T; 8] nopanic { - let [e0, e1, e2, e3, e4, e5, e6] = value; - [element, e0, e1, e2, e3, e4, e5, e6] - } -} - -impl TupleExtendFrontFixedSizedArraySize8 of TupleExtendFront<[T; 8], T> { - type Result = [T; 9]; - fn extend_front(value: [T; 8], element: T) -> [T; 9] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7] - } -} - -impl TupleExtendFrontFixedSizedArraySize9 of TupleExtendFront<[T; 9], T> { - type Result = [T; 10]; - fn extend_front(value: [T; 9], element: T) -> [T; 10] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8] - } -} - -impl TupleExtendFrontFixedSizedArraySize10 of TupleExtendFront<[T; 10], T> { - type Result = [T; 11]; - fn extend_front(value: [T; 10], element: T) -> [T; 11] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9] - } -} - -impl TupleExtendFrontFixedSizedArraySize11 of TupleExtendFront<[T; 11], T> { - type Result = [T; 12]; - fn extend_front(value: [T; 11], element: T) -> [T; 12] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] - } -} - -impl TupleExtendFrontFixedSizedArraySize12 of TupleExtendFront<[T; 12], T> { - type Result = [T; 13]; - fn extend_front(value: [T; 12], element: T) -> [T; 13] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] - } -} - -impl TupleExtendFrontFixedSizedArraySize13 of TupleExtendFront<[T; 13], T> { - type Result = [T; 14]; - fn extend_front(value: [T; 13], element: T) -> [T; 14] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] - } -} - -impl TupleExtendFrontFixedSizedArraySize14 of TupleExtendFront<[T; 14], T> { - type Result = [T; 15]; - fn extend_front(value: [T; 14], element: T) -> [T; 15] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] - } -} - -impl TupleExtendFrontFixedSizedArraySize15 of TupleExtendFront<[T; 15], T> { - type Result = [T; 16]; - fn extend_front(value: [T; 15], element: T) -> [T; 16] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] = value; - [element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] - } -} - - -impl TupleSnapForwardFixedSizedArraySized0 of TupleSnapForward<[T; 0]> { - type SnapForward = [@T; 0]; - fn snap_forward(self: @[T; 0]) -> [@T; 0] nopanic { - [] - } -} - -impl TupleSnapForwardFixedSizedArraySized1 of TupleSnapForward<[T; 1]> { - type SnapForward = [@T; 1]; - fn snap_forward(self: @[T; 1]) -> [@T; 1] nopanic { - let [e0] = self; - [e0] - } -} - -impl TupleSnapForwardFixedSizedArraySized2 of TupleSnapForward<[T; 2]> { - type SnapForward = [@T; 2]; - fn snap_forward(self: @[T; 2]) -> [@T; 2] nopanic { - let [e0, e1] = self; - [e0, e1] - } -} - -impl TupleSnapForwardFixedSizedArraySized3 of TupleSnapForward<[T; 3]> { - type SnapForward = [@T; 3]; - fn snap_forward(self: @[T; 3]) -> [@T; 3] nopanic { - let [e0, e1, e2] = self; - [e0, e1, e2] - } -} - -impl TupleSnapForwardFixedSizedArraySized4 of TupleSnapForward<[T; 4]> { - type SnapForward = [@T; 4]; - fn snap_forward(self: @[T; 4]) -> [@T; 4] nopanic { - let [e0, e1, e2, e3] = self; - [e0, e1, e2, e3] - } -} - -impl TupleSnapForwardFixedSizedArraySized5 of TupleSnapForward<[T; 5]> { - type SnapForward = [@T; 5]; - fn snap_forward(self: @[T; 5]) -> [@T; 5] nopanic { - let [e0, e1, e2, e3, e4] = self; - [e0, e1, e2, e3, e4] - } -} - -impl TupleSnapForwardFixedSizedArraySized6 of TupleSnapForward<[T; 6]> { - type SnapForward = [@T; 6]; - fn snap_forward(self: @[T; 6]) -> [@T; 6] nopanic { - let [e0, e1, e2, e3, e4, e5] = self; - [e0, e1, e2, e3, e4, e5] - } -} - -impl TupleSnapForwardFixedSizedArraySized7 of TupleSnapForward<[T; 7]> { - type SnapForward = [@T; 7]; - fn snap_forward(self: @[T; 7]) -> [@T; 7] nopanic { - let [e0, e1, e2, e3, e4, e5, e6] = self; - [e0, e1, e2, e3, e4, e5, e6] - } -} - -impl TupleSnapForwardFixedSizedArraySized8 of TupleSnapForward<[T; 8]> { - type SnapForward = [@T; 8]; - fn snap_forward(self: @[T; 8]) -> [@T; 8] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7] = self; - [e0, e1, e2, e3, e4, e5, e6, e7] - } -} - -impl TupleSnapForwardFixedSizedArraySized9 of TupleSnapForward<[T; 9]> { - type SnapForward = [@T; 9]; - fn snap_forward(self: @[T; 9]) -> [@T; 9] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8] - } -} - -impl TupleSnapForwardFixedSizedArraySized10 of TupleSnapForward<[T; 10]> { - type SnapForward = [@T; 10]; - fn snap_forward(self: @[T; 10]) -> [@T; 10] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9] - } -} - -impl TupleSnapForwardFixedSizedArraySized11 of TupleSnapForward<[T; 11]> { - type SnapForward = [@T; 11]; - fn snap_forward(self: @[T; 11]) -> [@T; 11] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] - } -} - -impl TupleSnapForwardFixedSizedArraySized12 of TupleSnapForward<[T; 12]> { - type SnapForward = [@T; 12]; - fn snap_forward(self: @[T; 12]) -> [@T; 12] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] - } -} - -impl TupleSnapForwardFixedSizedArraySized13 of TupleSnapForward<[T; 13]> { - type SnapForward = [@T; 13]; - fn snap_forward(self: @[T; 13]) -> [@T; 13] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] - } -} - -impl TupleSnapForwardFixedSizedArraySized14 of TupleSnapForward<[T; 14]> { - type SnapForward = [@T; 14]; - fn snap_forward(self: @[T; 14]) -> [@T; 14] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] - } -} - -impl TupleSnapForwardFixedSizedArraySized15 of TupleSnapForward<[T; 15]> { - type SnapForward = [@T; 15]; - fn snap_forward(self: @[T; 15]) -> [@T; 15] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] - } -} - -impl TupleSnapForwardFixedSizedArraySized16 of TupleSnapForward<[T; 16]> { - type SnapForward = [@T; 16]; - fn snap_forward(self: @[T; 16]) -> [@T; 16] nopanic { - let [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] = self; - [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] - } -} - -impl SnapRemoveFixedSizedArray of SnapRemove<[@T; N]> { - type Result = [T; N]; -} - -impl TuplePartialEqHelperBaseFixedSizedArray of TuplePartialEqHelper<[@T; 0]> { - fn eq(lhs: [@T; 0], rhs: [@T; 0]) -> bool { - true - } - fn ne(lhs: [@T; 0], rhs: [@T; 0]) -> bool { - false - } -} - - -impl DefaultFixedSizedArray of Default<[T; 0]> { - fn default() -> [T; 0] { - [] - } -} - -impl FixedSizedArrayDrop, const N: usize> of Drop<[T; N]>; -impl FixedSizedArrayCopy, const N: usize> of Copy<[T; N]>; diff --git a/corelib/src/fmt.cairo b/corelib/src/fmt.cairo deleted file mode 100644 index ecc7b81655..0000000000 --- a/corelib/src/fmt.cairo +++ /dev/null @@ -1,372 +0,0 @@ -//! Functionality for formatting values. -//! -//! The main components of this module are: -//! -//! - `Error`: A type representing formatting errors. -//! - `Formatter`: A struct that holds the configuration and buffer for formatting. -//! - `Display`: A trait for standard formatting using the empty format ("{}"). -//! - `Debug`: A trait for debug formatting using the empty format ("{:?}"). -//! - `LowerHex`: A trait for hex formatting in lower case. -//! -//! The module includes implementations of the [`Display`], [`Debug`] and [`LowerHex`] traits for -//! various types. - -/// Dedicated type for representing formatting errors. -#[derive(Drop)] -pub struct Error {} - -/// Configuration for formatting. -#[derive(Default, Drop)] -pub struct Formatter { - /// The pending result of formatting. - pub buffer: ByteArray, -} - -/// A trait for standard formatting, using the empty format ("{}"). -/// -/// # Examples -/// -/// ``` -/// let word: ByteArray = "123"; -/// println!("{}", word); -/// ``` -pub trait Display { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error>; -} - -impl DisplayByteArray of Display { - fn fmt(self: @ByteArray, ref f: Formatter) -> Result<(), Error> { - f.buffer.append(self); - Ok(()) - } -} - -#[feature("byte-span")] -impl DisplayByteSpan of Display { - fn fmt(self: @crate::byte_array::ByteSpan, ref f: Formatter) -> Result<(), Error> { - DisplayByteArray::fmt(@crate::byte_array::ByteSpanTrait::to_byte_array(*self), ref f) - } -} - -impl DisplayInteger< - T, +crate::to_byte_array::AppendFormattedToByteArray, +Into, +TryInto>, -> of Display { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { - // TODO(yuval): determine base according to Formatter parameters. - let base: T = 10_u8.into(); - self.append_formatted_to_byte_array(ref f.buffer, base.try_into().unwrap()); - Ok(()) - } -} - -impl DisplaySignedInteger< - Signed, - Unsigned, - +crate::integer::AbsAndSign, - +Display, - +Copy, - +Drop, -> of Display { - fn fmt(self: @Signed, ref f: Formatter) -> Result<(), Error> { - let (abs, sign) = (*self).abs_and_sign(); - if sign { - write!(f, "-")?; - } - abs.fmt(ref f) - } -} - -impl DisplayNonZero, +Copy, +Drop> of Display> { - fn fmt(self: @NonZero, ref f: Formatter) -> Result<(), Error> { - let value: T = (*self).into(); - write!(f, "{value}") - } -} - -impl DisplayBool of Display { - fn fmt(self: @bool, ref f: Formatter) -> Result<(), Error> { - if *self { - write!(f, "true") - } else { - write!(f, "false") - } - } -} - -impl DisplaySnapshot> of Display<@T> { - fn fmt(self: @@T, ref f: Formatter) -> Result<(), Error> { - Display::fmt(*self, ref f) - } -} - -/// A trait for debug formatting, using the empty format ("{:?}"). -/// -/// # Examples -/// -/// ``` -/// let word: ByteArray = "123"; -/// println!("{:?}", word); -/// ``` -pub trait Debug { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error>; -} - -impl DebugByteArray of Debug { - fn fmt(self: @ByteArray, ref f: Formatter) -> Result<(), Error> { - write!(f, "\"")?; - Display::fmt(self, ref f)?; - write!(f, "\"") - } -} - -// TODO(giladchase): find a way to do this by applying `ByteArray::extend` on the bytespan. -#[feature("byte-span")] -impl DebugByteSpan of Debug { - fn fmt(self: @crate::byte_array::ByteSpan, ref f: Formatter) -> Result<(), Error> { - write!(f, "\"")?; - Display::fmt(self, ref f)?; - write!(f, "\"") - } -} - -impl DebugInteger< - T, +crate::to_byte_array::AppendFormattedToByteArray, +Into, +TryInto>, -> of Debug { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { - Display::fmt(self, ref f) - } -} - -impl DebugSignedInteger< - Signed, - Unsigned, - +crate::integer::AbsAndSign, - +Display, - +Copy, - +Drop, -> of Debug { - fn fmt(self: @Signed, ref f: Formatter) -> Result<(), Error> { - Display::fmt(self, ref f) - } -} - -impl DebugNonZero, +Copy, +Drop> of Debug> { - fn fmt(self: @NonZero, ref f: Formatter) -> Result<(), Error> { - let value: T = (*self).into(); - write!(f, "{value:?}") - } -} - -impl DebugBool of Debug { - fn fmt(self: @bool, ref f: Formatter) -> Result<(), Error> { - Display::fmt(self, ref f) - } -} - -impl DebugSnapshot> of Debug<@T> { - fn fmt(self: @@T, ref f: Formatter) -> Result<(), Error> { - write!(f, "@")?; - Debug::fmt(*self, ref f) - } -} - -impl TupleDebug< - T, - impl TSF: crate::metaprogramming::TupleSnapForward, - +TupleDebugHelper, - +crate::metaprogramming::IsTuple, -> of Debug { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { - write!(f, "(")?; - TupleDebugHelper::fmt(TSF::snap_forward(self), ref f)?; - write!(f, ")") - } -} - -impl FixedSizedArrayDebug< - T, - impl TSF: crate::metaprogramming::TupleSnapForward, - +TupleDebugHelper, - -crate::metaprogramming::IsTuple, -> of Debug { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { - write!(f, "[")?; - TupleDebugHelper::fmt(TSF::snap_forward(self), ref f)?; - write!(f, "]") - } -} - -/// A helper trait for `Debug` implementation of tuples. -trait TupleDebugHelper { - fn fmt(value: T, ref f: Formatter) -> Result<(), Error>; -} - -impl TupleDebugHelperFromDebug> of TupleDebugHelper<@T> { - fn fmt(value: @T, ref f: Formatter) -> Result<(), Error> { - Debug::fmt(value, ref f) - } -} - -impl TupleDebugHelperTuple0 of TupleDebugHelper<()> { - fn fmt(value: (), ref f: Formatter) -> Result<(), Error> { - Ok(()) - } -} - -impl TupleDebugHelperTuple1> of TupleDebugHelper<(@E0,)> { - fn fmt(value: (@E0,), ref f: Formatter) -> Result<(), Error> { - let (e0,) = value; - TupleDebugHelper::fmt(e0, ref f)?; - write!(f, ",") - } -} - -impl TupleDebugHelperTuple2< - E0, E1, +TupleDebugHelper<@E0>, +TupleDebugHelper<@E1>, -> of TupleDebugHelper<(@E0, @E1)> { - fn fmt(value: (@E0, @E1), ref f: Formatter) -> Result<(), Error> { - let (e0, e1) = value; - TupleDebugHelper::fmt(e0, ref f)?; - write!(f, ", ")?; - TupleDebugHelper::fmt(e1, ref f) - } -} - -// `Debug` impl for tuples of size 3 and above. -// Not starting from size 1 nor 2 since we have special cases for 1 and 2. -impl TupleDebugHelperTupleNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - +crate::metaprogramming::IsTuple, - +TupleDebugHelper, - +TupleDebugHelper, - +Drop, - // Making sure the size it at least 3. - impl NTS: crate::metaprogramming::TupleSplit, - +crate::metaprogramming::TupleSplit, -> of TupleDebugHelper { - fn fmt(value: T, ref f: Formatter) -> Result<(), Error> { - fmt_head_and_rest(value, ref f) - } -} - -impl TupleDebugHelperFixedSizedArray0 of TupleDebugHelper<[@T; 0]> { - fn fmt(value: [@T; 0], ref f: Formatter) -> Result<(), Error> { - Ok(()) - } -} - -impl TupleDebugHelperFixedSizedArray1> of TupleDebugHelper<[@T; 1]> { - fn fmt(value: [@T; 1], ref f: Formatter) -> Result<(), Error> { - let [e0] = value; - TupleDebugHelper::fmt(e0, ref f) - } -} - -// `Debug` impl for fixed sized arrays of size 2 and above. -// Not starting from size 1 since we have a special case for 1. -impl TupleDebugHelperFixedSizedArrayNext< - T, - const N: usize, - impl TS: crate::metaprogramming::TupleSplit<[@T; N]>, - +TupleDebugHelper, - +TupleDebugHelper, - +Drop, - // Making sure the size it at least 2. - +crate::metaprogramming::TupleSplit, -> of TupleDebugHelper<[@T; N]> { - fn fmt(value: [@T; N], ref f: Formatter) -> Result<(), Error> { - fmt_head_and_rest(value, ref f) - } -} - -/// A helper function for formatting the head and tail of a tuple style struct. -fn fmt_head_and_rest< - T, - impl TS: crate::metaprogramming::TupleSplit, - +TupleDebugHelper, - +TupleDebugHelper, - +Drop, ->( - value: T, ref f: Formatter, -) -> Result<(), Error> { - let (head, rest) = TS::split_head(value); - TupleDebugHelper::fmt(head, ref f)?; - write!(f, ", ")?; - TupleDebugHelper::fmt(rest, ref f) -} - -impl ArrayTDebug> of Debug> { - fn fmt(self: @Array, ref f: Formatter) -> Result<(), Error> { - Debug::fmt(@self.span(), ref f) - } -} - -impl SpanTDebug> of Debug> { - fn fmt(self: @Span, ref f: Formatter) -> Result<(), Error> { - let mut self = *self; - write!(f, "[")?; - loop { - match self.pop_front() { - Some(value) => { - if Debug::fmt(value, ref f).is_err() { - break Err(Error {}); - } - if self.is_empty() { - break Ok(()); - } - if write!(f, ", ").is_err() { - break Err(Error {}); - } - }, - None => { break Ok(()); }, - } - }?; - write!(f, "]") - } -} - -/// Implementations for `Debug` and `LowerHex` for types that can be converted into `felt252` using -/// the `Into` trait. -/// -/// # Examples -/// -/// ``` -/// impl MyTypeDebug = crate::fmt::into_felt252_based::DebugImpl; -/// impl MyTypeLowerHex = crate::fmt::into_felt252_based::LowerHexImpl; -/// ``` -pub mod into_felt252_based { - pub impl DebugImpl, +Copy> of crate::fmt::Debug { - fn fmt(self: @T, ref f: crate::fmt::Formatter) -> Result<(), crate::fmt::Error> { - crate::fmt::DebugInteger::::fmt(@(*self).into(), ref f) - } - } - - pub impl LowerHexImpl, +Copy> of core::fmt::LowerHex { - fn fmt(self: @T, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> { - core::fmt::LowerHexInteger::::fmt(@(*self).into(), ref f) - } - } -} - -/// A trait for hex formatting in lower case, using the empty format ("{:x}"). -pub trait LowerHex { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error>; -} - -impl LowerHexInteger< - T, +crate::to_byte_array::AppendFormattedToByteArray, +Into, +TryInto>, -> of LowerHex { - fn fmt(self: @T, ref f: Formatter) -> Result<(), Error> { - let base: T = 16_u8.into(); - self.append_formatted_to_byte_array(ref f.buffer, base.try_into().unwrap()); - Ok(()) - } -} - -impl LowerHexNonZero, +Copy, +Drop> of LowerHex> { - fn fmt(self: @NonZero, ref f: Formatter) -> Result<(), Error> { - let value: T = (*self).into(); - write!(f, "{value:x}") - } -} diff --git a/corelib/src/gas.cairo b/corelib/src/gas.cairo deleted file mode 100644 index fd6bc50c0c..0000000000 --- a/corelib/src/gas.cairo +++ /dev/null @@ -1,96 +0,0 @@ -//! Utilities for handling gas in Cairo code. - -#[cfg(not(gas: "disabled"))] -use crate::RangeCheck; - -/// Type representing the table of the costs of the different builtin usages. -#[cfg(not(gas: "disabled"))] -pub extern type BuiltinCosts; - -/// Placeholder when gas mechanism is disabled. -#[cfg(gas: "disabled")] -pub struct BuiltinCosts {} - -impl BuiltinCostsCopy of Copy; -impl BuiltinCostsDrop of Drop; - -/// The gas builtin. -/// This type is used to handle gas in the Cairo code. -/// Contains the amount of gas available for the current run. -pub extern type GasBuiltin; - -/// Withdraws gas from the `GasBuiltin` to handle the success case flow. -/// Returns `Some(())` if there is sufficient gas to handle the success case, otherwise -/// returns `None`. -/// -/// # Examples -/// -/// ``` -/// // The success branch is the following lines, the failure branch is the `panic` caused by the -/// // `unwrap` call. -/// withdraw_gas().unwrap(); -/// ``` -/// -/// ``` -/// // Direct handling of `withdraw_gas`. -/// match withdraw_gas() { -/// Some(()) => success_case(), -/// None => cheap_not_enough_gas_case(), -/// } -/// ``` -#[cfg(not(gas: "disabled"))] -pub extern fn withdraw_gas() -> Option<()> implicits(RangeCheck, GasBuiltin) nopanic; - -/// Placeholder when gas mechanism is disabled. -#[cfg(gas: "disabled")] -pub fn withdraw_gas() -> Option<()> nopanic { - Some(()) -} - -/// Same as `withdraw_gas`, but directly receives `BuiltinCosts`, which enables optimizations -/// by removing the need for repeated internal calls for fetching the table of constants that may -/// internally happen in calls to `withdraw_gas`. -/// Should be used with caution. -#[cfg(not(gas: "disabled"))] -pub extern fn withdraw_gas_all( - costs: BuiltinCosts, -) -> Option<()> implicits(RangeCheck, GasBuiltin) nopanic; - -/// Placeholder when gas mechanism is disabled. -#[cfg(gas: "disabled")] -pub fn withdraw_gas_all(costs: BuiltinCosts) -> Option<()> nopanic { - Some(()) -} - -/// Returns unused gas into the gas builtin. -/// -/// Useful for cases where different branches take different amounts of gas, but gas withdrawal is -/// the same for both. -pub extern fn redeposit_gas() implicits(GasBuiltin) nopanic; - -/// Returns the `BuiltinCosts` table to be used in `withdraw_gas_all`. -#[cfg(not(gas: "disabled"))] -pub extern fn get_builtin_costs() -> BuiltinCosts nopanic; - -/// Placeholder when gas mechanism is disabled. -#[cfg(gas: "disabled")] -pub fn get_builtin_costs() -> BuiltinCosts nopanic { - BuiltinCosts {} -} - -/// Represents a gas reserve. -/// -/// Gas reserves can be created at any point using gas from the gas counter, -/// and can be utilized at a later point in time. -pub extern type GasReserve; - -/// Creates a new gas reserve by withdrawing the specified amount from the gas counter. -/// Returns `Some(GasReserve)` if there is sufficient gas, otherwise returns `None`. -#[cfg(not(gas: "disabled"))] -pub extern fn gas_reserve_create( - amount: u128, -) -> Option implicits(RangeCheck, GasBuiltin) nopanic; - -/// Adds the gas stored in the reserve back to the gas counter. -/// The reserve is consumed in the process. -pub extern fn gas_reserve_utilize(reserve: GasReserve) implicits(GasBuiltin) nopanic; diff --git a/corelib/src/hash.cairo b/corelib/src/hash.cairo deleted file mode 100644 index 0eb164dc23..0000000000 --- a/corelib/src/hash.cairo +++ /dev/null @@ -1,231 +0,0 @@ -//! Generic hashing support. -//! -//! This module provides a hash state abstraction that can be updated with values and finalized to -//! produce a hash. This allows for flexible and efficient hashing of any type with different hash -//! functions. -//! -//! The simplest way to make a type hashable is to use `#[derive(Hash)]`. Hashing a value is done by -//! initiating a `HashState` corresponding to a hash function, updating it with the value, and then -//! finalizing it to get the hash result. -//! -//! # Examples -//! -//! Basic usage with Pedersen and Poseidon hash: -//! -//! ``` -//! use core::pedersen::PedersenTrait; -//! use core::poseidon::PoseidonTrait; -//! -//! #[derive(Copy, Drop, Hash)] -//! struct Person { -//! id: u32, -//! phone: u64, -//! } -//! -//! fn main() { -//! let person1 = Person { id: 1, phone: 555_666_7777 }; -//! let person2 = Person { id: 2, phone: 555_666_7778 }; -//! -//! assert!( -//! PedersenTrait::new(0) -//! .update_with(person1) -//! .finalize() != PedersenTrait::new(0) -//! .update_with(person2) -//! .finalize(), -//! ); -//! assert!( -//! PoseidonTrait::new() -//! .update_with(person1) -//! .finalize() != PoseidonTrait::new() -//! .update_with(person2) -//! .finalize(), -//! ); -//! } -//! ``` - -#[allow(unused_imports)] -use crate::traits::Into; - -/// A trait for hash state accumulators. -/// -/// Provides methods to update a hash state with new values and finalize it into a hash result. -pub trait HashStateTrait { - /// Updates the current hash state `self` with the given `felt252` value and returns a new hash - /// state. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// use core::hash::HashStateTrait; - /// - /// let mut state = PedersenTrait::new(0); - /// state = state.update(1); - /// ``` - #[must_use] - fn update(self: S, value: felt252) -> S; - - /// Takes the current state `self` and returns the hash result. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// use core::hash::HashStateTrait; - /// - /// let mut state = PedersenTrait::new(0); - /// let hash = state.finalize(); - /// ``` - #[must_use] - fn finalize(self: S) -> felt252; -} - -/// A trait for values that can be hashed. -/// -/// This trait should be implemented for any type that can be included in a hash calculation. -/// The most common way to implement this trait is by using `#[derive(Hash)]`. -pub trait Hash> { - /// Updates the hash state with the given value and returns a new hash state. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// use core::hash::Hash; - /// - /// let mut state = PedersenTrait::new(0); - /// let new_state = Hash::update_state(state, 1); - /// ``` - #[must_use] - fn update_state(state: S, value: T) -> S; -} - - -/// A trait for hashing values using a `felt252` as hash state, used for backwards compatibility. -/// NOTE: Implement `Hash` instead of this trait if possible. -pub trait LegacyHash { - /// Takes a `felt252` state and a value of type `T` and returns the hash result. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// use core::hash::LegacyHash; - /// - /// let hash = LegacyHash::hash(0, 1); - /// ``` - #[must_use] - fn hash(state: felt252, value: T) -> felt252; -} - -/// Implementation of `LegacyHash` for types that implement `Hash` for backwards compatibility. -impl LegacyHashForHash> of LegacyHash { - #[inline] - fn hash(state: felt252, value: T) -> felt252 { - crate::pedersen::HashState { state }.update_with(value).state - } -} - -/// Extension trait for hash state accumulators. -/// -/// This trait adds the `update_with` method to hash states, allowing you to directly hash values of -/// any type T that implements `Hash`, rather than having to manually convert values to felt252 -/// first. This provides a more ergonomic API when working with complex types. -pub trait HashStateExTrait { - /// Updates the hash state with the given value and returns the updated state. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// use core::hash::HashStateExTrait; - /// - /// #[derive(Copy, Drop, Hash)] - /// struct Point { x: u32, y: u32 } - /// - /// let point = Point { x: 1, y: 2 }; - /// let hash = PedersenTrait::new(0) - /// .update_with(point) - /// .update_with(42) - /// .finalize(); - /// ``` - #[must_use] - fn update_with(self: S, value: T) -> S; -} - -/// Implementation for `HashStateExTrait` for types that implement `Hash` for backwards -/// compatibility. -impl HashStateEx, T, +Hash> of HashStateExTrait { - #[inline] - fn update_with(self: S, value: T) -> S { - Hash::update_state(self, value) - } -} - -impl HashFelt252> of Hash { - #[inline] - fn update_state(state: S, value: felt252) -> S { - state.update(value) - } -} - -/// Implementation for `Hash` for types that can be converted into `felt252` using the `Into` trait. -/// -/// # Examples -/// -/// ``` -/// impl MyTypeHash, +Drop> = -/// core::hash::into_felt252_based::HashImpl;` -/// ``` -pub mod into_felt252_based { - pub impl HashImpl< - T, S, +Into, +super::HashStateTrait, +Drop, - > of super::Hash { - #[inline] - fn update_state(state: S, value: T) -> S { - state.update(value.into()) - } - } -} - -impl HashBool, +Drop> = into_felt252_based::HashImpl; -impl HashU8, +Drop> = into_felt252_based::HashImpl; -impl HashU16, +Drop> = into_felt252_based::HashImpl; -impl HashU32, +Drop> = into_felt252_based::HashImpl; -impl HashU64, +Drop> = into_felt252_based::HashImpl; -impl HashU128, +Drop> = into_felt252_based::HashImpl; -impl HashI8, +Drop> = into_felt252_based::HashImpl; -impl HashI16, +Drop> = into_felt252_based::HashImpl; -impl HashI32, +Drop> = into_felt252_based::HashImpl; -impl HashI64, +Drop> = into_felt252_based::HashImpl; -impl HashI128, +Drop> = into_felt252_based::HashImpl; - -impl TupleSize0Hash> of Hash<(), S> { - #[inline] - fn update_state(state: S, value: ()) -> S { - state - } -} - -impl FixedSizedArray0Hash, +Drop> of Hash<[T; 0], S> { - #[inline] - fn update_state(state: S, value: [T; 0]) -> S { - state - } -} - -impl TupleNextHash< - T, - S, - +HashStateTrait, - impl TH: crate::metaprogramming::TupleSplit, - +Hash, - +Hash, - +Drop, -> of Hash { - #[inline] - fn update_state(state: S, value: T) -> S { - let (head, rest) = TH::split_head(value); - state.update_with(head).update_with(rest) - } -} diff --git a/corelib/src/integer.cairo b/corelib/src/integer.cairo deleted file mode 100644 index 3c63d8a88e..0000000000 --- a/corelib/src/integer.cairo +++ /dev/null @@ -1,3410 +0,0 @@ -//! Integer types and operations. -//! -//! This module provides the built-in integer types and their associated operations. -//! -//! # Integer Types -//! -//! The following integer types are available: -//! -//! * Unsigned integers: [`u8`], [`u16`], [`u32`], [`u64`], [`u128`], [`u256`] -//! * Signed integers: [`i8`], [`i16`], [`i32`], [`i64`], [`i128`] -//! -//! # Operations -//! -//! Integer types implement various traits that enable common operations: -//! -//! * Basic arithmetic via [`Add`], [`Sub`], [`Mul`], [`Div`], [`Rem`] and [`DivRem`] -//! * Bitwise operations via [`BitAnd`], [`BitOr`], [`BitXor`], and [`BitNot`] -//! * Comparison via [`PartialEq`] and [`PartialOrd`] -//! * Safe arithmetic via [`CheckedAdd`], [`CheckedSub`], [`CheckedMul`] -//! * Wrapping arithmetic via [`WrappingAdd`], [`WrappingSub`], [`WrappingMul`] -//! * Overflow handling via [`OverflowingAdd`], [`OverflowingSub`], [`OverflowingMul`] -//! -//! [`Add`]: crate::traits::Add -//! [`Sub`]: crate::traits::Sub -//! [`Mul`]: crate::traits::Mul -//! [`Div`]: crate::traits::Div -//! [`Rem`]: crate::traits::Rem -//! [`DivRem`]: crate::traits::DivRem -//! [`CheckedAdd`]: crate::num::traits::ops::checked::CheckedAdd -//! [`CheckedSub`]: crate::num::traits::ops::checked::CheckedSub -//! [`CheckedMul`]: crate::num::traits::ops::checked::CheckedMul -//! [`WrappingAdd`]: crate::num::traits::ops::wrapping::WrappingAdd -//! [`WrappingSub`]: crate::num::traits::ops::wrapping::WrappingSub -//! [`WrappingMul`]: crate::num::traits::ops::wrapping::WrappingMul -//! [`OverflowingAdd`]: crate::num::traits::ops::overflowing::OverflowingAdd -//! [`OverflowingSub`]: crate::num::traits::ops::overflowing::OverflowingSub -//! [`OverflowingMul`]: crate::num::traits::ops::overflowing::OverflowingMul -//! -//! # Examples -//! -//! Basic operators: -//! -//! ``` -//! let a: u8 = 5; -//! let b: u8 = 10; -//! assert_eq!(a + b, 15); -//! assert_eq!(a * b, 50); -//! assert_eq!(a & b, 0); -//! assert!(a < b); -//! ``` -//! -//! Checked operations: -//! -//! ``` -//! use core::num::traits::{CheckedAdd, Bounded}; -//! -//! let max: u8 = Bounded::MAX; -//! assert!(max.checked_add(1_u8).is_none()); -//! ``` -//! -//! # Conversions -//! -//! Integers can be converted between different types using: -//! -//! * [`TryInto`] for potentially fallible conversions -//! * [`Into`] for infallible conversions to wider types - -use crate::RangeCheck; -#[allow(unused_imports)] -use crate::array::{ArrayTrait, SpanTrait}; -#[feature("bounded-int-utils")] -use crate::internal::bounded_int::{downcast, upcast}; -use crate::option::OptionTrait; -use crate::result::ResultTrait; -use crate::traits::{BitAnd, BitNot, BitOr, BitXor, Default, Felt252DictValue, Into, TryInto}; -#[allow(unused_imports)] -use crate::zeroable::{IsZeroResult, NonZeroIntoImpl, Zeroable}; - -// TODO(spapini): Add method for const creation from Integer. -pub trait NumericLiteral; - -impl NumericLiteralfelt252 of NumericLiteral; - -impl NumericLiteralNonZero> of NumericLiteral>; - -/// The 128-bit unsigned integer type. -pub extern type u128; - -impl u128Copy of Copy; -impl u128Drop of Drop; - -impl NumericLiteralu128 of NumericLiteral; - -impl U128Serde = crate::serde::into_felt252_based::SerdeImpl; - -enum U128sFromFelt252Result { - Narrow: u128, - Wide: (u128, u128), -} - -extern const fn u128s_from_felt252( - a: felt252, -) -> U128sFromFelt252Result implicits(RangeCheck) nopanic; - -#[panic_with('u128_from Overflow', u128_from_felt252)] -const fn u128_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic { - match u128s_from_felt252(a) { - U128sFromFelt252Result::Narrow(x) => Some(x), - U128sFromFelt252Result::Wide(_x) => None, - } -} - -pub(crate) extern const fn u128_to_felt252(a: u128) -> felt252 nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub extern fn u128_overflowing_add( - lhs: u128, rhs: u128, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub extern fn u128_overflowing_sub( - lhs: u128, rhs: u128, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingAdd` instead")] -pub fn u128_wrapping_add(lhs: u128, rhs: u128) -> u128 implicits(RangeCheck) nopanic { - match u128_overflowing_add(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingSub` instead")] -pub fn u128_wrapping_sub(a: u128, b: u128) -> u128 implicits(RangeCheck) nopanic { - match u128_overflowing_sub(a, b) { - Ok(x) => x, - Err(x) => x, - } -} - -/// A type that contains 4 u128s (a, b, c, d) and guarantees that `a * b = 2**128 * c + d`. -/// -/// The guarantee is verified by `u128_mul_guarantee_verify`, which is the only way to destruct this -/// type. This way, one can trust that the guarantee holds although it has not yet been verified. -pub extern type U128MulGuarantee; - -/// Multiplies two u128s and returns a `U128MulGuarantee` for the result of `a * b`. -extern fn u128_guarantee_mul(a: u128, b: u128) -> (u128, u128, U128MulGuarantee) nopanic; - -/// Verifies the guarantee and returns the result of `a * b`. -extern fn u128_mul_guarantee_verify(guarantee: U128MulGuarantee) implicits(RangeCheck) nopanic; - -/// Multiplies two u128s and returns `(high, low)` - the 128-bit parts of the result. -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -#[inline] -pub fn u128_wide_mul(a: u128, b: u128) -> (u128, u128) nopanic { - let (high, low, _) = u128_guarantee_mul(a, b); - (high, low) -} - -impl U128MulGuaranteeDestruct of Destruct { - fn destruct(self: U128MulGuarantee) nopanic { - u128_mul_guarantee_verify(self); - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u128_sqrt(value: u128) -> u64 implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingMul` instead", -)] -pub fn u128_overflowing_mul(lhs: u128, rhs: u128) -> (u128, bool) implicits(RangeCheck) nopanic { - let (top_word, bottom_word) = u128_wide_mul(lhs, rhs); - match u128_to_felt252(top_word) { - 0 => (bottom_word, false), - _ => (bottom_word, true), - } -} - -fn u128_checked_add(lhs: u128, rhs: u128) -> Option implicits(RangeCheck) nopanic { - match u128_overflowing_add(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U128Add of Add { - fn add(lhs: u128, rhs: u128) -> u128 { - u128_overflowing_add(lhs, rhs).expect('u128_add Overflow') - } -} - -#[panic_with('u128_sub Overflow', u128_sub)] -fn u128_checked_sub(lhs: u128, rhs: u128) -> Option implicits(RangeCheck) nopanic { - match u128_overflowing_sub(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U128Sub of Sub { - fn sub(lhs: u128, rhs: u128) -> u128 { - u128_overflowing_sub(lhs, rhs).expect('u128_sub Overflow') - } -} - -fn u128_checked_mul(lhs: u128, rhs: u128) -> Option implicits(RangeCheck) nopanic { - let (top_word, bottom_word) = u128_wide_mul(lhs, rhs); - match u128_to_felt252(top_word) { - 0 => Some(bottom_word), - _ => None, - } -} - -impl U128Mul of Mul { - fn mul(lhs: u128, rhs: u128) -> u128 { - u128_checked_mul(lhs, rhs).expect('u128_mul Overflow') - } -} - -#[panic_with('u128 is 0', u128_as_non_zero)] -const fn u128_try_as_non_zero(a: u128) -> Option> nopanic { - match u128_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -pub(crate) impl U128TryIntoNonZero of TryInto> { - const fn try_into(self: u128) -> Option> { - u128_try_as_non_zero(self) - } -} - -impl U128DivRem of DivRem { - fn div_rem(lhs: u128, rhs: NonZero) -> (u128, u128) { - u128_safe_divmod(lhs, rhs) - } -} - -pub extern fn u128_safe_divmod( - lhs: u128, rhs: NonZero, -) -> (u128, u128) implicits(RangeCheck) nopanic; - -extern fn u128_eq(lhs: u128, rhs: u128) -> bool implicits() nopanic; - -impl U128PartialEq of PartialEq { - #[inline] - fn eq(lhs: @u128, rhs: @u128) -> bool { - u128_eq(*lhs, *rhs) - } -} - -impl U128PartialOrd of PartialOrd { - #[inline] - fn ge(lhs: u128, rhs: u128) -> bool { - u128_overflowing_sub(lhs, rhs).into_is_ok() - } - #[inline] - fn lt(lhs: u128, rhs: u128) -> bool { - u128_overflowing_sub(lhs, rhs).into_is_err() - } -} - -pub extern type Bitwise; - -/// Returns the bitwise operations (AND, XOR, OR) between `lhs` and `rhs`. -extern fn bitwise(lhs: u128, rhs: u128) -> (u128, u128, u128) implicits(Bitwise) nopanic; - -impl U128BitAnd of crate::traits::BitAnd { - #[inline] - fn bitand(lhs: u128, rhs: u128) -> u128 { - let (v, _, _) = bitwise(lhs, rhs); - v - } -} - -impl U128BitXor of crate::traits::BitXor { - #[inline] - fn bitxor(lhs: u128, rhs: u128) -> u128 { - let (_, v, _) = bitwise(lhs, rhs); - v - } -} - -impl U128BitOr of crate::traits::BitOr { - #[inline] - fn bitor(lhs: u128, rhs: u128) -> u128 { - let (_, _, v) = bitwise(lhs, rhs); - v - } -} - -impl U128BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 128 - } -} - -pub(crate) extern const fn u128_is_zero(a: u128) -> IsZeroResult implicits() nopanic; - -pub extern fn u128_byte_reverse(input: u128) -> u128 implicits(Bitwise) nopanic; - -/// The 8-bit unsigned integer type. -pub extern type u8; - -impl u8Copy of Copy; -impl u8Drop of Drop; - -impl NumericLiteralu8 of NumericLiteral; - -extern const fn u8_to_felt252(a: u8) -> felt252 nopanic; - -#[panic_with('u8_from Overflow', u8_from_felt252)] -extern const fn u8_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; - -extern fn u8_eq(lhs: u8, rhs: u8) -> bool implicits() nopanic; - -impl U8Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl U8PartialEq of PartialEq { - #[inline] - fn eq(lhs: @u8, rhs: @u8) -> bool { - u8_eq(*lhs, *rhs) - } -} - -impl U8PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: u8, rhs: u8) -> bool { - u8_overflowing_sub(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: u8, rhs: u8) -> bool { - u8_overflowing_sub(lhs, rhs).into_is_ok() - } -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub extern fn u8_overflowing_add(lhs: u8, rhs: u8) -> Result implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub extern fn u8_overflowing_sub(lhs: u8, rhs: u8) -> Result implicits(RangeCheck) nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingAdd` instead")] -pub fn u8_wrapping_add(lhs: u8, rhs: u8) -> u8 implicits(RangeCheck) nopanic { - match u8_overflowing_add(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingSub` instead")] -pub fn u8_wrapping_sub(lhs: u8, rhs: u8) -> u8 implicits(RangeCheck) nopanic { - match u8_overflowing_sub(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -fn u8_checked_add(lhs: u8, rhs: u8) -> Option implicits(RangeCheck) nopanic { - match u8_overflowing_add(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U8Add of Add { - fn add(lhs: u8, rhs: u8) -> u8 { - u8_overflowing_add(lhs, rhs).expect('u8_add Overflow') - } -} - -fn u8_checked_sub(lhs: u8, rhs: u8) -> Option implicits(RangeCheck) nopanic { - match u8_overflowing_sub(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U8Sub of Sub { - fn sub(lhs: u8, rhs: u8) -> u8 { - u8_overflowing_sub(lhs, rhs).expect('u8_sub Overflow') - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn u8_wide_mul(lhs: u8, rhs: u8) -> u16 implicits() nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u8_sqrt(value: u8) -> u8 implicits(RangeCheck) nopanic; - -impl U8Mul of Mul { - fn mul(lhs: u8, rhs: u8) -> u8 { - u8_wide_mul(lhs, rhs).try_into().expect('u8_mul Overflow') - } -} - -extern const fn u8_is_zero(a: u8) -> IsZeroResult implicits() nopanic; - -pub extern fn u8_safe_divmod(lhs: u8, rhs: NonZero) -> (u8, u8) implicits(RangeCheck) nopanic; - -#[panic_with('u8 is 0', u8_as_non_zero)] -const fn u8_try_as_non_zero(a: u8) -> Option> nopanic { - match u8_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -impl U8TryIntoNonZero of TryInto> { - const fn try_into(self: u8) -> Option> { - u8_try_as_non_zero(self) - } -} - -impl U8DivRem of DivRem { - fn div_rem(lhs: u8, rhs: NonZero) -> (u8, u8) { - u8_safe_divmod(lhs, rhs) - } -} - -extern fn u8_bitwise(lhs: u8, rhs: u8) -> (u8, u8, u8) implicits(Bitwise) nopanic; - -impl U8BitAnd of BitAnd { - #[inline] - fn bitand(lhs: u8, rhs: u8) -> u8 { - let (v, _, _) = u8_bitwise(lhs, rhs); - v - } -} - -impl U8BitXor of BitXor { - #[inline] - fn bitxor(lhs: u8, rhs: u8) -> u8 { - let (_, v, _) = u8_bitwise(lhs, rhs); - v - } -} - -impl U8BitOr of BitOr { - #[inline] - fn bitor(lhs: u8, rhs: u8) -> u8 { - let (_, _, v) = u8_bitwise(lhs, rhs); - v - } -} - -impl U8BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 8 - } -} - -/// The 16-bit unsigned integer type. -pub extern type u16; - -impl u16Copy of Copy; -impl u16Drop of Drop; - -impl NumericLiteralu16 of NumericLiteral; - -extern const fn u16_to_felt252(a: u16) -> felt252 nopanic; - -#[panic_with('u16_from Overflow', u16_from_felt252)] -extern const fn u16_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; - -extern fn u16_eq(lhs: u16, rhs: u16) -> bool implicits() nopanic; - -impl U16Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl U16PartialEq of PartialEq { - #[inline] - fn eq(lhs: @u16, rhs: @u16) -> bool { - u16_eq(*lhs, *rhs) - } -} - -impl U16PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: u16, rhs: u16) -> bool { - u16_overflowing_sub(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: u16, rhs: u16) -> bool { - u16_overflowing_sub(lhs, rhs).into_is_ok() - } -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub extern fn u16_overflowing_add( - lhs: u16, rhs: u16, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub extern fn u16_overflowing_sub( - lhs: u16, rhs: u16, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingAdd` instead")] -pub fn u16_wrapping_add(lhs: u16, rhs: u16) -> u16 implicits(RangeCheck) nopanic { - match u16_overflowing_add(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingSub` instead")] -pub fn u16_wrapping_sub(lhs: u16, rhs: u16) -> u16 implicits(RangeCheck) nopanic { - match u16_overflowing_sub(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -fn u16_checked_add(lhs: u16, rhs: u16) -> Option implicits(RangeCheck) nopanic { - match u16_overflowing_add(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U16Add of Add { - fn add(lhs: u16, rhs: u16) -> u16 { - u16_overflowing_add(lhs, rhs).expect('u16_add Overflow') - } -} - -fn u16_checked_sub(lhs: u16, rhs: u16) -> Option implicits(RangeCheck) nopanic { - match u16_overflowing_sub(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U16Sub of Sub { - fn sub(lhs: u16, rhs: u16) -> u16 { - u16_overflowing_sub(lhs, rhs).expect('u16_sub Overflow') - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn u16_wide_mul(lhs: u16, rhs: u16) -> u32 implicits() nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u16_sqrt(value: u16) -> u8 implicits(RangeCheck) nopanic; - -impl U16Mul of Mul { - fn mul(lhs: u16, rhs: u16) -> u16 { - u16_wide_mul(lhs, rhs).try_into().expect('u16_mul Overflow') - } -} - -extern const fn u16_is_zero(a: u16) -> IsZeroResult implicits() nopanic; - -pub extern fn u16_safe_divmod( - lhs: u16, rhs: NonZero, -) -> (u16, u16) implicits(RangeCheck) nopanic; - -#[panic_with('u16 is 0', u16_as_non_zero)] -const fn u16_try_as_non_zero(a: u16) -> Option> nopanic { - match u16_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -impl U16TryIntoNonZero of TryInto> { - const fn try_into(self: u16) -> Option> { - u16_try_as_non_zero(self) - } -} - -impl U16DivRem of DivRem { - fn div_rem(lhs: u16, rhs: NonZero) -> (u16, u16) { - u16_safe_divmod(lhs, rhs) - } -} - -extern fn u16_bitwise(lhs: u16, rhs: u16) -> (u16, u16, u16) implicits(Bitwise) nopanic; - -impl U16BitAnd of BitAnd { - #[inline] - fn bitand(lhs: u16, rhs: u16) -> u16 { - let (v, _, _) = u16_bitwise(lhs, rhs); - v - } -} - -impl U16BitXor of BitXor { - #[inline] - fn bitxor(lhs: u16, rhs: u16) -> u16 { - let (_, v, _) = u16_bitwise(lhs, rhs); - v - } -} - -impl U16BitOr of BitOr { - #[inline] - fn bitor(lhs: u16, rhs: u16) -> u16 { - let (_, _, v) = u16_bitwise(lhs, rhs); - v - } -} - -impl U16BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 16 - } -} - -/// The 32-bit unsigned integer type. -pub extern type u32; - -impl u32Copy of Copy; -impl u32Drop of Drop; - -impl NumericLiteralu32 of NumericLiteral; - -extern const fn u32_to_felt252(a: u32) -> felt252 nopanic; - -#[panic_with('u32_from Overflow', u32_from_felt252)] -extern const fn u32_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; - -extern fn u32_eq(lhs: u32, rhs: u32) -> bool implicits() nopanic; - -impl U32Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl U32PartialEq of PartialEq { - #[inline] - fn eq(lhs: @u32, rhs: @u32) -> bool { - u32_eq(*lhs, *rhs) - } -} - -impl U32PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: u32, rhs: u32) -> bool { - u32_overflowing_sub(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: u32, rhs: u32) -> bool { - u32_overflowing_sub(lhs, rhs).into_is_ok() - } -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub extern fn u32_overflowing_add( - lhs: u32, rhs: u32, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub extern fn u32_overflowing_sub( - lhs: u32, rhs: u32, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingAdd` instead")] -pub fn u32_wrapping_add(lhs: u32, rhs: u32) -> u32 implicits(RangeCheck) nopanic { - match u32_overflowing_add(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingSub` instead")] -pub fn u32_wrapping_sub(lhs: u32, rhs: u32) -> u32 implicits(RangeCheck) nopanic { - match u32_overflowing_sub(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -fn u32_checked_add(lhs: u32, rhs: u32) -> Option implicits(RangeCheck) nopanic { - match u32_overflowing_add(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U32Add of Add { - fn add(lhs: u32, rhs: u32) -> u32 { - u32_overflowing_add(lhs, rhs).expect('u32_add Overflow') - } -} - -fn u32_checked_sub(lhs: u32, rhs: u32) -> Option implicits(RangeCheck) nopanic { - match u32_overflowing_sub(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U32Sub of Sub { - fn sub(lhs: u32, rhs: u32) -> u32 { - u32_overflowing_sub(lhs, rhs).expect('u32_sub Overflow') - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn u32_wide_mul(lhs: u32, rhs: u32) -> u64 implicits() nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u32_sqrt(value: u32) -> u16 implicits(RangeCheck) nopanic; - -impl U32Mul of Mul { - fn mul(lhs: u32, rhs: u32) -> u32 { - u32_wide_mul(lhs, rhs).try_into().expect('u32_mul Overflow') - } -} - -extern const fn u32_is_zero(a: u32) -> IsZeroResult implicits() nopanic; - -pub extern fn u32_safe_divmod( - lhs: u32, rhs: NonZero, -) -> (u32, u32) implicits(RangeCheck) nopanic; - -#[panic_with('u32 is 0', u32_as_non_zero)] -const fn u32_try_as_non_zero(a: u32) -> Option> nopanic { - match u32_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -pub(crate) impl U32TryIntoNonZero of TryInto> { - const fn try_into(self: u32) -> Option> { - u32_try_as_non_zero(self) - } -} - -impl U32DivRem of DivRem { - fn div_rem(lhs: u32, rhs: NonZero) -> (u32, u32) { - u32_safe_divmod(lhs, rhs) - } -} - -extern fn u32_bitwise(lhs: u32, rhs: u32) -> (u32, u32, u32) implicits(Bitwise) nopanic; - -impl U32BitAnd of BitAnd { - #[inline] - fn bitand(lhs: u32, rhs: u32) -> u32 { - let (v, _, _) = u32_bitwise(lhs, rhs); - v - } -} - -impl U32BitXor of BitXor { - #[inline] - fn bitxor(lhs: u32, rhs: u32) -> u32 { - let (_, v, _) = u32_bitwise(lhs, rhs); - v - } -} - -impl U32BitOr of BitOr { - #[inline] - fn bitor(lhs: u32, rhs: u32) -> u32 { - let (_, _, v) = u32_bitwise(lhs, rhs); - v - } -} - -impl U32BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 32 - } -} - -/// The 64-bit unsigned integer type. -pub extern type u64; - -impl u64Copy of Copy; -impl u64Drop of Drop; - -impl NumericLiteralu64 of NumericLiteral; - -extern const fn u64_to_felt252(a: u64) -> felt252 nopanic; - -#[panic_with('u64_from Overflow', u64_from_felt252)] -extern const fn u64_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; - -extern fn u64_eq(lhs: u64, rhs: u64) -> bool implicits() nopanic; - -impl U64Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl U64PartialEq of PartialEq { - #[inline] - fn eq(lhs: @u64, rhs: @u64) -> bool { - u64_eq(*lhs, *rhs) - } -} - -impl U64PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: u64, rhs: u64) -> bool { - u64_overflowing_sub(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: u64, rhs: u64) -> bool { - u64_overflowing_sub(lhs, rhs).into_is_ok() - } -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub extern fn u64_overflowing_add( - lhs: u64, rhs: u64, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub extern fn u64_overflowing_sub( - lhs: u64, rhs: u64, -) -> Result implicits(RangeCheck) nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingAdd` instead")] -pub fn u64_wrapping_add(lhs: u64, rhs: u64) -> u64 implicits(RangeCheck) nopanic { - match u64_overflowing_add(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WrappingSub` instead")] -pub fn u64_wrapping_sub(lhs: u64, rhs: u64) -> u64 implicits(RangeCheck) nopanic { - match u64_overflowing_sub(lhs, rhs) { - Ok(x) => x, - Err(x) => x, - } -} - -fn u64_checked_add(lhs: u64, rhs: u64) -> Option implicits(RangeCheck) nopanic { - match u64_overflowing_add(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U64Add of Add { - fn add(lhs: u64, rhs: u64) -> u64 { - u64_overflowing_add(lhs, rhs).expect('u64_add Overflow') - } -} - -fn u64_checked_sub(lhs: u64, rhs: u64) -> Option implicits(RangeCheck) nopanic { - match u64_overflowing_sub(lhs, rhs) { - Ok(r) => Some(r), - Err(_r) => None, - } -} - -impl U64Sub of Sub { - fn sub(lhs: u64, rhs: u64) -> u64 { - u64_overflowing_sub(lhs, rhs).expect('u64_sub Overflow') - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn u64_wide_mul(lhs: u64, rhs: u64) -> u128 implicits() nopanic; - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u64_sqrt(value: u64) -> u32 implicits(RangeCheck) nopanic; - -impl U64Mul of Mul { - fn mul(lhs: u64, rhs: u64) -> u64 { - u64_wide_mul(lhs, rhs).try_into().expect('u64_mul Overflow') - } -} - -extern const fn u64_is_zero(a: u64) -> IsZeroResult implicits() nopanic; - -pub extern fn u64_safe_divmod( - lhs: u64, rhs: NonZero, -) -> (u64, u64) implicits(RangeCheck) nopanic; - -#[panic_with('u64 is 0', u64_as_non_zero)] -const fn u64_try_as_non_zero(a: u64) -> Option> nopanic { - match u64_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -impl U64TryIntoNonZero of TryInto> { - const fn try_into(self: u64) -> Option> { - u64_try_as_non_zero(self) - } -} - -impl U64DivRem of DivRem { - fn div_rem(lhs: u64, rhs: NonZero) -> (u64, u64) { - u64_safe_divmod(lhs, rhs) - } -} - -extern fn u64_bitwise(lhs: u64, rhs: u64) -> (u64, u64, u64) implicits(Bitwise) nopanic; -impl U64BitAnd of BitAnd { - #[inline] - fn bitand(lhs: u64, rhs: u64) -> u64 { - let (v, _, _) = u64_bitwise(lhs, rhs); - v - } -} -impl U64BitXor of BitXor { - #[inline] - fn bitxor(lhs: u64, rhs: u64) -> u64 { - let (_, v, _) = u64_bitwise(lhs, rhs); - v - } -} -impl U64BitOr of BitOr { - #[inline] - fn bitor(lhs: u64, rhs: u64) -> u64 { - let (_, _, v) = u64_bitwise(lhs, rhs); - v - } -} - -impl U64BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 64 - } -} - -/// The 256-bit unsigned integer type. -/// -/// The `u256` type is composed of two 128-bit parts: the low part [0, 128) and the high part [128, -/// 256). -#[derive(Copy, Drop, Hash, PartialEq, Serde)] -pub struct u256 { - pub low: u128, - pub high: u128, -} - -impl NumericLiteralU256 of NumericLiteral; - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingAdd` instead", -)] -pub fn u256_overflowing_add(lhs: u256, rhs: u256) -> (u256, bool) implicits(RangeCheck) nopanic { - let (high, overflow) = match u128_overflowing_add(lhs.high, rhs.high) { - Ok(high) => (high, false), - Err(high) => (high, true), - }; - match u128_overflowing_add(lhs.low, rhs.low) { - Ok(low) => (u256 { low, high }, overflow), - Err(low) => { - match u128_overflowing_add(high, 1_u128) { - Ok(high) => (u256 { low, high }, overflow), - Err(high) => (u256 { low, high }, true), - } - }, - } -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingSub` instead", -)] -pub fn u256_overflowing_sub(lhs: u256, rhs: u256) -> (u256, bool) implicits(RangeCheck) nopanic { - let (high, overflow) = match u128_overflowing_sub(lhs.high, rhs.high) { - Ok(high) => (high, false), - Err(high) => (high, true), - }; - match u128_overflowing_sub(lhs.low, rhs.low) { - Ok(low) => (u256 { low, high }, overflow), - Err(low) => { - match u128_overflowing_sub(high, 1_u128) { - Ok(high) => (u256 { low, high }, overflow), - Err(high) => (u256 { low, high }, true), - } - }, - } -} - -#[deprecated( - feature: "deprecated-overflow-functions", - note: "Use `core::integer::u256_overflowing_add` instead", -)] -pub fn u256_overflow_sub(lhs: u256, rhs: u256) -> (u256, bool) implicits(RangeCheck) nopanic { - u256_overflowing_sub(lhs, rhs) -} - -#[deprecated( - feature: "corelib-internal-use", note: "Use `core::num::traits::OverflowingMul` instead", -)] -pub fn u256_overflowing_mul(lhs: u256, rhs: u256) -> (u256, bool) { - let (high1, low) = u128_wide_mul(lhs.low, rhs.low); - let (overflow_value1, high2) = u128_wide_mul(lhs.low, rhs.high); - let (overflow_value2, high3) = u128_wide_mul(lhs.high, rhs.low); - let (high, overflow) = match u128_overflowing_add(high1, high2) { - Ok(high) => ( - high, - overflow_value1 != 0_u128 - || overflow_value2 != 0_u128 - || (lhs.high > 0_u128 && rhs.high > 0_u128), - ), - Err(high) => (high, true), - }; - let (high, overflow) = match u128_overflowing_add(high, high3) { - Ok(high) => (high, overflow), - Err(high) => (high, true), - }; - (u256 { low, high }, overflow) -} - -#[deprecated( - feature: "deprecated-overflow-functions", - note: "Use `core::integer::u256_overflowing_mul` instead", -)] -pub fn u256_overflow_mul(lhs: u256, rhs: u256) -> (u256, bool) { - u256_overflowing_mul(lhs, rhs) -} - -fn u256_checked_add(lhs: u256, rhs: u256) -> Option implicits(RangeCheck) nopanic { - let (r, overflow) = u256_overflowing_add(lhs, rhs); - if overflow { - None - } else { - Some(r) - } -} - -impl U256Add of Add { - fn add(lhs: u256, rhs: u256) -> u256 { - u256_checked_add(lhs, rhs).expect('u256_add Overflow') - } -} - -#[panic_with('u256_sub Overflow', u256_sub)] -fn u256_checked_sub(lhs: u256, rhs: u256) -> Option implicits(RangeCheck) nopanic { - let (r, overflow) = u256_overflowing_sub(lhs, rhs); - if overflow { - None - } else { - Some(r) - } -} - -impl U256Sub of Sub { - fn sub(lhs: u256, rhs: u256) -> u256 { - u256_checked_sub(lhs, rhs).expect('u256_sub Overflow') - } -} - -fn u256_checked_mul(lhs: u256, rhs: u256) -> Option implicits(RangeCheck) { - let (r, overflow) = u256_overflowing_mul(lhs, rhs); - if overflow { - None - } else { - Some(r) - } -} - -impl U256Mul of Mul { - fn mul(lhs: u256, rhs: u256) -> u256 { - u256_checked_mul(lhs, rhs).expect('u256_mul Overflow') - } -} - -impl U256PartialOrd of PartialOrd { - fn lt(lhs: u256, rhs: u256) -> bool { - if lhs.high < rhs.high { - true - } else if lhs.high == rhs.high { - lhs.low < rhs.low - } else { - false - } - } -} - -impl U256BitAnd of BitAnd { - #[inline] - fn bitand(lhs: u256, rhs: u256) -> u256 { - u256 { low: lhs.low & rhs.low, high: lhs.high & rhs.high } - } -} - -impl U256BitXor of BitXor { - #[inline] - fn bitxor(lhs: u256, rhs: u256) -> u256 { - u256 { low: lhs.low ^ rhs.low, high: lhs.high ^ rhs.high } - } -} - -impl U256BitOr of BitOr { - #[inline] - fn bitor(lhs: u256, rhs: u256) -> u256 { - u256 { low: lhs.low | rhs.low, high: lhs.high | rhs.high } - } -} - -const fn u256_from_felt252(lhs: felt252) -> u256 implicits(RangeCheck) nopanic { - match u128s_from_felt252(lhs) { - U128sFromFelt252Result::Narrow(low) => u256 { low, high: 0_u128 }, - U128sFromFelt252Result::Wide((high, low)) => u256 { low, high }, - } -} - -extern const fn u256_is_zero(a: u256) -> IsZeroResult implicits() nopanic; - -/// Calculates division with remainder of a u256 by a non-zero u256. -/// Additionally returns a `U128MulGuarantee` that is required for validating the calculation. -extern fn u256_safe_divmod( - lhs: u256, rhs: NonZero, -) -> (u256, u256, U128MulGuarantee) implicits(RangeCheck) nopanic; - -/// Calculates division with remainder of a u256 by a non-zero u256. -#[inline] -fn u256_safe_div_rem(lhs: u256, rhs: NonZero) -> (u256, u256) implicits(RangeCheck) nopanic { - let (q, r, _) = u256_safe_divmod(lhs, rhs); - (q, r) -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -pub extern fn u256_sqrt(a: u256) -> u128 implicits(RangeCheck) nopanic; - -#[panic_with('u256 is 0', u256_as_non_zero)] -const fn u256_try_as_non_zero(a: u256) -> Option> nopanic { - match u256_is_zero(a) { - IsZeroResult::Zero => None, - IsZeroResult::NonZero(x) => Some(x), - } -} - -pub(crate) impl U256TryIntoNonZero of TryInto> { - const fn try_into(self: u256) -> Option> { - u256_try_as_non_zero(self) - } -} - -impl U256DivRem of DivRem { - fn div_rem(lhs: u256, rhs: NonZero) -> (u256, u256) { - u256_safe_div_rem(lhs, rhs) - } -} - -impl U256BitNot of BitNot { - fn bitnot(a: u256) -> u256 { - u256 { low: ~a.low, high: ~a.high } - } -} - -impl U256BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 256 - } -} - -#[derive(Copy, Drop, Hash, PartialEq, Serde)] -pub struct u512 { - pub limb0: u128, - pub limb1: u128, - pub limb2: u128, - pub limb3: u128, -} - -// Returns the result of u128 addition, including an overflow word. -fn u128_add_with_carry(a: u128, b: u128) -> (u128, u128) nopanic { - match u128_overflowing_add(a, b) { - Ok(v) => (v, 0), - Err(v) => (v, 1), - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -#[feature("bounded-int-utils")] -pub fn u256_wide_mul(a: u256, b: u256) -> u512 nopanic { - let (limb1, limb0) = u128_wide_mul(a.low, b.low); - let (limb2, limb1_part) = u128_wide_mul(a.low, b.high); - let (limb1, limb1_overflow0) = u128_add_with_bounded_int_carry(limb1, limb1_part); - let (limb2_part, limb1_part) = u128_wide_mul(a.high, b.low); - let (limb1, limb1_overflow1) = u128_add_with_bounded_int_carry(limb1, limb1_part); - let (limb2, limb2_overflow0) = u128_add_with_bounded_int_carry(limb2, limb2_part); - let (limb3, limb2_part) = u128_wide_mul(a.high, b.high); - let (limb2, limb2_overflow1) = u128_add_with_bounded_int_carry(limb2, limb2_part); - // Packing together the overflow bits, making a cheaper addition into limb2. - let limb1_overflow = crate::internal::bounded_int::add(limb1_overflow0, limb1_overflow1); - let (limb2, limb2_overflow2) = u128_add_with_bounded_int_carry(limb2, upcast(limb1_overflow)); - // Packing together the overflow bits, making a cheaper addition into limb3. - let limb2_overflow = crate::internal::bounded_int::add(limb2_overflow0, limb2_overflow1); - let limb2_overflow = crate::internal::bounded_int::add(limb2_overflow, limb2_overflow2); - // No overflow since no limb4. - let limb3 = u128_wrapping_add(limb3, upcast(limb2_overflow)); - u512 { limb0, limb1, limb2, limb3 } -} - -/// Helper function for implementation of `u256_wide_mul`. -/// Used for adding two u128s and receiving a BoundedInt for the carry result. -#[feature("bounded-int-utils")] -pub(crate) fn u128_add_with_bounded_int_carry( - a: u128, b: u128, -) -> (u128, crate::internal::bounded_int::BoundedInt<0, 1>) nopanic { - match u128_overflowing_add(a, b) { - Ok(v) => (v, 0), - Err(v) => (v, 1), - } -} - -/// Calculates division with remainder of a u512 by a non-zero u256. -#[inline] -pub fn u512_safe_div_rem_by_u256( - lhs: u512, rhs: NonZero, -) -> (u512, u256) implicits(RangeCheck) nopanic { - let (q, r, _, _, _, _, _) = u512_safe_divmod_by_u256(lhs, rhs); - (q, r) -} - -/// Calculates division with remainder of a u512 by a non-zero u256. -/// Additionally returns several `U128MulGuarantee`s that are required for validating the -/// calculation. -extern fn u512_safe_divmod_by_u256( - lhs: u512, rhs: NonZero, -) -> ( - u512, - u256, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, -) implicits(RangeCheck) nopanic; - -impl U512TryIntoU256 of TryInto { - const fn try_into(self: u512) -> Option { - if self.limb2 != 0 || self.limb3 != 0 { - None - } else { - Some(u256 { low: self.limb0, high: self.limb1 }) - } - } -} - -/// Trait for getting the maximal and minimal values of an integer type. -#[deprecated( - feature: "deprecated-bounded-int-trait", note: "Use `core::num::traits::Bounded` instead", -)] -pub trait BoundedInt { - /// Returns the minimal value of the type. - #[must_use] - fn min() -> T nopanic; - - /// Returns the maximal value of the type. - #[must_use] - fn max() -> T nopanic; -} - -mod bounded_int_impls { - #[feature("deprecated-bounded-int-trait")] - pub impl ByBounded> of super::BoundedInt { - #[inline] - fn min() -> T nopanic { - Bounded::MIN - } - - #[inline] - fn max() -> T nopanic { - Bounded::MAX - } - } -} - -impl BoundedU8 = bounded_int_impls::ByBounded; -impl BoundedU16 = bounded_int_impls::ByBounded; -impl BoundedU32 = bounded_int_impls::ByBounded; -impl BoundedU64 = bounded_int_impls::ByBounded; -impl BoundedU128 = bounded_int_impls::ByBounded; -impl BoundedU256 = bounded_int_impls::ByBounded; -impl BoundedI8 = bounded_int_impls::ByBounded; -impl BoundedI16 = bounded_int_impls::ByBounded; -impl BoundedI32 = bounded_int_impls::ByBounded; -impl BoundedI64 = bounded_int_impls::ByBounded; -impl BoundedI128 = bounded_int_impls::ByBounded; - -/// Conversions. -pub(crate) impl Felt252TryIntoU8 of TryInto { - const fn try_into(self: felt252) -> Option { - u8_try_from_felt252(self) - } -} - -pub(crate) impl U8IntoFelt252 of Into { - const fn into(self: u8) -> felt252 { - u8_to_felt252(self) - } -} - -pub(crate) impl Felt252TryIntoU16 of TryInto { - const fn try_into(self: felt252) -> Option { - u16_try_from_felt252(self) - } -} - -pub(crate) impl U16IntoFelt252 of Into { - const fn into(self: u16) -> felt252 { - u16_to_felt252(self) - } -} - -pub(crate) impl Felt252TryIntoU32 of TryInto { - const fn try_into(self: felt252) -> Option { - u32_try_from_felt252(self) - } -} - -pub(crate) impl U32IntoFelt252 of Into { - const fn into(self: u32) -> felt252 { - u32_to_felt252(self) - } -} - -pub(crate) impl Felt252TryIntoU64 of TryInto { - const fn try_into(self: felt252) -> Option { - u64_try_from_felt252(self) - } -} - -pub(crate) impl U64IntoFelt252 of Into { - const fn into(self: u64) -> felt252 { - u64_to_felt252(self) - } -} - -pub(crate) impl Felt252TryIntoU128 of TryInto { - const fn try_into(self: felt252) -> Option { - u128_try_from_felt252(self) - } -} - -pub(crate) impl U128IntoFelt252 of Into { - const fn into(self: u128) -> felt252 { - u128_to_felt252(self) - } -} - -pub(crate) impl Felt252IntoU256 of Into { - const fn into(self: felt252) -> u256 { - u256_from_felt252(self) - } -} - -pub(crate) impl U256TryIntoFelt252 of TryInto { - const fn try_into(self: u256) -> Option { - let FELT252_PRIME_HIGH: u128 = 0x8000000000000110000000000000000; - if self.high > FELT252_PRIME_HIGH { - None - } else if self.high == FELT252_PRIME_HIGH && self.low != 0 { - None - } else { - Some(self.high.into() * 0x100000000000000000000000000000000_felt252 + self.low.into()) - } - } -} - -impl Felt252TryIntoI8 of TryInto { - const fn try_into(self: felt252) -> Option { - i8_try_from_felt252(self) - } -} - -pub(crate) impl I8IntoFelt252 of Into { - const fn into(self: i8) -> felt252 { - i8_to_felt252(self) - } -} - -impl Felt252TryIntoI16 of TryInto { - const fn try_into(self: felt252) -> Option { - i16_try_from_felt252(self) - } -} - -pub(crate) impl I16IntoFelt252 of Into { - const fn into(self: i16) -> felt252 { - i16_to_felt252(self) - } -} - -impl Felt252TryIntoI32 of TryInto { - const fn try_into(self: felt252) -> Option { - i32_try_from_felt252(self) - } -} - -pub(crate) impl I32IntoFelt252 of Into { - const fn into(self: i32) -> felt252 { - i32_to_felt252(self) - } -} - -impl Felt252TryIntoI64 of TryInto { - const fn try_into(self: felt252) -> Option { - i64_try_from_felt252(self) - } -} - -pub(crate) impl I64IntoFelt252 of Into { - const fn into(self: i64) -> felt252 { - i64_to_felt252(self) - } -} - -impl Felt252TryIntoI128 of TryInto { - const fn try_into(self: felt252) -> Option { - i128_try_from_felt252(self) - } -} - -pub(crate) impl I128IntoFelt252 of Into { - const fn into(self: i128) -> felt252 { - i128_to_felt252(self) - } -} - -// Marks `FromType` as upcastable to `ToType`. -// Do not add user code implementing this trait. -trait Upcastable; - -impl UpcastableU8U16 of Upcastable; -impl UpcastableU8I16 of Upcastable; -impl UpcastableU8U32 of Upcastable; -impl UpcastableU8I32 of Upcastable; -impl UpcastableU8U64 of Upcastable; -impl UpcastableU8I64 of Upcastable; -impl UpcastableU8U128 of Upcastable; -impl UpcastableU8I128 of Upcastable; -impl UpcastableI8I16 of Upcastable; -impl UpcastableI8I32 of Upcastable; -impl UpcastableI8I64 of Upcastable; -impl UpcastableI8I128 of Upcastable; -impl UpcastableU16U32 of Upcastable; -impl UpcastableU16I32 of Upcastable; -impl UpcastableU16U64 of Upcastable; -impl UpcastableU16I64 of Upcastable; -impl UpcastableU16U128 of Upcastable; -impl UpcastableU16I128 of Upcastable; -impl UpcastableI16I32 of Upcastable; -impl UpcastableI16I64 of Upcastable; -impl UpcastableI16I128 of Upcastable; -impl UpcastableU32U64 of Upcastable; -impl UpcastableU32I64 of Upcastable; -impl UpcastableU32U128 of Upcastable; -impl UpcastableU32I128 of Upcastable; -impl UpcastableI32I64 of Upcastable; -impl UpcastableI32I128 of Upcastable; -impl UpcastableU64U128 of Upcastable; -impl UpcastableU64I128 of Upcastable; -impl UpcastableI64I128 of Upcastable; - -// Marks a type as an int that is downcastable to other downcastable ints. -// Do not add user code implementing this trait. -trait DowncastableInt; - -impl DowncastableU8 of DowncastableInt; -impl DowncastableI8 of DowncastableInt; -impl DowncastableU16 of DowncastableInt; -impl DowncastableI16 of DowncastableInt; -impl DowncastableU32 of DowncastableInt; -impl DowncastableI32 of DowncastableInt; -impl DowncastableU64 of DowncastableInt; -impl DowncastableI64 of DowncastableInt; -impl DowncastableU128 of DowncastableInt; -impl DowncastableI128 of DowncastableInt; - -/// Default values -impl U8Default of Default { - #[inline] - fn default() -> u8 nopanic { - 0_u8 - } -} - -impl U16Default of Default { - #[inline] - fn default() -> u16 nopanic { - 0_u16 - } -} - -impl U32Default of Default { - #[inline] - fn default() -> u32 nopanic { - 0_u32 - } -} - -impl U64Default of Default { - #[inline] - fn default() -> u64 nopanic { - 0_u64 - } -} - -impl U128Default of Default { - #[inline] - fn default() -> u128 nopanic { - 0_u128 - } -} - -impl U256Default of Default { - #[inline] - fn default() -> u256 nopanic { - 0_u256 - } -} - -impl I8Default of Default { - #[inline] - fn default() -> i8 nopanic { - 0_i8 - } -} - -impl I16Default of Default { - #[inline] - fn default() -> i16 nopanic { - 0_i16 - } -} - -impl I32Default of Default { - #[inline] - fn default() -> i32 nopanic { - 0_i32 - } -} - -impl I64Default of Default { - #[inline] - fn default() -> i64 nopanic { - 0_i64 - } -} - -impl I128Default of Default { - #[inline] - fn default() -> i128 nopanic { - 0_i128 - } -} - -/// Default values for felt252_dict values. -impl U8Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> u8 nopanic { - 0 - } -} - -impl U16Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> u16 nopanic { - 0 - } -} - -impl U32Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> u32 nopanic { - 0 - } -} - -impl U64Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> u64 nopanic { - 0 - } -} - -impl U128Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> u128 nopanic { - 0 - } -} - -impl UpcastableInto> of Into { - const fn into(self: From) -> To { - upcast(self) - } -} - -impl DowncastableIntTryInto< - From, To, +DowncastableInt, +DowncastableInt, -Into, -> of TryInto { - const fn try_into(self: From) -> Option { - downcast(self) - } -} - -impl U8IntoU256 of Into { - const fn into(self: u8) -> u256 { - u256 { low: upcast(self), high: 0_u128 } - } -} - -impl U256TryIntoU8 of TryInto { - const fn try_into(self: u256) -> Option { - let u256 { low, high } = self; - - if high != 0 { - None - } else { - low.try_into() - } - } -} - -impl U16IntoU256 of Into { - const fn into(self: u16) -> u256 { - u256 { low: upcast(self), high: 0_u128 } - } -} - -impl U256TryIntoU16 of TryInto { - const fn try_into(self: u256) -> Option { - let u256 { low, high } = self; - - if high != 0 { - None - } else { - low.try_into() - } - } -} - -impl U32IntoU256 of Into { - const fn into(self: u32) -> u256 { - u256 { low: upcast(self), high: 0_u128 } - } -} - -impl U256TryIntoU32 of TryInto { - const fn try_into(self: u256) -> Option { - let u256 { low, high } = self; - - if high != 0 { - None - } else { - low.try_into() - } - } -} - -impl U64IntoU256 of Into { - const fn into(self: u64) -> u256 { - u256 { low: upcast(self), high: 0_u128 } - } -} - -impl U256TryIntoU64 of TryInto { - const fn try_into(self: u256) -> Option { - let u256 { low, high } = self; - - if high != 0 { - None - } else { - low.try_into() - } - } -} - -impl U128IntoU256 of Into { - const fn into(self: u128) -> u256 { - u256 { low: self, high: 0_u128 } - } -} - -impl U256TryIntoU128 of TryInto { - const fn try_into(self: u256) -> Option { - let u256 { low, high } = self; - - if high != 0 { - None - } else { - Some(low) - } - } -} - -pub(crate) enum SignedIntegerResult { - InRange: T, - Underflow: T, - Overflow: T, -} - -impl SignedIntegerResultDrop> of Drop>; - -/// Impls for signed int addition and subtraction. -mod signed_int_impls { - use super::SignedIntegerResult; - - /// Helper trait for calling the libfuncs per signed int type. - trait SignedIntegerHelper { - /// The wrapper for the addition libfunc. - fn add(lhs: T, rhs: T) -> SignedIntegerResult nopanic; - - /// The wrapper for the subtraction libfunc. - fn sub(lhs: T, rhs: T) -> SignedIntegerResult nopanic; - } - - impl SignedIntegerHelperI8 of SignedIntegerHelper { - fn add(lhs: i8, rhs: i8) -> SignedIntegerResult nopanic { - super::i8_overflowing_add_impl(lhs, rhs) - } - - fn sub(lhs: i8, rhs: i8) -> SignedIntegerResult nopanic { - super::i8_overflowing_sub_impl(lhs, rhs) - } - } - - impl SignedIntegerHelperI16 of SignedIntegerHelper { - fn add(lhs: i16, rhs: i16) -> SignedIntegerResult nopanic { - super::i16_overflowing_add_impl(lhs, rhs) - } - - fn sub(lhs: i16, rhs: i16) -> SignedIntegerResult nopanic { - super::i16_overflowing_sub_impl(lhs, rhs) - } - } - - impl SignedIntegerHelperI32 of SignedIntegerHelper { - fn add(lhs: i32, rhs: i32) -> SignedIntegerResult nopanic { - super::i32_overflowing_add_impl(lhs, rhs) - } - - fn sub(lhs: i32, rhs: i32) -> SignedIntegerResult nopanic { - super::i32_overflowing_sub_impl(lhs, rhs) - } - } - - impl SignedIntegerHelperI64 of SignedIntegerHelper { - fn add(lhs: i64, rhs: i64) -> SignedIntegerResult nopanic { - super::i64_overflowing_add_impl(lhs, rhs) - } - - fn sub(lhs: i64, rhs: i64) -> SignedIntegerResult nopanic { - super::i64_overflowing_sub_impl(lhs, rhs) - } - } - - impl SignedIntegerHelperI128 of SignedIntegerHelper { - fn add(lhs: i128, rhs: i128) -> SignedIntegerResult nopanic { - super::i128_overflowing_add_impl(lhs, rhs) - } - - fn sub(lhs: i128, rhs: i128) -> SignedIntegerResult nopanic { - super::i128_overflowing_sub_impl(lhs, rhs) - } - } - - /// Impl for `CheckedAdd` based on `SignedIntegerHelper`. - pub impl CheckedAddImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::CheckedAdd { - fn checked_add(self: T, v: T) -> Option { - as_checked(H::add(self, v)) - } - } - - /// Impl for `CheckedSub` based on `SignedIntegerHelper`. - pub impl CheckedSubImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::CheckedSub { - fn checked_sub(self: T, v: T) -> Option { - as_checked(H::sub(self, v)) - } - } - - /// Converts `SignedIntegerResult` to an `Some` if in range and to `None` - /// otherwise. - fn as_checked>(result: SignedIntegerResult) -> Option { - match result { - SignedIntegerResult::InRange(result) => Some(result), - SignedIntegerResult::Underflow(_) | SignedIntegerResult::Overflow(_) => None, - } - } - - /// Impl for `SaturatingAdd` based on `SignedIntegerHelper`. - pub impl SaturatingAddImpl< - T, impl H: SignedIntegerHelper, +Drop, +crate::num::traits::Bounded, - > of crate::num::traits::SaturatingAdd { - fn saturating_add(self: T, other: T) -> T { - as_saturating(H::add(self, other)) - } - } - - /// Impl for `SaturatingSub` based on `SignedIntegerHelper`. - pub impl SaturatingSubImpl< - T, impl H: SignedIntegerHelper, +Drop, +crate::num::traits::Bounded, - > of crate::num::traits::SaturatingSub { - fn saturating_sub(self: T, other: T) -> T { - as_saturating(H::sub(self, other)) - } - } - - /// Converts `SignedIntegerResult` to a saturated value. - fn as_saturating, impl B: crate::num::traits::Bounded>( - result: SignedIntegerResult, - ) -> T { - match result { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => B::MIN, - SignedIntegerResult::Overflow(_) => B::MAX, - } - } - - /// Impl for `OverflowingAdd` based on `SignedIntegerHelper`. - pub impl OverflowingAddImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: T, v: T) -> (T, bool) { - as_overflowing(H::add(self, v)) - } - } - - /// Impl for `OverflowingSub` based on `SignedIntegerHelper`. - pub impl OverflowingSubImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: T, v: T) -> (T, bool) { - as_overflowing(H::sub(self, v)) - } - } - - /// Converts `SignedIntegerResult` to a tuple of the result and a boolean indicating overflow. - fn as_overflowing(result: SignedIntegerResult) -> (T, bool) { - match result { - SignedIntegerResult::InRange(result) => (result, false), - SignedIntegerResult::Underflow(result) | - SignedIntegerResult::Overflow(result) => (result, true), - } - } - - /// Impl for `WrappingAdd` based on `SignedIntegerHelper`. - pub impl WrappingAddImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::WrappingAdd { - fn wrapping_add(self: T, v: T) -> T { - as_wrapping(H::add(self, v)) - } - } - - /// Impl for `WrappingSub` based on `SignedIntegerHelper`. - pub impl WrappingSubImpl< - T, impl H: SignedIntegerHelper, +Drop, - > of crate::num::traits::WrappingSub { - fn wrapping_sub(self: T, v: T) -> T { - as_wrapping(H::sub(self, v)) - } - } - - /// Converts `SignedIntegerResult` to a wrapping value. - fn as_wrapping(result: SignedIntegerResult) -> T { - match result { - SignedIntegerResult::InRange(result) | SignedIntegerResult::Underflow(result) | - SignedIntegerResult::Overflow(result) => result, - } - } -} - -impl I8CheckedAdd = signed_int_impls::CheckedAddImpl; -impl I8CheckedSub = signed_int_impls::CheckedSubImpl; -impl I8SaturatingAdd = signed_int_impls::SaturatingAddImpl; -impl I8SaturatingSub = signed_int_impls::SaturatingSubImpl; -impl I8OverflowingAdd = signed_int_impls::OverflowingAddImpl; -impl I8OverflowingSub = signed_int_impls::OverflowingSubImpl; -impl I8WrappingAdd = signed_int_impls::WrappingAddImpl; -impl I8WrappingSub = signed_int_impls::WrappingSubImpl; - -impl I16CheckedAdd = signed_int_impls::CheckedAddImpl; -impl I16CheckedSub = signed_int_impls::CheckedSubImpl; -impl I16SaturatingAdd = signed_int_impls::SaturatingAddImpl; -impl I16SaturatingSub = signed_int_impls::SaturatingSubImpl; -impl I16OverflowingAdd = signed_int_impls::OverflowingAddImpl; -impl I16OverflowingSub = signed_int_impls::OverflowingSubImpl; -impl I16WrappingAdd = signed_int_impls::WrappingAddImpl; -impl I16WrappingSub = signed_int_impls::WrappingSubImpl; - -impl I32CheckedAdd = signed_int_impls::CheckedAddImpl; -impl I32CheckedSub = signed_int_impls::CheckedSubImpl; -impl I32SaturatingAdd = signed_int_impls::SaturatingAddImpl; -impl I32SaturatingSub = signed_int_impls::SaturatingSubImpl; -impl I32OverflowingAdd = signed_int_impls::OverflowingAddImpl; -impl I32OverflowingSub = signed_int_impls::OverflowingSubImpl; -impl I32WrappingAdd = signed_int_impls::WrappingAddImpl; -impl I32WrappingSub = signed_int_impls::WrappingSubImpl; - -impl I64CheckedAdd = signed_int_impls::CheckedAddImpl; -impl I64CheckedSub = signed_int_impls::CheckedSubImpl; -impl I64SaturatingAdd = signed_int_impls::SaturatingAddImpl; -impl I64SaturatingSub = signed_int_impls::SaturatingSubImpl; -impl I64OverflowingAdd = signed_int_impls::OverflowingAddImpl; -impl I64OverflowingSub = signed_int_impls::OverflowingSubImpl; -impl I64WrappingAdd = signed_int_impls::WrappingAddImpl; -impl I64WrappingSub = signed_int_impls::WrappingSubImpl; - -impl I128CheckedAdd = signed_int_impls::CheckedAddImpl; -impl I128CheckedSub = signed_int_impls::CheckedSubImpl; -impl I128SaturatingAdd = signed_int_impls::SaturatingAddImpl; -impl I128SaturatingSub = signed_int_impls::SaturatingSubImpl; -impl I128OverflowingAdd = signed_int_impls::OverflowingAddImpl; -impl I128OverflowingSub = signed_int_impls::OverflowingSubImpl; -impl I128WrappingAdd = signed_int_impls::WrappingAddImpl; -impl I128WrappingSub = signed_int_impls::WrappingSubImpl; - -/// The 8-bit signed integer type. -pub extern type i8; - -impl i8Copy of Copy; -impl i8Drop of Drop; - -impl NumericLiterali8 of NumericLiteral; - -extern const fn i8_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; -extern const fn i8_to_felt252(a: i8) -> felt252 nopanic; - -extern fn i8_eq(lhs: i8, rhs: i8) -> bool implicits() nopanic; - -impl I8Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl I8PartialEq of PartialEq { - #[inline] - fn eq(lhs: @i8, rhs: @i8) -> bool { - i8_eq(*lhs, *rhs) - } -} - -extern fn i8_overflowing_add_impl( - lhs: i8, rhs: i8, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -extern fn i8_overflowing_sub_impl( - lhs: i8, rhs: i8, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -impl I8Add of Add { - fn add(lhs: i8, rhs: i8) -> i8 { - match i8_overflowing_add_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i8_add Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i8_add Overflow'), - } - } -} - -impl I8Sub of Sub { - fn sub(lhs: i8, rhs: i8) -> i8 { - match i8_overflowing_sub_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i8_sub Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i8_sub Overflow'), - } - } -} - -impl I8Neg of Neg { - #[inline] - #[feature("bounded-int-utils")] - fn neg(a: i8) -> i8 { - let core::internal::OptionRev::Some(a) = core::internal::bounded_int::trim_min(a) else { - crate::panic_with_felt252('i8_neg Underflow'); - }; - upcast(core::internal::bounded_int::NegateHelper::negate(a)) - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `crate::num::traits::WideMul` instead")] -pub extern fn i8_wide_mul(lhs: i8, rhs: i8) -> i16 implicits() nopanic; -impl I8Mul of Mul { - fn mul(lhs: i8, rhs: i8) -> i8 { - i8_wide_mul(lhs, rhs).try_into().expect('i8_mul Overflow') - } -} - -/// If `lhs` >= `rhs` returns `Ok(lhs - rhs)` else returns `Err(2**8 + lhs - rhs)`. -pub extern fn i8_diff(lhs: i8, rhs: i8) -> Result implicits(RangeCheck) nopanic; - -impl I8PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: i8, rhs: i8) -> bool { - i8_diff(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: i8, rhs: i8) -> bool { - i8_diff(lhs, rhs).into_is_ok() - } -} - -impl I8BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 8 - } -} - -/// The 16-bit signed integer type. -pub extern type i16; - -impl i16Copy of Copy; -impl i16Drop of Drop; - -impl NumericLiterali16 of NumericLiteral; - -extern const fn i16_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; -extern const fn i16_to_felt252(a: i16) -> felt252 nopanic; - -extern fn i16_eq(lhs: i16, rhs: i16) -> bool implicits() nopanic; - -impl I16Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl I16PartialEq of PartialEq { - #[inline] - fn eq(lhs: @i16, rhs: @i16) -> bool { - i16_eq(*lhs, *rhs) - } -} - -extern fn i16_overflowing_add_impl( - lhs: i16, rhs: i16, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -extern fn i16_overflowing_sub_impl( - lhs: i16, rhs: i16, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -impl I16Add of Add { - fn add(lhs: i16, rhs: i16) -> i16 { - match i16_overflowing_add_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i16_add Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i16_add Overflow'), - } - } -} - -impl I16Sub of Sub { - fn sub(lhs: i16, rhs: i16) -> i16 { - match i16_overflowing_sub_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i16_sub Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i16_sub Overflow'), - } - } -} - -impl I16Neg of Neg { - #[inline] - #[feature("bounded-int-utils")] - fn neg(a: i16) -> i16 { - let core::internal::OptionRev::Some(a) = core::internal::bounded_int::trim_min(a) else { - crate::panic_with_felt252('i16_neg Underflow'); - }; - upcast(core::internal::bounded_int::NegateHelper::negate(a)) - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `crate::num::traits::WideMul` instead")] -pub extern fn i16_wide_mul(lhs: i16, rhs: i16) -> i32 implicits() nopanic; - -impl I16Mul of Mul { - fn mul(lhs: i16, rhs: i16) -> i16 { - i16_wide_mul(lhs, rhs).try_into().expect('i16_mul Overflow') - } -} - -/// If `lhs` >= `rhs` returns `Ok(lhs - rhs)` else returns `Err(2**16 + lhs - rhs)`. -pub extern fn i16_diff(lhs: i16, rhs: i16) -> Result implicits(RangeCheck) nopanic; - -impl I16PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: i16, rhs: i16) -> bool { - i16_diff(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: i16, rhs: i16) -> bool { - i16_diff(lhs, rhs).into_is_ok() - } -} - -impl I16BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 16 - } -} - -/// The 32-bit signed integer type. -pub extern type i32; - -impl i32Copy of Copy; -impl i32Drop of Drop; - -impl NumericLiterali32 of NumericLiteral; - -extern const fn i32_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; -extern const fn i32_to_felt252(a: i32) -> felt252 nopanic; - -extern fn i32_eq(lhs: i32, rhs: i32) -> bool implicits() nopanic; - -impl I32Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl I32PartialEq of PartialEq { - #[inline] - fn eq(lhs: @i32, rhs: @i32) -> bool { - i32_eq(*lhs, *rhs) - } -} - -extern fn i32_overflowing_add_impl( - lhs: i32, rhs: i32, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -extern fn i32_overflowing_sub_impl( - lhs: i32, rhs: i32, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -impl I32Add of Add { - fn add(lhs: i32, rhs: i32) -> i32 { - match i32_overflowing_add_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i32_add Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i32_add Overflow'), - } - } -} - -impl I32Sub of Sub { - fn sub(lhs: i32, rhs: i32) -> i32 { - match i32_overflowing_sub_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i32_sub Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i32_sub Overflow'), - } - } -} - -impl I32Neg of Neg { - #[inline] - #[feature("bounded-int-utils")] - fn neg(a: i32) -> i32 { - let core::internal::OptionRev::Some(a) = core::internal::bounded_int::trim_min(a) else { - crate::panic_with_felt252('i32_neg Underflow'); - }; - upcast(core::internal::bounded_int::NegateHelper::negate(a)) - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn i32_wide_mul(lhs: i32, rhs: i32) -> i64 implicits() nopanic; - -impl I32Mul of Mul { - fn mul(lhs: i32, rhs: i32) -> i32 { - i32_wide_mul(lhs, rhs).try_into().expect('i32_mul Overflow') - } -} - -/// If `lhs` >= `rhs` returns `Ok(lhs - rhs)` else returns `Err(2**32 + lhs - rhs)`. -pub extern fn i32_diff(lhs: i32, rhs: i32) -> Result implicits(RangeCheck) nopanic; - -impl I32PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: i32, rhs: i32) -> bool { - i32_diff(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: i32, rhs: i32) -> bool { - i32_diff(lhs, rhs).into_is_ok() - } -} - -impl I32BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 32 - } -} - -/// The 64-bit signed integer type. -pub extern type i64; - -impl i64Copy of Copy; -impl i64Drop of Drop; - -impl NumericLiterali64 of NumericLiteral; - -extern const fn i64_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; -extern const fn i64_to_felt252(a: i64) -> felt252 nopanic; - -extern fn i64_eq(lhs: i64, rhs: i64) -> bool implicits() nopanic; - -impl I64Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl I64PartialEq of PartialEq { - #[inline] - fn eq(lhs: @i64, rhs: @i64) -> bool { - i64_eq(*lhs, *rhs) - } -} - -extern fn i64_overflowing_add_impl( - lhs: i64, rhs: i64, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -extern fn i64_overflowing_sub_impl( - lhs: i64, rhs: i64, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -impl I64Add of Add { - fn add(lhs: i64, rhs: i64) -> i64 { - match i64_overflowing_add_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i64_add Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i64_add Overflow'), - } - } -} - -impl I64Sub of Sub { - fn sub(lhs: i64, rhs: i64) -> i64 { - match i64_overflowing_sub_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i64_sub Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i64_sub Overflow'), - } - } -} - -impl I64Neg of Neg { - #[inline] - #[feature("bounded-int-utils")] - fn neg(a: i64) -> i64 { - let core::internal::OptionRev::Some(a) = core::internal::bounded_int::trim_min(a) else { - crate::panic_with_felt252('i64_neg Underflow'); - }; - upcast(core::internal::bounded_int::NegateHelper::negate(a)) - } -} - -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::WideMul` instead")] -pub extern fn i64_wide_mul(lhs: i64, rhs: i64) -> i128 implicits() nopanic; - -impl I64Mul of Mul { - fn mul(lhs: i64, rhs: i64) -> i64 { - i64_wide_mul(lhs, rhs).try_into().expect('i64_mul Overflow') - } -} - -/// If `lhs` >= `rhs` returns `Ok(lhs - rhs)` else returns `Err(2**64 + lhs - rhs)`. -pub extern fn i64_diff(lhs: i64, rhs: i64) -> Result implicits(RangeCheck) nopanic; - -impl I64PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: i64, rhs: i64) -> bool { - i64_diff(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: i64, rhs: i64) -> bool { - i64_diff(lhs, rhs).into_is_ok() - } -} - -impl I64BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 64 - } -} - -/// The 128-bit signed integer type. -pub extern type i128; - -impl i128Copy of Copy; -impl i128Drop of Drop; - -impl NumericLiterali128 of NumericLiteral; - -extern const fn i128_try_from_felt252(a: felt252) -> Option implicits(RangeCheck) nopanic; -extern const fn i128_to_felt252(a: i128) -> felt252 nopanic; - -extern fn i128_eq(lhs: i128, rhs: i128) -> bool implicits() nopanic; - -impl I128Serde = crate::serde::into_felt252_based::SerdeImpl; - -impl I128PartialEq of PartialEq { - #[inline] - fn eq(lhs: @i128, rhs: @i128) -> bool { - i128_eq(*lhs, *rhs) - } - - #[inline] - fn ne(lhs: @i128, rhs: @i128) -> bool { - !(*lhs == *rhs) - } -} - -extern fn i128_overflowing_add_impl( - lhs: i128, rhs: i128, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -extern fn i128_overflowing_sub_impl( - lhs: i128, rhs: i128, -) -> SignedIntegerResult implicits(RangeCheck) nopanic; - -impl I128Add of Add { - fn add(lhs: i128, rhs: i128) -> i128 { - match i128_overflowing_add_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i128_add Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i128_add Overflow'), - } - } -} - -impl I128Sub of Sub { - fn sub(lhs: i128, rhs: i128) -> i128 { - match i128_overflowing_sub_impl(lhs, rhs) { - SignedIntegerResult::InRange(result) => result, - SignedIntegerResult::Underflow(_) => crate::panic_with_felt252('i128_sub Underflow'), - SignedIntegerResult::Overflow(_) => crate::panic_with_felt252('i128_sub Overflow'), - } - } -} - -impl I128Neg of Neg { - #[inline] - #[feature("bounded-int-utils")] - fn neg(a: i128) -> i128 { - let core::internal::OptionRev::Some(a) = core::internal::bounded_int::trim_min(a) else { - crate::panic_with_felt252('i128_neg Underflow'); - }; - upcast(core::internal::bounded_int::NegateHelper::negate(a)) - } -} - -impl I128Mul of Mul { - fn mul(lhs: i128, rhs: i128) -> i128 { - let (lhs_u127, lhs_neg) = lhs.abs_and_sign(); - #[feature("bounded-int-utils")] - let (rhs_u127, res_neg) = match core::internal::bounded_int::constrain::(rhs) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), !lhs_neg), - Err(ge0) => (upcast(ge0), lhs_neg), - }; - let res_as_u128 = lhs_u127 * rhs_u127; - let res_as_felt252: felt252 = if res_neg { - -res_as_u128.into() - } else { - res_as_u128.into() - }; - res_as_felt252.try_into().expect('i128_mul Overflow') - } -} - -/// If `lhs` >= `rhs` returns `Ok(lhs - rhs)` else returns `Err(2**128 + lhs - rhs)`. -pub extern fn i128_diff(lhs: i128, rhs: i128) -> Result implicits(RangeCheck) nopanic; - -impl I128PartialOrd of PartialOrd { - #[inline] - fn lt(lhs: i128, rhs: i128) -> bool { - i128_diff(lhs, rhs).into_is_err() - } - - #[inline] - fn ge(lhs: i128, rhs: i128) -> bool { - i128_diff(lhs, rhs).into_is_ok() - } -} - -mod signed_div_rem { - #[feature("bounded-int-utils")] - use crate::internal::bounded_int::{ - BoundedInt, ConstrainHelper, DivRemHelper, MulHelper, NegateHelper, UnitInt, constrain, - div_rem, downcast, is_zero, upcast, - }; - - impl DivRemImpl< - T, - impl CH: ConstrainHelper, - impl NH: MulHelper>, - // Positive by Positive Div Rem (PPDR) Helper. - impl PPDR: DivRemHelper, - // Negative by Positive Div Rem (NPDR) Helper. - impl NPDR: DivRemHelper, - // Positive by Negative Div Rem (PNDR) Helper. - impl PNDR: DivRemHelper, - // Negative by Negative Div Rem (NNDR) Helper. - impl NNDR: DivRemHelper, - +MulHelper>, - +MulHelper>, - +MulHelper>, - +MulHelper>, - +Drop, - +Drop, - +Drop, - +Drop, - +Drop, - +Drop, - +Drop, - > of DivRem { - fn div_rem(lhs: T, rhs: NonZero) -> (T, T) { - match constrain::(lhs) { - Ok(lhs_lt0) => { - match constrain::, 0>(rhs) { - Ok(rhs_lt0) => { - let (q, r) = div_rem(lhs_lt0.negate(), rhs_lt0.negate()); - ( - // Catching the case for division of `i{8,16,32,64,128}::MIN` by - // `-1`, which overflows. - downcast(q).expect('attempt to divide with overflow'), - upcast(r.negate()), - ) - }, - Err(rhs_ge0) => { - let (q, r) = div_rem(lhs_lt0.negate(), rhs_ge0); - (upcast(q.negate()), upcast(r.negate())) - }, - } - }, - Err(lhs_ge0) => { - match constrain::, 0>(rhs) { - Ok(rhs_lt0) => { - let (q, r) = div_rem(lhs_ge0, rhs_lt0.negate()); - (upcast(q.negate()), upcast(r)) - }, - Err(rhs_ge0) => { - let (q, r) = div_rem(lhs_ge0, rhs_ge0); - (upcast(q), upcast(r)) - }, - } - }, - } - } - } - - mod impls { - pub impl DivRem of super::DivRemHelper { - type DivT = DivT; - type RemT = RemT; - } - } - - type i8_neg = ConstrainHelper::::LowT; - type i8_pos = ConstrainHelper::::HighT; - type minus_i8_neg = NegateHelper::::Result; - - impl I8PPDR = impls::DivRem>; - impl I8NPDR = impls::DivRem, BoundedInt<0, 0x7e>>; - impl I8PNDR = impls::DivRem; - impl I8NNDR = impls::DivRem, i8_pos>; - pub impl I8DivRem = DivRemImpl; - - type i16_neg = ConstrainHelper::::LowT; - type i16_pos = ConstrainHelper::::HighT; - type minus_i16_neg = NegateHelper::::Result; - - impl I16PPDR = impls::DivRem>; - impl I16NPDR = - impls::DivRem, BoundedInt<0, 0x7ffe>>; - impl I16PNDR = impls::DivRem; - impl I16NNDR = impls::DivRem, i16_pos>; - pub impl I16DivRem = DivRemImpl; - - type i32_neg = ConstrainHelper::::LowT; - type i32_pos = ConstrainHelper::::HighT; - type minus_i32_neg = NegateHelper::::Result; - - impl I32PPDR = impls::DivRem>; - impl I32NPDR = - impls::DivRem, BoundedInt<0, 0x7ffffffe>>; - impl I32PNDR = impls::DivRem; - impl I32NNDR = impls::DivRem, i32_pos>; - pub impl I32DivRem = DivRemImpl; - - type i64_neg = ConstrainHelper::::LowT; - type i64_pos = ConstrainHelper::::HighT; - type minus_i64_neg = NegateHelper::::Result; - - impl I64PPDR = impls::DivRem>; - impl I64NPDR = - impls::DivRem< - minus_i64_neg, - i64_pos, - BoundedInt<0, 0x8000000000000000>, - BoundedInt<0, 0x7ffffffffffffffe>, - >; - impl I64PNDR = impls::DivRem; - impl I64NNDR = - impls::DivRem, i64_pos>; - pub impl I64DivRem = DivRemImpl; - - type i128_neg = ConstrainHelper::::LowT; - type i128_pos = ConstrainHelper::::HighT; - type minus_i128_neg = NegateHelper::::Result; - - impl I128PPDR = - impls::DivRem< - i128_pos, i128_pos, i128_pos, BoundedInt<0, 0x7ffffffffffffffffffffffffffffffe>, - >; - impl I128NPDR = - impls::DivRem< - minus_i128_neg, - i128_pos, - BoundedInt<0, 0x80000000000000000000000000000000>, - BoundedInt<0, 0x7ffffffffffffffffffffffffffffffe>, - >; - impl I128PNDR = impls::DivRem; - impl I128NNDR = - impls::DivRem< - minus_i128_neg, - minus_i128_neg, - BoundedInt<0, 0x80000000000000000000000000000000>, - i128_pos, - >; - pub impl I128DivRem = DivRemImpl; - - pub impl TryIntoNonZero of TryInto> { - const fn try_into(self: T) -> Option> { - match is_zero(self) { - super::IsZeroResult::Zero => None, - super::IsZeroResult::NonZero(x) => Some(x), - } - } - } -} - -impl I8DivRem = signed_div_rem::I8DivRem; -impl I8TryIntoNonZero = signed_div_rem::TryIntoNonZero; -impl I16DivRem = signed_div_rem::I16DivRem; -impl I16TryIntoNonZero = signed_div_rem::TryIntoNonZero; -impl I32DivRem = signed_div_rem::I32DivRem; -impl I32TryIntoNonZero = signed_div_rem::TryIntoNonZero; -impl I64DivRem = signed_div_rem::I64DivRem; -impl I64TryIntoNonZero = signed_div_rem::TryIntoNonZero; -impl I128DivRem = signed_div_rem::I128DivRem; -impl I128TryIntoNonZero = signed_div_rem::TryIntoNonZero; - -// Implementations for `Div` and `Rem` given `DivRem`. -mod by_div_rem { - pub impl DivImpl, +TryInto>, +Drop> of Div { - fn div(lhs: T, rhs: T) -> T { - let (q, _r) = DivRem::div_rem(lhs, rhs.try_into().expect('Division by 0')); - q - } - } - - pub impl RemImpl, +TryInto>, +Drop> of Rem { - fn rem(lhs: T, rhs: T) -> T { - let (_q, r) = DivRem::div_rem(lhs, rhs.try_into().expect('Division by 0')); - r - } - } -} - -impl U8Div = by_div_rem::DivImpl; -impl U8Rem = by_div_rem::RemImpl; -impl U16Div = by_div_rem::DivImpl; -impl U16Rem = by_div_rem::RemImpl; -impl U32Div = by_div_rem::DivImpl; -impl U32Rem = by_div_rem::RemImpl; -impl U64Div = by_div_rem::DivImpl; -impl U64Rem = by_div_rem::RemImpl; -impl U128Div = by_div_rem::DivImpl; -impl U128Rem = by_div_rem::RemImpl; -impl U256Div = by_div_rem::DivImpl; -impl U256Rem = by_div_rem::RemImpl; - -impl I8Div = by_div_rem::DivImpl; -impl I8Rem = by_div_rem::RemImpl; -impl I16Div = by_div_rem::DivImpl; -impl I16Rem = by_div_rem::RemImpl; -impl I32Div = by_div_rem::DivImpl; -impl I32Rem = by_div_rem::RemImpl; -impl I64Div = by_div_rem::DivImpl; -impl I64Rem = by_div_rem::RemImpl; -impl I128Div = by_div_rem::DivImpl; -impl I128Rem = by_div_rem::RemImpl; - -// Implementations for `*Eq` operations. -#[feature("deprecated-op-assign-traits")] -mod op_eq_by_op { - pub impl AddEqImpl> of crate::traits::AddEq { - fn add_eq(ref self: T, other: T) { - self = Add::add(self, other); - } - } - - pub impl SubEqImpl> of crate::traits::SubEq { - fn sub_eq(ref self: T, other: T) { - self = Sub::sub(self, other); - } - } - - pub impl MulEqImpl> of crate::traits::MulEq { - fn mul_eq(ref self: T, other: T) { - self = Mul::mul(self, other); - } - } - - pub impl DivEqImpl> of crate::traits::DivEq { - fn div_eq(ref self: T, other: T) { - self = Div::div(self, other); - } - } - - pub impl RemEqImpl> of crate::traits::RemEq { - fn rem_eq(ref self: T, other: T) { - self = Rem::rem(self, other); - } - } -} - -impl I8AddEq = op_eq_by_op::AddEqImpl; -impl I8SubEq = op_eq_by_op::SubEqImpl; -impl I8MulEq = op_eq_by_op::MulEqImpl; -impl I8DivEq = op_eq_by_op::DivEqImpl; -impl I8RemEq = op_eq_by_op::RemEqImpl; -impl I16AddEq = op_eq_by_op::AddEqImpl; -impl I16SubEq = op_eq_by_op::SubEqImpl; -impl I16MulEq = op_eq_by_op::MulEqImpl; -impl I16DivEq = op_eq_by_op::DivEqImpl; -impl I16RemEq = op_eq_by_op::RemEqImpl; -impl I32AddEq = op_eq_by_op::AddEqImpl; -impl I32SubEq = op_eq_by_op::SubEqImpl; -impl I32MulEq = op_eq_by_op::MulEqImpl; -impl I64AddEq = op_eq_by_op::AddEqImpl; -impl I64SubEq = op_eq_by_op::SubEqImpl; -impl I64MulEq = op_eq_by_op::MulEqImpl; -impl I128AddEq = op_eq_by_op::AddEqImpl; -impl I128SubEq = op_eq_by_op::SubEqImpl; -impl I128MulEq = op_eq_by_op::MulEqImpl; -impl U8AddEq = op_eq_by_op::AddEqImpl; -impl U8SubEq = op_eq_by_op::SubEqImpl; -impl U8MulEq = op_eq_by_op::MulEqImpl; -impl U8DivEq = op_eq_by_op::DivEqImpl; -impl U8RemEq = op_eq_by_op::RemEqImpl; -impl U16AddEq = op_eq_by_op::AddEqImpl; -impl U16SubEq = op_eq_by_op::SubEqImpl; -impl U16MulEq = op_eq_by_op::MulEqImpl; -impl U16DivEq = op_eq_by_op::DivEqImpl; -impl U16RemEq = op_eq_by_op::RemEqImpl; -impl U32AddEq = op_eq_by_op::AddEqImpl; -impl U32SubEq = op_eq_by_op::SubEqImpl; -impl U32MulEq = op_eq_by_op::MulEqImpl; -impl U32DivEq = op_eq_by_op::DivEqImpl; -impl U32RemEq = op_eq_by_op::RemEqImpl; -impl U64AddEq = op_eq_by_op::AddEqImpl; -impl U64SubEq = op_eq_by_op::SubEqImpl; -impl U64MulEq = op_eq_by_op::MulEqImpl; -impl U64DivEq = op_eq_by_op::DivEqImpl; -impl U64RemEq = op_eq_by_op::RemEqImpl; -impl U128AddEq = op_eq_by_op::AddEqImpl; -impl U128SubEq = op_eq_by_op::SubEqImpl; -impl U128MulEq = op_eq_by_op::MulEqImpl; -impl U128DivEq = op_eq_by_op::DivEqImpl; -impl U128RemEq = op_eq_by_op::RemEqImpl; -impl U256AddEq = op_eq_by_op::AddEqImpl; -impl U256SubEq = op_eq_by_op::SubEqImpl; -impl U256MulEq = op_eq_by_op::MulEqImpl; -impl U256DivEq = op_eq_by_op::DivEqImpl; -impl U256RemEq = op_eq_by_op::RemEqImpl; - -// Zeroable impls -pub(crate) impl U8Zeroable = crate::zeroable::zero_based::ZeroableImpl; -pub(crate) impl U16Zeroable = crate::zeroable::zero_based::ZeroableImpl; -pub(crate) impl U32Zeroable = crate::zeroable::zero_based::ZeroableImpl; -pub(crate) impl U64Zeroable = crate::zeroable::zero_based::ZeroableImpl; -pub(crate) impl U128Zeroable = crate::zeroable::zero_based::ZeroableImpl; -pub(crate) impl U256Zeroable = crate::zeroable::zero_based::ZeroableImpl; - -impl I128BitSize of crate::num::traits::BitSize { - fn bits() -> usize { - 128 - } -} - -// Zero trait implementations -impl U8Zero of crate::num::traits::Zero { - const fn zero() -> u8 { - 0 - } - - #[inline] - const fn is_zero(self: @u8) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u8) -> bool { - !self.is_zero() - } -} - -impl U16Zero of crate::num::traits::Zero { - const fn zero() -> u16 { - 0 - } - - #[inline] - const fn is_zero(self: @u16) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u16) -> bool { - !self.is_zero() - } -} - -impl U32Zero of crate::num::traits::Zero { - const fn zero() -> u32 { - 0 - } - - #[inline] - const fn is_zero(self: @u32) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u32) -> bool { - !self.is_zero() - } -} - -impl U64Zero of crate::num::traits::Zero { - const fn zero() -> u64 { - 0 - } - - #[inline] - const fn is_zero(self: @u64) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u64) -> bool { - !self.is_zero() - } -} - -impl U128Zero of crate::num::traits::Zero { - const fn zero() -> u128 { - 0 - } - - #[inline] - const fn is_zero(self: @u128) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u128) -> bool { - !self.is_zero() - } -} - -impl U256Zero of crate::num::traits::Zero { - const fn zero() -> u256 { - 0 - } - - #[inline] - const fn is_zero(self: @u256) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @u256) -> bool { - !self.is_zero() - } -} - -impl I8Zero of crate::num::traits::Zero { - const fn zero() -> i8 { - 0 - } - - #[inline] - const fn is_zero(self: @i8) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @i8) -> bool { - !self.is_zero() - } -} - -impl I16Zero of crate::num::traits::Zero { - const fn zero() -> i16 { - 0 - } - - #[inline] - const fn is_zero(self: @i16) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @i16) -> bool { - !self.is_zero() - } -} - -impl I32Zero of crate::num::traits::Zero { - const fn zero() -> i32 { - 0 - } - - #[inline] - const fn is_zero(self: @i32) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @i32) -> bool { - !self.is_zero() - } -} - -impl I64Zero of crate::num::traits::Zero { - const fn zero() -> i64 { - 0 - } - - #[inline] - const fn is_zero(self: @i64) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @i64) -> bool { - !self.is_zero() - } -} - -impl I128Zero of crate::num::traits::Zero { - const fn zero() -> i128 { - 0 - } - - #[inline] - const fn is_zero(self: @i128) -> bool { - *self == Self::zero() - } - - #[inline] - const fn is_non_zero(self: @i128) -> bool { - !self.is_zero() - } -} - -// One trait implementations -impl U8One of crate::num::traits::One { - fn one() -> u8 { - 1 - } - - #[inline] - fn is_one(self: @u8) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u8) -> bool { - !self.is_one() - } -} - -impl U16One of crate::num::traits::One { - fn one() -> u16 { - 1 - } - - #[inline] - fn is_one(self: @u16) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u16) -> bool { - !self.is_one() - } -} - -impl U32One of crate::num::traits::One { - fn one() -> u32 { - 1 - } - - #[inline] - fn is_one(self: @u32) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u32) -> bool { - !self.is_one() - } -} - -impl U64One of crate::num::traits::One { - fn one() -> u64 { - 1 - } - - #[inline] - fn is_one(self: @u64) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u64) -> bool { - !self.is_one() - } -} - -impl U128One of crate::num::traits::One { - fn one() -> u128 { - 1 - } - - #[inline] - fn is_one(self: @u128) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u128) -> bool { - !self.is_one() - } -} - -impl U256One of crate::num::traits::One { - fn one() -> u256 { - 1 - } - - #[inline] - fn is_one(self: @u256) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @u256) -> bool { - !self.is_one() - } -} - -impl I8One of crate::num::traits::One { - fn one() -> i8 { - 1 - } - - #[inline] - fn is_one(self: @i8) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @i8) -> bool { - !self.is_one() - } -} - -impl I16One of crate::num::traits::One { - fn one() -> i16 { - 1 - } - - #[inline] - fn is_one(self: @i16) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @i16) -> bool { - !self.is_one() - } -} - -impl I32One of crate::num::traits::One { - fn one() -> i32 { - 1 - } - - #[inline] - fn is_one(self: @i32) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @i32) -> bool { - !self.is_one() - } -} - -impl I64One of crate::num::traits::One { - fn one() -> i64 { - 1 - } - - #[inline] - fn is_one(self: @i64) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @i64) -> bool { - !self.is_one() - } -} - -impl I128One of crate::num::traits::One { - fn one() -> i128 { - 1 - } - - #[inline] - fn is_one(self: @i128) -> bool { - *self == Self::one() - } - - #[inline] - fn is_non_one(self: @i128) -> bool { - !self.is_one() - } -} - -// OverflowingAdd implementations -impl U8OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u8, v: u8) -> (u8, bool) { - match u8_overflowing_add(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U16OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u16, v: u16) -> (u16, bool) { - match u16_overflowing_add(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U32OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u32, v: u32) -> (u32, bool) { - match u32_overflowing_add(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U64OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u64, v: u64) -> (u64, bool) { - match u64_overflowing_add(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U128OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u128, v: u128) -> (u128, bool) { - match u128_overflowing_add(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U256OverflowingAdd of crate::num::traits::OverflowingAdd { - fn overflowing_add(self: u256, v: u256) -> (u256, bool) { - u256_overflowing_add(self, v) - } -} - -// OverflowingSub implementations -impl U8OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u8, v: u8) -> (u8, bool) { - match u8_overflowing_sub(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U16OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u16, v: u16) -> (u16, bool) { - match u16_overflowing_sub(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U32OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u32, v: u32) -> (u32, bool) { - match u32_overflowing_sub(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U64OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u64, v: u64) -> (u64, bool) { - match u64_overflowing_sub(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U128OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u128, v: u128) -> (u128, bool) { - match u128_overflowing_sub(self, v) { - Ok(x) => (x, false), - Err(x) => (x, true), - } - } -} - -impl U256OverflowingSub of crate::num::traits::OverflowingSub { - fn overflowing_sub(self: u256, v: u256) -> (u256, bool) { - u256_overflowing_sub(self, v) - } -} - -// OverflowingMul implementations -impl U8OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u8, v: u8) -> (u8, bool) { - let (high, low) = crate::num::traits::Split::split(u8_wide_mul(self, v)); - (low, high != 0) - } -} - -impl U16OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u16, v: u16) -> (u16, bool) { - let (high, low) = crate::num::traits::Split::split(u16_wide_mul(self, v)); - (low, high != 0) - } -} - -impl U32OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u32, v: u32) -> (u32, bool) { - let (high, low) = crate::num::traits::Split::split(u32_wide_mul(self, v)); - (low, high != 0) - } -} - -impl U64OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u64, v: u64) -> (u64, bool) { - let (high, low) = crate::num::traits::Split::split(u64_wide_mul(self, v)); - (low, high != 0) - } -} - -impl U128OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u128, v: u128) -> (u128, bool) { - u128_overflowing_mul(self, v) - } -} - -impl U256OverflowingMul of crate::num::traits::OverflowingMul { - fn overflowing_mul(self: u256, v: u256) -> (u256, bool) { - u256_overflowing_mul(self, v) - } -} - -/// WrappingAdd implementations -impl U8WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl U16WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl U32WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl U64WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl U128WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; -impl U256WrappingAdd = crate::num::traits::ops::wrapping::overflow_based::TWrappingAdd; - -/// WrappingSub implementations -impl U8WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl U16WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl U32WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl U64WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl U128WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; -impl U256WrappingSub = crate::num::traits::ops::wrapping::overflow_based::TWrappingSub; - -/// WrappingMul implementations -impl U8WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; -impl U16WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; -impl U32WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; -impl U64WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; -impl U128WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; -impl U256WrappingMul = crate::num::traits::ops::wrapping::overflow_based::TWrappingMul; - -// CheckedAdd implementations -impl U8CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u8, v: u8) -> Option { - u8_checked_add(self, v) - } -} - -impl U16CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u16, v: u16) -> Option { - u16_checked_add(self, v) - } -} - -impl U32CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u32, v: u32) -> Option { - u32_checked_add(self, v) - } -} - -impl U64CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u64, v: u64) -> Option { - u64_checked_add(self, v) - } -} - -impl U128CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u128, v: u128) -> Option { - u128_checked_add(self, v) - } -} - -impl U256CheckedAdd of crate::num::traits::CheckedAdd { - fn checked_add(self: u256, v: u256) -> Option { - u256_checked_add(self, v) - } -} - -// CheckedSub implementations -impl U8CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u8, v: u8) -> Option { - u8_checked_sub(self, v) - } -} - -impl U16CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u16, v: u16) -> Option { - u16_checked_sub(self, v) - } -} - -impl U32CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u32, v: u32) -> Option { - u32_checked_sub(self, v) - } -} - -impl U64CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u64, v: u64) -> Option { - u64_checked_sub(self, v) - } -} - -impl U128CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u128, v: u128) -> Option { - u128_checked_sub(self, v) - } -} - -impl U256CheckedSub of crate::num::traits::CheckedSub { - fn checked_sub(self: u256, v: u256) -> Option { - u256_checked_sub(self, v) - } -} - -// CheckedMul implementations -impl U8CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; -impl U16CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; -impl U32CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; -impl U64CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; -impl U128CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; -impl U256CheckedMul = crate::num::traits::ops::checked::overflow_based::TCheckedMul; - - -// SaturatingAdd implementations -impl U8SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl U16SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl U32SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl U64SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl U128SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; -impl U256SaturatingAdd = crate::num::traits::ops::saturating::overflow_based::TSaturatingAdd; - -// SaturatingSub implementations -impl U8SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl U16SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl U32SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl U64SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl U128SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; -impl U256SaturatingSub = crate::num::traits::ops::saturating::overflow_based::TSaturatingSub; - -// SaturatingMul implementations -impl U8SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; -impl U16SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; -impl U32SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; -impl U64SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; -impl U128SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; -impl U256SaturatingMul = crate::num::traits::ops::saturating::overflow_based::TSaturatingMul; - -mod bitnot_impls { - #[feature("bounded-int-utils")] - use core::internal::bounded_int::{BoundedInt, SubHelper, UnitInt, sub, upcast}; - - impl SubHelperImpl of SubHelper, T> { - type Result = BoundedInt<0, MAX>; - } - - pub impl Impl> of core::traits::BitNot { - fn bitnot(a: T) -> T { - upcast::, T>(sub(MAX_TYPED, a)) - } - } -} - -impl U8BitNot = bitnot_impls::Impl; -impl U16BitNot = bitnot_impls::Impl; -impl U32BitNot = bitnot_impls::Impl; -impl U64BitNot = bitnot_impls::Impl; -impl U128BitNot = - bitnot_impls::Impl< - u128, 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff, 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff, - >; - -/// Internal trait for easier finding of absolute values. -pub(crate) trait AbsAndSign { - /// Returns the absolute value of the `Signed` value as `Unsigned` and the original sign. - /// Returns `true` for sign if the number was negative and `false` otherwise. - fn abs_and_sign(self: Signed) -> (Unsigned, bool); -} - -impl I8ToU8 of AbsAndSign { - #[feature("bounded-int-utils")] - fn abs_and_sign(self: i8) -> (u8, bool) { - match core::internal::bounded_int::constrain::(self) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), true), - Err(ge0) => (upcast(ge0), false), - } - } -} - -impl I16ToU16 of AbsAndSign { - #[feature("bounded-int-utils")] - fn abs_and_sign(self: i16) -> (u16, bool) { - match core::internal::bounded_int::constrain::(self) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), true), - Err(ge0) => (upcast(ge0), false), - } - } -} - -impl I32ToU32 of AbsAndSign { - #[feature("bounded-int-utils")] - fn abs_and_sign(self: i32) -> (u32, bool) { - match core::internal::bounded_int::constrain::(self) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), true), - Err(ge0) => (upcast(ge0), false), - } - } -} - -impl I64ToU64 of AbsAndSign { - #[feature("bounded-int-utils")] - fn abs_and_sign(self: i64) -> (u64, bool) { - match core::internal::bounded_int::constrain::(self) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), true), - Err(ge0) => (upcast(ge0), false), - } - } -} - -impl I128ToU128 of AbsAndSign { - #[feature("bounded-int-utils")] - fn abs_and_sign(self: i128) -> (u128, bool) { - match core::internal::bounded_int::constrain::(self) { - Ok(lt0) => (upcast(core::internal::bounded_int::NegateHelper::negate(lt0)), true), - Err(ge0) => (upcast(ge0), false), - } - } -} diff --git a/corelib/src/internal.cairo b/corelib/src/internal.cairo deleted file mode 100644 index a049dcd1e5..0000000000 --- a/corelib/src/internal.cairo +++ /dev/null @@ -1,64 +0,0 @@ -pub extern fn revoke_ap_tracking() implicits() nopanic; - -/// Function to enforce that `Implicit` is used by a function calling it. -/// Note: This extern function is not mapped to a Sierra function, and all usages of it are removed -/// during compilation. -pub extern fn require_implicit() implicits(Implicit) nopanic; - -extern type index_enum_type; - -/// Function for marking the current state of execution. -/// Useful for debugging and panic tracking. -extern fn trace() nopanic; - -#[unstable( - feature: "bounded-int-utils", - note: "Improper usage of the functionalities in this module is likely to cause compiler crashes, use with caution.", -)] -pub mod bounded_int; - -mod num; - -/// Same as `Option`, except that the order of the variants is reversed. -/// This is used as the return type of some libfuncs for efficiency reasons. -#[must_use] -#[derive(Copy, Drop, Debug, PartialEq)] -pub enum OptionRev { - None, - Some: T, -} - -/// Wrapper type to ensure that a type `T` is dropped using a specific `Drop` impl. -pub struct DropWith> { - pub value: T, -} -impl DropWithDrop> of Drop>; - -/// Helper to have the same interface as `DropWith` while inferring the `Drop` implementation. -#[derive(Drop)] -pub struct InferDrop { - pub value: T, -} - -/// Wrapper type to ensure that a type `T` is destructed using a specific `Destruct` impl. -pub struct DestructWith> { - pub value: T, -} -impl DestructWithDestruct> of Destruct> { - fn destruct(self: DestructWith) nopanic { - DestructT::destruct(self.value) - } -} - -/// Helper to have the same interface as `DestructWith` while inferring the `Destruct` -/// implementation. -#[derive(Destruct)] -pub struct InferDestruct { - pub value: T, -} - -/// The return type for loops with an early return. -pub enum LoopResult { - Normal: N, - EarlyReturn: E, -} diff --git a/corelib/src/internal/bounded_int.cairo b/corelib/src/internal/bounded_int.cairo deleted file mode 100644 index d241c18fff..0000000000 --- a/corelib/src/internal/bounded_int.cairo +++ /dev/null @@ -1,347 +0,0 @@ -use crate::RangeCheck; - -pub(crate) extern type BoundedInt; - -impl BoundedIntCopy of Copy>; -impl BoundedIntDrop of Drop>; - -impl NumericLiteralBoundedInt< - const MIN: felt252, const MAX: felt252, -> of crate::integer::NumericLiteral>; - -/// Upcasts `FromType` to `ToType` - for types where conversion is always legal. -/// -/// If done for wrong types would cause a compiler panic at the Sierra stage. -pub extern const fn upcast(x: FromType) -> ToType nopanic; - -/// Downcasts `FromType` to `ToType` - for types where conversion may fail. -/// -/// If done for wrong types would cause a compiler panic at the Sierra stage. -pub extern const fn downcast( - x: FromType, -) -> Option implicits(RangeCheck) nopanic; - -impl BoundedIntIntoFelt252< - const MIN: felt252, const MAX: felt252, -> of Into, felt252> { - const fn into(self: BoundedInt) -> felt252 { - upcast(self) - } -} - -impl Felt252TryIntoBoundedInt< - const MIN: felt252, const MAX: felt252, -> of TryInto> { - const fn try_into(self: felt252) -> Option> { - // Using `downcast` is allowed, since `BoundedInt` itself is not `pub`, and only has a few - // specific `pub` instances, such as `u96`, `ConstZero` and `ConstOne`. - downcast(self) - } -} - -impl BoundedIntSerde = - crate::serde::into_felt252_based::SerdeImpl>; - -impl BoundedIntPartialEq< - const MIN: felt252, const MAX: felt252, -> of PartialEq> { - #[inline(always)] - fn eq(lhs: @BoundedInt, rhs: @BoundedInt) -> bool { - Into::<_, felt252>::into(*lhs) == (*rhs).into() - } -} - -impl BoundedIntDebug = - crate::fmt::into_felt252_based::DebugImpl>; - -/// A helper trait for adding two `BoundedInt` instances. -pub trait AddHelper { - type Result; -} -impl AddBI01BI01Helper of AddHelper, BoundedInt<0, 1>> { - type Result = BoundedInt<0, 2>; -} -impl AddBI02BI01Helper of AddHelper, BoundedInt<0, 1>> { - type Result = BoundedInt<0, 3>; -} -impl AddOneToU8Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 0xff>; -} -impl AddOneToU16Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 0xffff>; -} -impl AddOneToU32Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 0xffffffff>; -} -impl AddOneToU64Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 0xffffffffffffffff>; -} -impl AddOneToU128Helper of AddHelper< - BoundedInt<0, 0xfffffffffffffffffffffffffffffffe>, UnitInt<1>, -> { - type Result = BoundedInt<1, 0xffffffffffffffffffffffffffffffff>; -} -impl AddOneToI8Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<-0x7f, 0x7f>; -} -impl AddOneToI16Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<-0x7fff, 0x7fff>; -} -impl AddOneToI32Helper of AddHelper, UnitInt<1>> { - type Result = BoundedInt<-0x7fffffff, 0x7fffffff>; -} -impl AddOneToI64Helper of AddHelper< - BoundedInt<-0x8000000000000000, 0x7ffffffffffffffe>, UnitInt<1>, -> { - type Result = BoundedInt<-0x7fffffffffffffff, 0x7fffffffffffffff>; -} -impl AddOneToI128Helper of AddHelper< - BoundedInt<-0x80000000000000000000000000000000, 0x7ffffffffffffffffffffffffffffffe>, UnitInt<1>, -> { - type Result = - BoundedInt<-0x7fffffffffffffffffffffffffffffff, 0x7fffffffffffffffffffffffffffffff>; -} -extern fn bounded_int_add>( - lhs: Lhs, rhs: Rhs, -) -> H::Result nopanic; - -/// A helper trait for subtracting two `BoundedInt` instances. -pub trait SubHelper { - type Result; -} -impl SubOneToU8Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<0, 0xfe>; -} -impl SubOneToU16Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<0, 0xfffe>; -} -impl SubOneToU32Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<0, 0xfffffffe>; -} -impl SubOneToU64Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<0, 0xfffffffffffffffe>; -} -impl SubOneToU128Helper of SubHelper< - BoundedInt<1, 0xffffffffffffffffffffffffffffffff>, UnitInt<1>, -> { - type Result = BoundedInt<0, 0xfffffffffffffffffffffffffffffffe>; -} -impl SubOneToI8Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<-0x80, 0x7e>; -} -impl SubOneToI16Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<-0x8000, 0x7ffe>; -} -impl SubOneToI32Helper of SubHelper, UnitInt<1>> { - type Result = BoundedInt<-0x80000000, 0x7ffffffe>; -} -impl SubOneToI64Helper of SubHelper< - BoundedInt<-0x7fffffffffffffff, 0x7fffffffffffffff>, UnitInt<1>, -> { - type Result = BoundedInt<-0x8000000000000000, 0x7ffffffffffffffe>; -} -impl SubOneToI128Helper of SubHelper< - BoundedInt<-0x7fffffffffffffffffffffffffffffff, 0x7fffffffffffffffffffffffffffffff>, UnitInt<1>, -> { - type Result = - BoundedInt<-0x80000000000000000000000000000000, 0x7ffffffffffffffffffffffffffffffe>; -} -extern fn bounded_int_sub>( - lhs: Lhs, rhs: Rhs, -) -> H::Result nopanic; - -/// A helper trait for multiplying two `BoundedInt` instances. -pub trait MulHelper { - type Result; -} -impl NonZeroMulHelper< - Lhs, Rhs, impl H: MulHelper, -> of MulHelper, NonZero> { - type Result = NonZero; -} -extern fn bounded_int_mul>( - lhs: Lhs, rhs: Rhs, -) -> H::Result nopanic; - -/// A helper trait for dividing two `BoundedInt` instances. -pub trait DivRemHelper { - type DivT; - type RemT; -} -extern fn bounded_int_div_rem>( - lhs: Lhs, rhs: NonZero, -) -> (H::DivT, H::RemT) implicits(RangeCheck) nopanic; - -/// A helper trait for constraining a `BoundedInt` instance. -pub trait ConstrainHelper { - type LowT; - type HighT; -} -impl NonZeroConstrainHelper< - T, const BOUNDARY: felt252, impl H: ConstrainHelper, -> of ConstrainHelper, BOUNDARY> { - type LowT = NonZero; - type HighT = NonZero; -} -mod constrain0 { - pub impl Impl of super::ConstrainHelper { - type LowT = super::BoundedInt; - type HighT = super::BoundedInt<0, MAX>; - } -} -impl I8Constrain0 = constrain0::Impl; -impl I16Constrain0 = constrain0::Impl; -impl I32Constrain0 = constrain0::Impl; -impl I64Constrain0 = constrain0::Impl; -impl I128Constrain0 = - constrain0::Impl; - -extern fn bounded_int_constrain>( - value: T, -) -> Result implicits(RangeCheck) nopanic; - -/// A helper trait for trimming a `BoundedInt` instance's min value. -pub trait TrimMinHelper { - type Target; -} -/// A helper trait for trimming a `BoundedInt` instance's max value. -pub trait TrimMaxHelper { - type Target; -} -mod trim_impl { - pub impl Min of super::TrimMinHelper { - type Target = super::BoundedInt; - } - pub impl Max of super::TrimMaxHelper { - type Target = super::BoundedInt; - } -} -impl U8TrimBelow = trim_impl::Min; -impl U8TrimAbove = trim_impl::Max; -impl I8TrimBelow = trim_impl::Min; -impl I8TrimAbove = trim_impl::Max; -impl U16TrimBelow = trim_impl::Min; -impl U16TrimAbove = trim_impl::Max; -impl I16TrimBelow = trim_impl::Min; -impl I16TrimAbove = trim_impl::Max; -impl U32TrimBelow = trim_impl::Min; -impl U32TrimAbove = trim_impl::Max; -impl I32TrimBelow = trim_impl::Min; -impl I32TrimAbove = trim_impl::Max; -impl U64TrimBelow = trim_impl::Min; -impl U64TrimAbove = trim_impl::Max; -impl I64TrimBelow = trim_impl::Min; -impl I64TrimAbove = trim_impl::Max; -impl U128TrimBelow = trim_impl::Min; -impl U128TrimAbove = trim_impl::Max; -impl I128TrimBelow = - trim_impl::Min; -impl I128TrimAbove = - trim_impl::Max; - -extern fn bounded_int_trim_min>( - value: T, -) -> core::internal::OptionRev nopanic; -extern fn bounded_int_trim_max>( - value: T, -) -> core::internal::OptionRev nopanic; - -extern const fn bounded_int_is_zero( - value: T, -) -> crate::zeroable::IsZeroResult implicits() nopanic; - -/// Returns the negation of the given `felt252` value. -trait NegFelt252 { - /// The negation of the given `felt252` value. - const VALUE: felt252; -} - -/// Helper implementation for `NegFelt252`. -mod neg_felt252 { - pub impl Impl of super::NegFelt252 { - const VALUE: felt252 = OUTPUT; - } -} -impl NegFelt2520 = neg_felt252::Impl<0, 0>; -impl NegFelt2521 = neg_felt252::Impl<1, -1>; -impl NegFelt252Minus1 = neg_felt252::Impl<-1, 1>; -impl NegFelt2520x7e = neg_felt252::Impl<0x7e, -0x7e>; -impl NegFelt252Minus0x7e = neg_felt252::Impl<-0x7e, 0x7e>; -impl NegFelt2520x7f = neg_felt252::Impl<0x7f, -0x7f>; -impl NegFelt252Minus0x7f = neg_felt252::Impl<-0x7f, 0x7f>; -impl NegFelt2520x80 = neg_felt252::Impl<0x80, -0x80>; -impl NegFelt252Minus0x80 = neg_felt252::Impl<-0x80, 0x80>; -impl NegFelt2520x7ffe = neg_felt252::Impl<0x7ffe, -0x7ffe>; -impl NegFelt252Minus0x7ffe = neg_felt252::Impl<-0x7ffe, 0x7ffe>; -impl NegFelt2520x7fff = neg_felt252::Impl<0x7fff, -0x7fff>; -impl NegFelt252Minus0x7fff = neg_felt252::Impl<-0x7fff, 0x7fff>; -impl NegFelt2520x8000 = neg_felt252::Impl<0x8000, -0x8000>; -impl NegFelt252Minus0x8000 = neg_felt252::Impl<-0x8000, 0x8000>; -impl NegFelt2520x7ffffffe = neg_felt252::Impl<0x7ffffffe, -0x7ffffffe>; -impl NegFelt252Minus0x7ffffffe = neg_felt252::Impl<-0x7ffffffe, 0x7ffffffe>; -impl NegFelt2520x7fffffff = neg_felt252::Impl<0x7fffffff, -0x7fffffff>; -impl NegFelt252Minus0x7fffffff = neg_felt252::Impl<-0x7fffffff, 0x7fffffff>; -impl NegFelt2520x80000000 = neg_felt252::Impl<0x80000000, -0x80000000>; -impl NegFelt252Minus0x80000000 = neg_felt252::Impl<-0x80000000, 0x80000000>; -impl NegFelt2520x7ffffffffffffffe = neg_felt252::Impl<0x7ffffffffffffffe, -0x7ffffffffffffffe>; -impl NegFelt252Minus0x7ffffffffffffffe = neg_felt252::Impl<-0x7ffffffffffffffe, 0x7ffffffffffffffe>; -impl NegFelt2520x7fffffffffffffff = neg_felt252::Impl<0x7fffffffffffffff, -0x7fffffffffffffff>; -impl NegFelt252Minus0x7fffffffffffffff = neg_felt252::Impl<-0x7fffffffffffffff, 0x7fffffffffffffff>; -impl NegFelt2520x8000000000000000 = neg_felt252::Impl<0x8000000000000000, -0x8000000000000000>; -impl NegFelt252Minus0x8000000000000000 = neg_felt252::Impl<-0x8000000000000000, 0x8000000000000000>; -impl NegFelt2520x7ffffffffffffffffffffffffffffffe = - neg_felt252::Impl<0x7ffffffffffffffffffffffffffffffe, -0x7ffffffffffffffffffffffffffffffe>; -impl NegFelt252Minus0x7ffffffffffffffffffffffffffffffe = - neg_felt252::Impl<-0x7ffffffffffffffffffffffffffffffe, 0x7ffffffffffffffffffffffffffffffe>; -impl NegFelt2520x7fffffffffffffffffffffffffffffff = - neg_felt252::Impl<0x7fffffffffffffffffffffffffffffff, -0x7fffffffffffffffffffffffffffffff>; -impl NegFelt252Minus0x7fffffffffffffffffffffffffffffff = - neg_felt252::Impl<-0x7fffffffffffffffffffffffffffffff, 0x7fffffffffffffffffffffffffffffff>; -impl NegFelt2520x80000000000000000000000000000000 = - neg_felt252::Impl<0x80000000000000000000000000000000, -0x80000000000000000000000000000000>; -impl NegFelt252Minus0x80000000000000000000000000000000 = - neg_felt252::Impl<-0x80000000000000000000000000000000, 0x80000000000000000000000000000000>; - -pub type UnitInt = BoundedInt; - -impl MulMinus1< - const MIN: felt252, - const MAX: felt252, - impl NegMin: NegFelt252, - impl NegMax: NegFelt252, -> of MulHelper, UnitInt<-1>> { - type Result = BoundedInt; -} - -/// A helper trait for negating a `BoundedInt` instance. -pub trait NegateHelper { - /// The result of negating the given value. - type Result; - - /// Negates the given value. - fn negate(self: T) -> Self::Result; -} - -impl MulMinusOneNegateHelper>> of NegateHelper { - type Result = H::Result; - - fn negate(self: T) -> H::Result { - bounded_int_mul::<_, UnitInt<-1>>(self, -1) - } -} - -impl NonZeroMulMinusOneNegateHelper< - T, impl H: MulHelper>, -> of NegateHelper> { - type Result = NonZero; - - fn negate(self: NonZero) -> NonZero { - bounded_int_mul::<_, NonZero>>(self, -1) - } -} - -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_max as trim_max, bounded_int_trim_min as trim_min, -}; diff --git a/corelib/src/internal/num.cairo b/corelib/src/internal/num.cairo deleted file mode 100644 index 91e1b83a69..0000000000 --- a/corelib/src/internal/num.cairo +++ /dev/null @@ -1,161 +0,0 @@ -use crate::integer::SignedIntegerResult; -use crate::internal::OptionRev; -#[feature("bounded-int-utils")] -use crate::internal::bounded_int::{ - AddHelper, SubHelper, TrimMaxHelper, TrimMinHelper, UnitInt, add, sub, trim_max, trim_min, - upcast, -}; - -/// Returns `Ok(t + 1)`, or `Err(core::num::traits::Bounded::MIN)` if out of range. -/// -/// Designed to be equivalent to `*_overflowing_add(t, 1)`. -fn uint_inc< - T, - impl Bounded: crate::num::traits::Bounded, - impl Trim: TrimMaxHelper, - impl Add: AddHelper>, ->( - t: T, -) -> Result { - if let OptionRev::Some(trimmed) = trim_max(t) { - Ok(upcast(add::<_, _, Add>(trimmed, 1))) - } else { - Err(Bounded::MIN) - } -} - -/// Returns `Ok(t - 1)`, or `Err(core::num::traits::Bounded::MAX)` if out of range. -/// -/// Designed to be equivalent to `*_overflowing_sub(t, 1)`. -fn uint_dec< - T, - impl Bounded: crate::num::traits::Bounded, - impl Trim: TrimMinHelper, - impl Sub: SubHelper>, ->( - t: T, -) -> Result { - if let OptionRev::Some(trimmed) = trim_min(t) { - Ok(upcast(sub::<_, _, Sub>(trimmed, 1))) - } else { - Err(Bounded::MAX) - } -} - -fn u8_inc(value: u8) -> Result { - uint_inc(value) -} - -fn u8_dec(value: u8) -> Result { - uint_dec(value) -} - -fn u16_inc(value: u16) -> Result { - uint_inc(value) -} - -fn u16_dec(value: u16) -> Result { - uint_dec(value) -} - -fn u32_inc(value: u32) -> Result { - uint_inc(value) -} - -fn u32_dec(value: u32) -> Result { - uint_dec(value) -} - -fn u64_inc(value: u64) -> Result { - uint_inc(value) -} - -fn u64_dec(value: u64) -> Result { - uint_dec(value) -} - -fn u128_inc(value: u128) -> Result { - uint_inc(value) -} - -fn u128_dec(value: u128) -> Result { - uint_dec(value) -} - -/// Returns `SignedIntegerResult::InRange(t + 1)`, or -/// `SignedIntegerResult::Overflow(core::num::traits::Bounded::MIN)` if out of range. -/// -/// Designed to be equivalent to `*_overflowing_add_impl(t, 1)`. -fn sint_inc< - T, - impl Bounded: crate::num::traits::Bounded, - impl Trim: TrimMaxHelper, - impl Add: AddHelper>, ->( - t: T, -) -> SignedIntegerResult { - if let OptionRev::Some(trimmed) = trim_max(t) { - SignedIntegerResult::InRange(upcast(add::<_, _, Add>(trimmed, 1))) - } else { - SignedIntegerResult::Overflow(Bounded::MIN) - } -} - -/// Returns `SignedIntegerResult::InRange(t - 1)`, or -/// `SignedIntegerResult::Underflow(core::num::traits::Bounded::MAX)` if out of range. -/// -/// Designed to be equivalent to `*_overflowing_sub_impl(t, 1)`. -fn sint_dec< - T, - impl Bounded: crate::num::traits::Bounded, - impl Trim: TrimMinHelper, - impl Sub: SubHelper>, ->( - t: T, -) -> SignedIntegerResult { - if let OptionRev::Some(trimmed) = trim_min(t) { - SignedIntegerResult::InRange(upcast(sub::<_, _, Sub>(trimmed, 1))) - } else { - SignedIntegerResult::Underflow(Bounded::MAX) - } -} - -fn i8_inc(value: i8) -> SignedIntegerResult { - sint_inc(value) -} - -fn i8_dec(value: i8) -> SignedIntegerResult { - sint_dec(value) -} - -fn i16_inc(value: i16) -> SignedIntegerResult { - sint_inc(value) -} - -fn i16_dec(value: i16) -> SignedIntegerResult { - sint_dec(value) -} - -fn i32_inc(value: i32) -> SignedIntegerResult { - sint_inc(value) -} - -fn i32_dec(value: i32) -> SignedIntegerResult { - sint_dec(value) -} - -fn i64_inc(value: i64) -> SignedIntegerResult { - sint_inc(value) -} - -fn i64_dec(value: i64) -> SignedIntegerResult { - sint_dec(value) -} - -fn i128_inc(value: i128) -> SignedIntegerResult { - sint_inc(value) -} - -fn i128_dec(value: i128) -> SignedIntegerResult { - sint_dec(value) -} diff --git a/corelib/src/iter.cairo b/corelib/src/iter.cairo deleted file mode 100644 index 28fd693f26..0000000000 --- a/corelib/src/iter.cairo +++ /dev/null @@ -1,236 +0,0 @@ -//! Composable external iteration. -//! -//! If you've found yourself with a collection of some kind, and needed to -//! perform an operation on the elements of said collection, you'll quickly run -//! into 'iterators'. Iterators are heavily used in idiomatic code, so -//! it's worth becoming familiar with them. -//! -//! Before explaining more, let's talk about how this module is structured: -//! -//! # Organization -//! -//! This module is largely organized by type: -//! -//! * [Traits] are the core portion: these traits define what kind of iterators -//! exist and what you can do with them. The methods of these traits are worth -//! putting some extra study time into. -//! * [Functions] provide some helpful ways to create some basic iterators. -//! * [Structs] are often the return types of the various methods on this -//! module's traits. You'll usually want to look at the method that creates -//! the `struct`, rather than the `struct` itself. For more detail about why, -//! see '[Implementing Iterator](#implementing-iterator)'. -//! -//! [Traits]: #traits -//! [Functions]: #functions -//! [Structs]: #structs -//! -//! That's it! Let's dig into iterators. -//! -//! # Iterator -//! -//! The heart and soul of this module is the [`Iterator`] trait. The core of -//! [`Iterator`] looks like this: -//! -//! ``` -//! trait Iterator { -//! type Item; -//! fn next(ref self) -> Option; -//! } -//! ``` -//! -//! An iterator has a method, [`next`], which when called, returns an -//! [Option]\. Calling [`next`] will return [`Some(Item)`] as long as -//! there are elements, and once they've all been exhausted, will return `None` to -//! indicate that iteration is finished. -//! -//! [`Iterator`]'s full definition includes a number of other methods as well, -//! but they are default methods, built on top of [`next`], and so you get -//! them for free. -//! -//! Iterators are also composable, and it's common to chain them together to do -//! more complex forms of processing. See the [Adapters](#adapters) section -//! below for more details. -//! -//! [`Some(Item)`]: Some -//! [`next`]: Iterator::next -//! -//! # Forms of iteration -//! -//! There is currently only one common method which can create iterators from a collection: -//! -//! * `into_iter()`, which iterates over `T`. -//! -//! # Implementing Iterator -//! -//! Creating an iterator of your own involves two steps: creating a `struct` to -//! hold the iterator's state, and then implementing [`Iterator`] for that `struct`. -//! This is why there are so many `struct`s in this module: there is one for -//! each iterator and iterator adapter. -//! -//! Let's make an iterator named `Counter` which counts from `1` to `5`: -//! -//! ``` -//! // First, the struct: -//! -//! /// An iterator which counts from one to five -//! #[derive(Drop)] -//! struct Counter { -//! count: usize, -//! } -//! -//! // we want our count to start at one, so let's add a new() method to help. -//! // This isn't strictly necessary, but is convenient. Note that we start -//! // `count` at zero, we'll see why in `next()`'s implementation below. -//! #[generate_trait] -//! impl CounterImpl of CounterTrait { -//! fn new() -> Counter { -//! Counter { count: 0 } -//! } -//! } -//! -//! // Then, we implement `Iterator` for our `Counter`: -//! -//! impl CounterIter of core::iter::Iterator { -//! // we will be counting with usize -//! type Item = usize; -//! -//! // next() is the only required method -//! fn next(ref self: Counter) -> Option { -//! // Increment our count. This is why we started at zero. -//! self.count += 1; -//! -//! // Check to see if we've finished counting or not. -//! if self.count < 6 { -//! Some(self.count) -//! } else { -//! None -//! } -//! } -//! } -//! -//! // And now we can use it! -//! -//! let mut counter = CounterTrait::new(); -//! -//! assert!(counter.next() == Some(1)); -//! assert!(counter.next() == Some(2)); -//! assert!(counter.next() == Some(3)); -//! assert!(counter.next() == Some(4)); -//! assert!(counter.next() == Some(5)); -//! assert!(counter.next() == None); -//! ``` -//! -//! Calling [`next`] this way gets repetitive. Cairo has a construct which can -//! call [`next`] on your iterator, until it reaches `None`. Let's go over that -//! next. -//! -//! # `for` loops and `IntoIterator` -//! -//! Cairo's `for` loop syntax is actually sugar for iterators. Here's a basic -//! example of `for`: -//! -//! ``` -//! let values = array![1, 2, 3, 4, 5]; -//! -//! for x in values { -//! println!("{x}"); -//! } -//! ``` -//! -//! This will print the numbers one through five, each on their own line. But -//! you'll notice something here: we never called anything on our array to -//! produce an iterator. What gives? -//! -//! There's a trait in the core library for converting something into an -//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter`], -//! which converts the thing implementing [`IntoIterator`] into an iterator. -//! Let's take a look at that `for` loop again, and what the compiler converts -//! it into: -//! -//! [`into_iter`]: core::iter::IntoIterator::into_iter -//! -//! ``` -//! let values = array![1, 2, 3, 4, 5]; -//! -//! for x in values { -//! println!("{x}"); -//! } -//! ``` -//! -//! Cairo de-sugars this into: -//! -//! ``` -//! let values = array![1, 2, 3, 4, 5]; -//! { -//! let mut iter = IntoIterator::into_iter(values); -//! let result = loop { -//! let mut next = 0; -//! match iter.next() { -//! Some(val) => next = val, -//! None => { -//! break; -//! }, -//! }; -//! let x = next; -//! let () = { println!("{x}"); }; -//! }; -//! result -//! } -//! ``` -//! -//! First, we call `into_iter()` on the value. Then, we match on the iterator -//! that returns, calling [`next`] over and over until we see a `None`. At -//! that point, we `break` out of the loop, and we're done iterating. -//! -//! There's one more subtle bit here: the core library contains an -//! interesting implementation of [`IntoIterator`]: -//! -//! ```ignore (only-for-syntax-highlight) -//! impl IteratorIntoIterator> of IntoIterator -//! ``` -//! -//! In other words, all [`Iterator`]s implement [`IntoIterator`], by just -//! returning themselves. This means two things: -//! -//! 1. If you're writing an [`Iterator`], you can use it with a `for` loop. -//! 2. If you're creating a collection, implementing [`IntoIterator`] for it -//! will allow your collection to be used with the `for` loop. -//! -//! # Adapters -//! -//! Functions which take an [`Iterator`] and return another [`Iterator`] are -//! often called 'iterator adapters', as they're a form of the 'adapter -//! pattern'. -//! -//! Common iterators adapters include [`map`], [`enumerate`] and [`zip`]. -//! -//! [`map`]: Iterator::map -//! [`enumerate`]: Iterator::enumerate -//! [`zip`]: Iterator::zip -//! -//! # Laziness -//! -//! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that -//! just creating an iterator doesn't _do_ a whole lot. Nothing really happens -//! until you call [`next`]. This is sometimes a source of confusion when -//! creating an iterator solely for its side effects. For example, the [`map`] -//! method calls a closure on each element it iterates over: -//! -//! ``` -//! let v = array![1, 2, 3, 4, 5]; -//! let _ = v.into_iter().map(|x| println!("{x}")); -//! ``` -//! -//! This will not print any values, as we only created an iterator, rather than -//! using it. The compiler will warn us about this kind of behavior: -//! -//! ```text -//! Unhandled `#[must_use]` type -//! ``` -//! -//! [`map`]: Iterator::map -mod adapters; -mod traits; -pub use adapters::PeekableTrait; -pub use adapters::zip::zip; -pub use traits::{Extend, FromIterator, IntoIterator, Iterator, Product, Sum}; diff --git a/corelib/src/iter/adapters.cairo b/corelib/src/iter/adapters.cairo deleted file mode 100644 index 662d1ebc01..0000000000 --- a/corelib/src/iter/adapters.cairo +++ /dev/null @@ -1,32 +0,0 @@ -mod map; -pub use map::Map; -#[allow(unused_imports)] -pub(crate) use map::mapped_iterator; - -mod enumerate; -pub use enumerate::Enumerate; -#[allow(unused_imports)] -pub(crate) use enumerate::enumerated_iterator; - -pub(crate) mod zip; -pub use zip::Zip; - -mod peekable; -#[allow(unused_imports)] -pub(crate) use peekable::peekable_iterator; -pub use peekable::{Peekable, PeekableTrait}; - -mod filter; -pub use filter::Filter; -#[allow(unused_imports)] -pub(crate) use filter::filter_iterator; - -mod take; -pub use take::Take; -#[allow(unused_imports)] -pub(crate) use take::take_iterator; - -mod chain; -pub use chain::Chain; -#[allow(unused_imports)] -pub(crate) use chain::chained_iterator; diff --git a/corelib/src/iter/adapters/chain.cairo b/corelib/src/iter/adapters/chain.cairo deleted file mode 100644 index 3055b5eec3..0000000000 --- a/corelib/src/iter/adapters/chain.cairo +++ /dev/null @@ -1,46 +0,0 @@ -/// An iterator that links two iterators together, in a chain. -/// -/// This `struct` is created by [`Iterator::chain`]. See the -/// documentation for more. -#[derive(Drop)] -pub enum Chain { - /// First iterator processing is not done yet. - Both: (A, B), - /// First iterator processing is done, processing the second iterator. - Second: B, -} - -#[inline] -pub fn chained_iterator(a: A, b: B) -> Chain { - Chain::Both((a, b)) -} - -impl ChainIterator< - A, - B, - impl IterA: Iterator, - +Iterator[Item: IterA::Item], - +Destruct, - +Destruct, - +Destruct, -> of Iterator> { - type Item = IterA::Item; - - fn next(ref self: Chain) -> Option { - let mut b = match self { - Chain::Second(b) => b, - Chain::Both(( - mut a, b, - )) => { - if let Some(value) = a.next() { - self = Chain::Both((a, b)); - return Option::Some(value); - } - b - }, - }; - let next_val = b.next(); - self = Chain::Second(b); - next_val - } -} diff --git a/corelib/src/iter/adapters/enumerate.cairo b/corelib/src/iter/adapters/enumerate.cairo deleted file mode 100644 index 57ddaddc07..0000000000 --- a/corelib/src/iter/adapters/enumerate.cairo +++ /dev/null @@ -1,41 +0,0 @@ -/// An iterator that yields the current count and the element during iteration. -/// -/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`enumerate`]: Iterator::enumerate -/// [`Iterator`]: core::iter::Iterator -#[must_use] -#[derive(Drop, Clone, Debug)] -pub struct Enumerate { - iter: I, - count: usize, -} - -pub fn enumerated_iterator(iter: I) -> Enumerate { - Enumerate { iter, count: 0 } -} - -impl EnumerateIterator< - I, T, +Iterator[Item: T], +Destruct, +Destruct, -> of Iterator> { - type Item = (usize, T); - - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// `Bounded::::MAX` elements will always panic. - /// - /// [`Bounded`]: core::num::traits::Bounded - /// - /// # Panics - /// - /// Will panic if the index of the element overflows a `usize`. - #[inline] - fn next(ref self: Enumerate) -> Option { - let a = self.iter.next()?; - let i = self.count; - self.count += 1; - Some((i, a)) - } -} diff --git a/corelib/src/iter/adapters/filter.cairo b/corelib/src/iter/adapters/filter.cairo deleted file mode 100644 index 896fad3c8f..0000000000 --- a/corelib/src/iter/adapters/filter.cairo +++ /dev/null @@ -1,31 +0,0 @@ -/// An iterator that filters the elements of `iter` with `predicate`. -/// -/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter`]: Iterator::filter -#[must_use] -#[derive(Drop, Clone)] -pub struct Filter { - pub iter: I, - pub predicate: P, -} - -pub fn filter_iterator(iter: I, predicate: P) -> Filter { - Filter { iter, predicate } -} - -impl FilterIterator< - I, - P, - impl TIter: Iterator, - +core::ops::Fn[Output: bool], - +Destruct, - +Destruct

, - +Destruct, - +Destruct, - >( - ref self: T, predicate: P, - ) -> bool { - match Self::next(ref self) { - None => false, - Some(x) => predicate(x) || Self::any(ref self, predicate), - } - } - - /// Tests if every element of the iterator matches a predicate. - /// - /// `all()` takes a closure that returns `true` or `false`. It applies this closure to each - /// element of the iterator, and if all of them return `true`, then so does `all()`. If any - /// of them return `false`, it returns `false`. - /// - /// `all()` is short-circuiting; in other words, it will stop processing as soon as it finds a - /// `false`, given that no matter what else happens, the result will also be `false`. - /// - /// An empty iterator returns `true`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(array![1, 2, 3].into_iter().all(|x| x > 0)); - /// - /// assert!(!array![1, 2, 3].into_iter().all(|x| x > 2)); - /// ``` - fn all< - P, - +core::ops::Fn[Output: bool], - +Destruct

, - +Destruct, - +Destruct, - >( - ref self: T, predicate: P, - ) -> bool { - match Self::next(ref self) { - None => true, - Some(x) => predicate(x) && Self::all(ref self, predicate), - } - } - - /// Searches for an element of an iterator that satisfies a predicate. - /// - /// `find()` takes a closure that returns `true` or `false`. It applies - /// this closure to each element of the iterator as a snapshot, and if - /// any of them return `true`, then `find()` returns [`Some(element)`]. - /// If they all return `false`, it returns [`None`]. - /// - /// `find()` is short-circuiting; in other words, it will stop processing - /// as soon as the closure returns `true`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// - /// assert_eq!(iter.find(|x| *x == 2), Option::Some(2)); - /// - /// assert_eq!(iter.find(|x| *x == 5), Option::None); - /// ``` - /// - /// Stopping at the first `true`: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// - /// assert_eq!(iter.find(|x| *x == 2), Option::Some(2)); - /// - /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Option::Some(3)); - /// ``` - /// - /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. - fn find< - P, - +core::ops::Fn[Output: bool], - +Destruct

, - +Destruct, - +Destruct, - >( - ref self: T, predicate: P, - ) -> Option< - Self::Item, - > { - match Self::next(ref self) { - Option::None => Option::None, - Option::Some(x) => if predicate(@x) { - Option::Some(x) - } else { - Self::find(ref self, predicate) - }, - } - } - - /// Creates an iterator that uses a closure to determine if an element - /// should be yielded. The closure takes each element as a snapshot. - /// - /// Given an element the closure must return `true` or `false`. The returned - /// iterator will yield only the elements for which the closure returns - /// `true`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let a = array![0_u32, 1, 2]; - /// - /// let mut iter = a.into_iter().filter(|x| *x > 0); - /// - /// assert_eq!(iter.next(), Option::Some(1)); - /// assert_eq!(iter.next(), Option::Some(2)); - /// assert_eq!(iter.next(), Option::None); - /// ``` - /// - /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`. - #[inline] - fn filter< - P, - +core::ops::Fn[Output: bool], - +Destruct

, - +Destruct, - +Destruct, - >( - self: T, predicate: P, - ) -> Filter { - filter_iterator(self, predicate) - } - - /// 'Zips up' two iterators into a single iterator of pairs. - /// - /// `zip()` returns a new iterator that will iterate over two other - /// iterators, returning a tuple where the first element comes from the - /// first iterator, and the second element comes from the second iterator. - /// - /// In other words, it zips two iterators together, into a single one. - /// - /// If either iterator returns [`None`], [`next`] from the zipped iterator - /// will return [`None`]. - /// If the zipped iterator has no more elements to return then each further attempt to advance - /// it will first try to advance the first iterator at most one time and if it still yields an - /// item try to advance the second iterator at most one time. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter().zip(array![4, 5, 6].into_iter()); - /// - /// assert_eq!(iter.next(), Some((1, 4))); - /// assert_eq!(iter.next(), Some((2, 5))); - /// assert_eq!(iter.next(), Some((3, 6))); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// Since the argument to `zip()` uses [`IntoIterator`], we can pass - /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter().zip(array![4, 5, 6]); - /// - /// assert_eq!(iter.next(), Some((1, 4))); - /// assert_eq!(iter.next(), Some((2, 5))); - /// assert_eq!(iter.next(), Some((3, 6))); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// [`enumerate`]: Iterator::enumerate - /// [`next`]: Iterator::next - #[inline] - fn zip, +Destruct>( - self: T, other: U, - ) -> Zip { - zipped_iterator(self, other.into_iter()) - } - - /// Transforms an iterator into a collection. - /// - /// `collect()` can take anything iterable, and turn it into a relevant - /// collection. This is one of the more powerful methods in the core - /// library, used in a variety of contexts. - /// - /// The most basic pattern in which `collect()` is used is to turn one - /// collection into another. You take a collection, call [`iter`] on it, - /// do a bunch of transformations, and then `collect()` at the end. - /// - /// `collect()` can also create instances of types that are not typical - /// collections. - /// - /// Because `collect()` is so general, it can cause problems with type - /// inference. As such, `collect()` is one of the few times you'll see - /// the syntax affectionately known as the 'turbofish': `::<>`. This - /// helps the inference algorithm understand specifically which collection - /// you're trying to collect into. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let doubled: Array = array![1, 2, 3].into_iter().map(|x| x * 2).collect(); - /// - /// assert_eq!(array![2, 4, 6], doubled); - /// ``` - /// - /// Note that we needed the `: Array` on the left-hand side. - /// - /// Using the 'turbofish' instead of annotating `doubled`: - /// - /// ``` - /// let doubled = array![1, 2, 3].into_iter().map(|x| x * 2).collect::>(); - /// - /// assert_eq!(array![2, 4, 6], doubled); - /// ``` - /// - /// Because `collect()` only cares about what you're collecting into, you can - /// still use a partial type hint, `_`, with the turbofish: - /// - /// ``` - /// let doubled = array![1, 2, 3].into_iter().map(|x| x * 2).collect::>(); - /// - /// assert_eq!(array![2, 4, 6], doubled); - /// ``` - #[inline] - #[must_use] - fn collect< - B, - impl IntoIter: IntoIterator, - impl ItemEqual: TypeEqual, - +Destruct, - +FromIterator, - +Destruct, - >( - self: T, - ) -> B { - FromIterator::::from_iter::(self) - } - - /// Creates an iterator that can use the [`peek`] method to look at the next element of the - /// iterator. See its documentation for more information. - /// - /// Note that the underlying iterator is still advanced when [`peek`] is called for the first - /// time: In order to retrieve the next element, [`next`] is called on the underlying iterator, - /// hence any side effects (i.e. anything other than fetching the next value) of the [`next`] - /// method will occur. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = (1..4_u8).into_iter().peekable(); - /// - /// // peek() lets us see one step into the future - /// assert_eq!(iter.peek(), Option::Some(1)); - /// assert_eq!(iter.next(), Option::Some(1)); - /// - /// assert_eq!(iter.next(), Option::Some(2)); - /// - /// // we can peek() multiple times, the iterator won't advance - /// assert_eq!(iter.peek(), Option::Some(3)); - /// assert_eq!(iter.peek(), Option::Some(3)); - /// - /// assert_eq!(iter.next(), Option::Some(3)); - /// - /// // after the iterator is finished, so is peek() - /// assert_eq!(iter.peek(), Option::None); - /// assert_eq!(iter.next(), Option::None); - /// ``` - #[inline] - #[must_use] - fn peekable(self: T) -> Peekable { - peekable_iterator(self) - } - - /// Creates an iterator that yields the first `n` elements, or fewer - /// if the underlying iterator ends sooner. - /// - /// `take(n)` yields elements until `n` elements are yielded or the end of - /// the iterator is reached (whichever happens first). - /// The returned iterator is a prefix of length `n` if the original iterator - /// contains at least `n` elements, otherwise it contains all of the - /// (fewer than `n`) elements of the original iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter().take(2); - /// - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// If fewer than `n` elements are available, - /// `take` will limit itself to the size of the underlying iterator: - /// - /// ``` - /// let mut iter = array![1, 2].into_iter().take(5); - /// assert_eq!(iter.next(), Some(1)); - /// assert_eq!(iter.next(), Some(2)); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[must_use] - fn take(self: T, n: usize) -> Take { - take_iterator(self, n) - } - - /// Sums the elements of an iterator. - /// - /// Takes each element, adds them together, and returns the result. - /// - /// An empty iterator returns the zero value of the type. - /// - /// `sum()` can be used to sum any type implementing [`Sum`][`core::iter::Sum`], - /// including [`Option`][`Option::sum`] and [`Result`][`Result::sum`]. - /// - /// # Panics - /// - /// When calling `sum()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows. - /// - /// # Examples - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// let sum: usize = iter.sum(); - /// - /// assert_eq!(sum, 6); - /// ``` - fn sum<+Destruct, +Destruct, +Sum>( - self: T, - ) -> Self::Item { - Sum::::sum::(self) - } - - /// Iterates over the entire iterator, multiplying all the elements - /// - /// An empty iterator returns the one value of the type. - /// - /// # Panics - /// - /// When calling `product()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows. - /// - /// # Examples - /// - /// ``` - /// fn factorial(n: u32) -> u32 { - /// (1..=n).into_iter().product() - /// } - /// assert_eq!(factorial(0), 1); - /// assert_eq!(factorial(1), 1); - /// assert_eq!(factorial(5), 120); - /// ``` - fn product<+Destruct, +Destruct, +Product>( - self: T, - ) -> Self::Item { - Product::::product::(self) - } - - /// Takes two iterators and creates a new iterator over both in sequence. - /// - /// `chain()` will return a new iterator that will first iterate over - /// values from the first iterator and then over values from the second - /// iterator. - /// - /// In other words, it links two iterators together, in a chain. 🔗 - /// - /// Arguments do not have to be of the same type as long as the underlying iterated - /// over items are. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use core::ops::Range; - /// - /// let a: Array = array![7, 8, 9]; - /// let b: Range = 0..5; - /// - /// let mut iter = a.into_iter().chain(b.into_iter()); - /// - /// assert_eq!(iter.next(), Option::Some(7)); - /// assert_eq!(iter.next(), Option::Some(8)); - /// assert_eq!(iter.next(), Option::Some(9)); - /// assert_eq!(iter.next(), Option::Some(0)); - /// assert_eq!(iter.next(), Option::Some(1)); - /// assert_eq!(iter.next(), Option::Some(2)); - /// assert_eq!(iter.next(), Option::Some(3)); - /// assert_eq!(iter.next(), Option::Some(4)); - /// assert_eq!(iter.next(), Option::None); - /// ``` - /// - /// Since the argument to `chain()` uses [`IntoIterator`], we can pass - /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example, arrays implement - /// [`IntoIterator`], and so can be passed to `chain()` directly: - /// - /// ``` - /// let a = array![1, 2, 3]; - /// let b = array![4, 5, 6]; - /// - /// let mut iter = a.into_iter().chain(b); - /// - /// assert_eq!(iter.next(), Option::Some(1)); - /// assert_eq!(iter.next(), Option::Some(2)); - /// assert_eq!(iter.next(), Option::Some(3)); - /// assert_eq!(iter.next(), Option::Some(4)); - /// assert_eq!(iter.next(), Option::Some(5)); - /// assert_eq!(iter.next(), Option::Some(6)); - /// assert_eq!(iter.next(), Option::None); - /// ``` - fn chain< - U, - impl IntoIterU: IntoIterator, - +TypeEqual, - +Destruct, - >( - self: T, other: U, - ) -> Chain { - chained_iterator(self, other.into_iter()) - } -} diff --git a/corelib/src/keccak.cairo b/corelib/src/keccak.cairo deleted file mode 100644 index 9a2fa4fa8d..0000000000 --- a/corelib/src/keccak.cairo +++ /dev/null @@ -1,357 +0,0 @@ -//! Keccak-256 cryptographic hash function implementation. -//! -//! # Main Functions -//! -//! - [`keccak_u256s_le_inputs`] - Hash multiple `u256` values in little-endian format -//! - [`keccak_u256s_be_inputs`] - Hash multiple `u256` values in big-endian format -//! - [`cairo_keccak`] - Hash u64 words with a final partial word. Closest to the syscall input. -//! - [`compute_keccak_byte_array`] - Hash a `ByteArray` directly -//! -//! # Examples -//! -//! ``` -//! use core::keccak::*; -//! -//! // Hash u256 values -//! let input = array![1_u256, 2_u256].span(); -//! assert!(keccak_u256s_le_inputs(input) == -//! 0x234a9e12e9b063b60f7e3289ee9b86a731de8e7e41bd4987f10982d6a753444d); -//! assert!(keccak_u256s_be_inputs(input) == -//! 0xe0c2a7d2cc99d544061ac0ccbb083ac8976e54eed878fb1854dfe7b6ce7b0be9); -//! -//! // Hash a `Bytearray` -//! let text: ByteArray = "Hello, Keccak!"; -//! assert!(compute_keccak_byte_array(@text) == -//! 0x85c9aab73219c1e95c5b5966a4ecc8db4418c3500072a830cfb5a2d13d2c2249); -//! ``` - -use starknet::SyscallResultTrait; -use crate::array::{ArrayTrait, Span, SpanTrait}; -#[feature("byte-span")] -use crate::byte_array::ToByteSpanTrait; -#[feature("bounded-int-utils")] -use crate::internal::bounded_int::upcast; -use crate::num::traits::Split; - - -const KECCAK_FULL_RATE_IN_U64S: NonZero = 17; - -fn keccak_add_u256_le(ref keccak_input: Array, v: u256) { - let (high, low) = v.low.split(); - keccak_input.append(low); - keccak_input.append(high); - let (high, low) = v.high.split(); - keccak_input.append(low); - keccak_input.append(high); -} - -/// Computes the Keccak-256 hash of multiple `u256` values in little-endian format. -/// -/// # Arguments -/// -/// * `input` - A span of little-endian `u256` values to be hashed -/// -/// # Returns -/// -/// The 32-byte Keccak-256 hash as a little-endian `u256` -/// -/// # Examples -/// -/// ``` -/// use core::keccak::keccak_u256s_le_inputs; -/// -/// let input: Span = array![0, 1, 2].span(); -/// assert!(keccak_u256s_le_inputs(input) == -/// 0xf005473605efc7d8ff67d9f23fe2e4a4f23454c12b49b38822ed362e0a92a0a6); -/// ``` -pub fn keccak_u256s_le_inputs(mut input: Span) -> u256 { - let mut keccak_input: Array = Default::default(); - - loop { - match input.pop_front() { - Some(v) => { keccak_add_u256_le(ref keccak_input, *v); }, - None => { break (); }, - } - } - - add_padding(ref keccak_input, 0, 0); - starknet::syscalls::keccak_syscall(keccak_input.span()).unwrap_syscall() -} - -fn keccak_add_u256_be(ref keccak_input: Array, v: u256) { - let (high, low) = crate::integer::u128_byte_reverse(v.high).split(); - keccak_input.append(low); - keccak_input.append(high); - let (high, low) = crate::integer::u128_byte_reverse(v.low).split(); - keccak_input.append(low); - keccak_input.append(high); -} - -/// Computes the Keccak-256 hash of multiple `u256` values in big-endian format. -/// -/// # Arguments -/// -/// * `input` - A span of big-endian `u256` values to be hashed -/// -/// # Returns -/// -/// The 32-byte Keccak-256 hash as a little-endian `u256` -/// -/// # Examples -/// -/// ``` -/// use core::keccak::keccak_u256s_be_inputs; -/// -/// let input = array![0x1234_u256, 0x5678_u256].span(); -/// let hash = assert!(keccak_u256s_be_inputs(input) == -/// 0xfa31cb2326ed629f79d2da5beb78e2bd8ac7a1b8b86cae09eeb6a89a908b12a); -/// ``` -pub fn keccak_u256s_be_inputs(mut input: Span) -> u256 { - let mut keccak_input: Array = Default::default(); - - loop { - match input.pop_front() { - Some(v) => { keccak_add_u256_be(ref keccak_input, *v); }, - None => { break (); }, - } - } - - add_padding(ref keccak_input, 0, 0); - starknet::syscalls::keccak_syscall(keccak_input.span()).unwrap_syscall() -} - -/// Computes the Keccak-256 hash of a byte sequence with custom padding. -/// -/// This function allows hashing arbitrary byte sequences by providing the input as -/// 64-bit words in little-endian format and a final partial word. -/// -/// # Arguments -/// -/// * `input` - Array of complete 64-bit words in little-endian format -/// * `last_input_word` - Final partial word (if any) -/// * `last_input_num_bytes` - Number of valid bytes in the final word (0-7) -/// -/// # Returns -/// -/// The 32-byte Keccak-256 hash as a little-endian `u256` -/// -/// # Panics -/// -/// Panics if `last_input_num_bytes` is greater than 7. -/// -/// # Examples -/// -/// ``` -/// use core::keccak::cairo_keccak; -/// -/// // Hash "Hello world!" by splitting into 64-bit words in little-endian -/// let mut input = array![0x6f77206f6c6c6548]; // a full 8-byte word -/// let hash = cairo_keccak(ref input, 0x21646c72, 4); // 4 bytes of the last word -/// assert!(hash == 0xabea1f2503529a21734e2077c8b584d7bee3f45550c2d2f12a198ea908e1d0ec); -/// ``` -pub fn cairo_keccak( - ref input: Array, last_input_word: u64, last_input_num_bytes: usize, -) -> u256 { - add_padding(ref input, last_input_word, last_input_num_bytes); - starknet::syscalls::keccak_syscall(input.span()).unwrap_syscall() -} - -/// Adds Keccak-256 padding according to the "1 0* 1" rule. -/// -/// # Arguments -/// -/// * `input` - The buffer to pad -/// * `last_input_word` - Final partial word to include before padding -/// * `last_input_num_bytes` - Number of valid bytes in the final word (0-7) -/// -/// # Panics -/// -/// Panics if `last_input_num_bytes` is greater than 7. -fn add_padding(ref input: Array, last_input_word: u64, last_input_num_bytes: usize) { - // `last_block_num_full_words` is in range [0, KECCAK_FULL_RATE_IN_U64S - 1] - let (_, last_block_num_full_words) = crate::integer::u32_safe_divmod( - input.len(), KECCAK_FULL_RATE_IN_U64S, - ); - - // The first word to append would be of the form - // 0x1<`last_input_num_bytes` LSB bytes of `last_input_word`>. - // For example, for `last_input_num_bytes == 4`: - // 0x1000000 + (last_input_word & 0xffffff) - let first_word_to_append = if last_input_num_bytes == 0 { - // This case is handled separately to avoid unnecessary computations. - 1 - } else { - let first_padding_byte_part: NonZero = if last_input_num_bytes == 1 { - 0x100 - } else if last_input_num_bytes == 2 { - 0x10000 - } else if last_input_num_bytes == 3 { - 0x1000000 - } else if last_input_num_bytes == 4 { - 0x100000000 - } else if last_input_num_bytes == 5 { - 0x10000000000 - } else if last_input_num_bytes == 6 { - 0x1000000000000 - } else if last_input_num_bytes == 7 { - 0x100000000000000 - } else { - crate::panic_with_felt252('Keccak last input word >7b') - }; - let (_, r) = crate::integer::u64_safe_divmod(last_input_word, first_padding_byte_part); - first_padding_byte_part.into() + r - }; - - const LAST_FULL_COUNT: usize = KECCAK_FULL_RATE_IN_U64S.into() - 1; - if last_block_num_full_words == LAST_FULL_COUNT { - input.append(0x8000000000000000 + first_word_to_append); - return; - } - - // last_block_num_full_words < LAST_FULL_COUNT - input.append(first_word_to_append); - finalize_padding(ref input, LAST_FULL_COUNT - last_block_num_full_words); -} - -/// Finalizes the padding by appending "0* 1". -fn finalize_padding(ref input: Array, num_padding_words: u32) { - if (num_padding_words == 1) { - input.append(0x8000000000000000); - return; - } - - input.append(0); - finalize_padding(ref input, num_padding_words - 1); -} - -/// Computes the Keccak-256 hash of a `ByteArray`. -/// -/// # Arguments -/// -/// * `arr` - The input bytes to hash -/// -/// # Returns -/// -/// The 32-byte Keccak-256 hash as a little-endian `u256` -/// -/// # Examples -/// -/// ``` -/// use core::keccak::compute_keccak_byte_array; -/// -/// let text: ByteArray = "Hello world!"; -/// let hash = compute_keccak_byte_array(@text); -/// assert!(hash == 0xabea1f2503529a21734e2077c8b584d7bee3f45550c2d2f12a198ea908e1d0ec); -/// ``` -pub fn compute_keccak_byte_array(arr: @ByteArray) -> u256 { - let mut iter = arr.span().into_iter(); - let mut word_arr = array![]; - - let (last_word, last_word_len) = loop { - let Some(curr_word) = iter.next() else { - break (0, 0); - }; - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 1); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x100); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 2); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x10000); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 3); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x1000000); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 4); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x100000000); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 5); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x10000000000); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 6); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x1000000000000); - let Some(next_byte) = iter.next() else { - break (upcast(curr_word), 7); - }; - let curr_word = conversions::prepend_byte(curr_word, next_byte, 0x100000000000000); - word_arr.append(upcast(curr_word)); - }; - add_padding(ref word_arr, last_word, last_word_len); - starknet::syscalls::keccak_syscall(word_arr.span()).unwrap_syscall() -} - -mod conversions { - #[feature("bounded-int-utils")] - use core::internal::bounded_int::{self, AddHelper, BoundedInt, MulHelper, UnitInt}; - - impl U8Shift8 of MulHelper> { - type Result = BoundedInt<0, 0xFF00>; - } - impl U8Shift16 of MulHelper> { - type Result = BoundedInt<0, 0xFF0000>; - } - impl U8Shift24 of MulHelper> { - type Result = BoundedInt<0, 0xFF000000>; - } - impl U8Shift32 of MulHelper> { - type Result = BoundedInt<0, 0xFF00000000>; - } - impl U8Shift40 of MulHelper> { - type Result = BoundedInt<0, 0xFF0000000000>; - } - impl U8Shift48 of MulHelper> { - type Result = BoundedInt<0, 0xFF000000000000>; - } - impl U8Shift56 of MulHelper> { - type Result = BoundedInt<0, 0xFF00000000000000>; - } - impl U8ShiftAddU8 of AddHelper { - type Result = BoundedInt<0, 0xFFFF>; - } - impl U8ShiftAddU16 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFF>; - } - impl U8ShiftAddU24 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFF>; - } - impl U8ShiftAddU32 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFFFF>; - } - impl U8ShiftAddU40 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFFFFFF>; - } - impl U8ShiftAddU48 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFFFFFFFF>; - } - impl U8ShiftAddU56 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFFFFFFFFFF>; - } - - trait PrependByte { - impl Mul: MulHelper>; - impl Add: AddHelper; - } - - // Blanket implementation for any type with appropriate helpers. - impl PrependByteImpl< - T, const C: felt252, impl MH: MulHelper>, impl AH: AddHelper, - > of PrependByte {} - - /// Shifts a byte to be the next byte of the word. - pub fn prepend_byte< - T, - const C: felt252, - MulResult, - impl PB: PrependByte, - +core::metaprogramming::TypeEqual, - >( - word: T, byte: u8, shift: UnitInt, - ) -> PB::Add::Result { - bounded_int::add::<_, _, PB::Add>(word, bounded_int::mul::<_, _, PB::Mul>(byte, shift)) - } -} diff --git a/corelib/src/keyword_docs.cairo b/corelib/src/keyword_docs.cairo deleted file mode 100644 index ef0b36e40b..0000000000 --- a/corelib/src/keyword_docs.cairo +++ /dev/null @@ -1,362 +0,0 @@ -/// ### The `as` keyword. -/// Allows to alias an item when importing it with `use` statement. -/// -/// ### Example -/// ```cairo -/// pub mod single_const { -/// pub const A: u8 = 1; -/// } -/// -/// fn using_aliased_const() { -/// use single_const::A as B; -/// assert_eq!(B, 1); -/// } -/// ``` -mod keyword_as {} - -/// ### The `const` keyword. -/// Introduces a constant item or const generic parameter. Constants are evaluated at compile time. -/// -/// ### Examples -/// -/// - Module-level constant: -/// ```cairo -/// const TEN: u32 = 10; -/// fn times_ten(x: u32) -> u32 { x * TEN } -/// ``` -/// -/// - Const-generic parameter used by functions: -/// ```cairo -/// fn pad_with(x: felt252) -> felt252 { x + P } -/// ``` -mod keyword_const {} - -/// ### The `else` keyword. -/// Specifies an alternative branch for `if` or a fallback with `match` guards. -/// -/// ### Example -/// ```cairo -/// fn is_positive(x: i32) -> bool { -/// if x >= 0 { true } else { false } -/// } -/// ``` -mod keyword_else {} - -/// ### The `enum` keyword. -/// Declares an enumeration type with named variants. -/// -/// ### Example -/// ```cairo -/// #[derive(Copy, Drop)] -/// enum ResultU32 { -/// Ok: u32, -/// Err: felt252, -/// } -/// ``` -mod keyword_enum {} - -/// ### The `extern` keyword. -/// Declares external libfuncs or types provided by the compiler. -/// -/// ### Example -/// ```cairo -/// extern fn array_new() -> Array nopanic; -/// ``` -mod keyword_extern {} - -/// ### The `false` keyword. -/// Boolean enum value representing logical false. -/// -/// ### Example -/// ```cairo -/// fn default_bool() -> bool { false } -/// ``` -mod keyword_false {} - -/// ### The `fn` keyword. -/// Declares a function. Functions may specify implicits, panic behavior, generics, and attrs. -/// -/// ### Example -/// ```cairo -/// fn add_u32(a: u32, b: u32) -> u32 { a + b } -/// ``` -mod keyword_fn {} - -/// ### The `if` keyword. -/// Begins a conditional branch. -/// -/// ### Example -/// ```cairo -/// fn sign(x: felt252) -> felt252 { -/// if x == 0 { -/// 0 -/// } else { -/// if x > 0 { 1 } else { -1 } -/// } -/// } -/// ``` -mod keyword_if {} - -/// ### The `while` keyword. -/// Starts a conditional loop that runs while the condition is true. -/// -/// ### Example -/// ```cairo -/// fn sum_first(n: u32) -> u32 { -/// let mut i = 0; -/// let mut acc = 0; -/// while i < n { acc = acc + i; i = i + 1; } -/// acc -/// } -/// ``` -mod keyword_while {} - -/// ### The `for` keyword. -/// Iteration construct over ranges or iterables. -/// -/// ### Example -/// ```cairo -/// fn sum_range(n: u32) -> u32 { -/// let mut acc = 0; -/// for i in 0..n { acc = acc + i; } -/// acc -/// } -/// ``` -mod keyword_for {} - -/// ### The `loop` keyword. -/// Starts an infinite loop, typically exited with `break` or `return`. -/// -/// ### Example -/// ```cairo -/// fn first_positive(xs: Array) -> felt252 { -/// let mut i = 0; -/// loop { -/// if i >= xs.len() { return 0; } -/// let v = *xs.at(i); -/// if v != 0 { return v; } -/// i = i + 1; -/// } -/// } -/// ``` -mod keyword_loop {} - -/// ### The `impl` keyword. -/// Introduces an implementation block for a trait or type. -/// -/// ### Example -/// ```cairo -/// trait Doubler { fn double(self: @u32) -> u32; } -/// impl Doubling of Doubler { -/// fn double(self: @u32) -> u32 { *self + *self } -/// } -/// ``` -mod keyword_impl {} - -/// ### The `implicits` keyword. -/// Declares implicit parameters required by a function. These are usually passed automatically. -/// -/// ### Example -/// ```cairo -/// extern fn check_in_u32_range(value: u32) -> (bool,) implicits(RangeCheck) nopanic; -/// ``` -mod keyword_implicits {} - -/// ### The `let` keyword. -/// Binds a new variable. -/// -/// ### Example -/// ```cairo -/// fn square(x: u32) -> u32 { let y = x * x; y } -/// ``` -mod keyword_let {} - -/// ### The `macro` keyword. -/// Creates a declarative macro. -/// -/// ### Example -/// ```cairo -/// macro add_one { -/// ($x:ident) => { $x + 1 }; -/// } -/// ``` -mod keyword_macro {} - -/// ### The `match` keyword. -/// Pattern matching construct that selects a branch based on a value. -/// -/// ### Example -/// ```cairo -/// fn to_bool(x: u32) -> bool { -/// match x { 0 => false, _ => true } -/// } -/// ``` -mod keyword_match {} - -/// ### The `mod` keyword. -/// Declares a module. Modules group items and control visibility. -/// -/// ### Example -/// ```cairo -/// mod math_utils { pub fn add(a: u32, b: u32) -> u32 { a + b } } -/// ``` -mod keyword_mod {} - -/// ### The `mut` keyword. -/// Marks a binding or reference as mutable. -/// -/// ### Example -/// ```cairo -/// fn count(n: u32) -> u32 { -/// let mut i = 0; while i < n { i = i + 1; } i -/// } -/// ``` -mod keyword_mut {} - -/// ### The `nopanic` keyword. -/// Marks a function as guaranteed not to panic. The compiler enforces no panicking paths. -/// -/// ### Example -/// ```cairo -/// extern fn bool_to_felt252(a: bool) -> felt252 nopanic; -/// fn into_felt(b: bool) -> felt252 nopanic { bool_to_felt252(b) } -/// ``` -mod keyword_nopanic {} - -/// ### The `of` keyword. -/// Used in `impl Type of Trait` headers. -/// -/// ### Example -/// ```cairo -/// trait Foo { fn foo(self: @T) -> T; } -/// impl FooU32 of Foo { fn foo(self: @u32) -> u32 { *self + 1 } } -/// ``` -mod keyword_of {} - - -/// ### The `ref` keyword. -/// Allows functions to mutate variables by passing them as a reference. -/// The value is implicitly copied and passed back to the user. -/// -/// ### Example -/// ```cairo -/// fn push_four(ref ary: Array) { -/// ary.append(4) -/// } -/// -/// fn main() { -/// let mut ary = array![1, 2, 3]; -/// push_four(ref ary); -/// assert!(ary == array![1, 2, 3, 4]) -/// } -/// ``` -mod keyword_ref {} - -/// ### The `continue` keyword. -/// Skips to the next iteration of a loop. -/// -/// ### Example -/// ```cairo -/// fn skip_even(n: u32) -> u32 { -/// let mut i = 0; let mut cnt = 0; -/// while i < n { -/// i = i + 1; -/// if i % 2 == 0 { continue; } -/// cnt = cnt + 1; -/// } -/// cnt -/// } -/// ``` -mod keyword_continue {} - -/// ### The `return` keyword. -/// Exits a function, optionally returning a value. -/// -/// ### Example -/// ```cairo -/// fn clamp01(x: i32) -> i32 { -/// if x < 0 { return 0; } -/// if x > 1 { return 1; } -/// x -/// } -/// ``` -mod keyword_return {} - -/// ### The `break` keyword. -/// Exits a loop early. Can only be used inside `loop`, `while` or `for` loop blocks. -/// -/// ### Example -/// ```cairo -/// fn first_gt(xs: Array, cmp: u32) -> Option { -/// let mut i = 0; -/// let v = loop { -/// if i >= xs.len() { -/// return None; -/// } -/// -/// let v = *xs.at(i); -/// if v > cmp { break Some(v); } -/// i = i + 1; -/// }; -/// v -/// } -/// ``` -mod keyword_break {} - -/// ### The `struct` keyword. -/// Declares a structure type with named members. -/// -/// ### Example -/// ```cairo -/// struct Point { x: felt252, y: felt252 } -/// fn origin() -> Point { Point { x: 0, y: 0 } } -/// ``` -mod keyword_struct {} - -/// ### The `trait` keyword. -/// Declares a trait containing associated items to be implemented. -/// -/// ### Example -/// ```cairo -/// trait Volume { fn volume(self: @T) -> usize; } -/// impl ArrayVolume of Volume> { fn volume(self: @Array) -> usize { self.len() } } -/// ``` -mod keyword_trait {} - -/// ### The `true` keyword. -/// Boolean enum value representing logical true. -/// -/// ### Example -/// ```cairo -/// fn yes() -> bool { true } -/// ``` -mod keyword_true {} - -/// ### The `type` keyword. -/// Declares a type alias. -/// -/// ### Example -/// ```cairo -/// type usize = u32; -/// ``` -mod keyword_type {} - -/// ### The `use` keyword. -/// Imports items into the current scope. -/// -/// ### Examples -/// ```cairo -/// use core::panic_with_felt252; -/// use super::traits::PartialEq; -/// ``` -mod keyword_use {} - -/// ### The `pub` keyword. -/// Makes an item public within its parent module (or crate). -/// -/// ### Example -/// ```cairo -/// pub fn get_zero() -> u32 { 0 } -/// pub(crate) struct Pair { pub a: u32, b: u32 } -/// ``` -mod keyword_pub {} diff --git a/corelib/src/lib.cairo b/corelib/src/lib.cairo deleted file mode 100644 index 8b7c1e38df..0000000000 --- a/corelib/src/lib.cairo +++ /dev/null @@ -1,445 +0,0 @@ -//! Main entrypoint for the Cairo core library. - -pub mod traits; -use serde::Serde; -#[feature("deprecated-index-traits")] -#[feature("deprecated-op-assign-traits")] -#[allow(unused_imports)] -use traits::{ - Add, AddEq, BitAnd, BitNot, BitOr, BitXor, Copy, Default, Destruct, Div, DivEq, DivRem, Drop, - Felt252DictValue, Index, IndexView, Into, Mul, MulEq, Neg, Not, PanicDestruct, PartialEq, - PartialOrd, Rem, RemEq, Sub, SubEq, TryInto, -}; - -/// `usize` is an alias for `u32` type. -pub type usize = u32; - -/// `bool` enum representing either `false` or `true`. -#[derive(Copy, Drop, Default)] -pub enum bool { - #[default] - False, - True, -} - -impl BoolSerde of Serde { - fn serialize(self: @bool, ref output: Array) { - if *self { - 1_felt252 - } else { - 0_felt252 - }.serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Some(*serialized.pop_front()? != 0) - } -} - -extern fn bool_and_impl(lhs: bool, rhs: bool) -> (bool,) implicits() nopanic; -impl BoolBitAnd of BitAnd { - #[inline] - fn bitand(lhs: bool, rhs: bool) -> bool { - let (r,) = bool_and_impl(lhs, rhs); - r - } -} - -extern fn bool_or_impl(lhs: bool, rhs: bool) -> (bool,) implicits() nopanic; -impl BoolBitOr of BitOr { - #[inline] - fn bitor(lhs: bool, rhs: bool) -> bool { - let (r,) = bool_or_impl(lhs, rhs); - r - } -} - -extern fn bool_not_impl(a: bool) -> (bool,) implicits() nopanic; -#[inline] -impl BoolNot of Not { - #[inline] - fn not(a: bool) -> bool implicits() nopanic { - let (r,) = bool_not_impl(a); - r - } -} - -extern fn bool_xor_impl(lhs: bool, rhs: bool) -> (bool,) implicits() nopanic; -impl BoolBitXor of BitXor { - #[inline] - fn bitxor(lhs: bool, rhs: bool) -> bool { - let (r,) = bool_xor_impl(lhs, rhs); - r - } -} - -impl BoolPartialEq of PartialEq { - #[inline] - fn eq(lhs: @bool, rhs: @bool) -> bool { - match lhs { - false => !*rhs, - true => *rhs, - } - } - - #[inline] - fn ne(lhs: @bool, rhs: @bool) -> bool { - match lhs { - false => *rhs, - true => !*rhs, - } - } -} - -impl BoolFelt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> bool nopanic { - false - } -} - -extern fn bool_to_felt252(a: bool) -> felt252 implicits() nopanic; -impl BoolIntoFelt252 of Into { - #[inline] - fn into(self: bool) -> felt252 implicits() nopanic { - bool_to_felt252(self) - } -} - -pub mod boolean; - -pub mod circuit; - -/// General purpose implicits. -pub extern type RangeCheck; -pub extern type SegmentArena; - -mod felt_252; -#[allow(unused_imports)] -use felt_252::{Felt252One, Felt252Zero}; - -/// `felt252` is the basic field element used in Cairo. -/// -/// It corresponds to an integer in the range 0 ≤ x < P where P is -/// a very large prime number currently equal to 2^251 + 17⋅2^192 + 1. -/// -/// Any operation that uses `felt252` will be computed modulo P. -pub extern type felt252; - -impl felt252Copy of Copy; -impl felt252Drop of Drop; - -extern fn felt252_const() -> felt252 nopanic; - -impl Felt252Serde of Serde { - fn serialize(self: @felt252, ref output: Array) { - output.append(*self); - } - - fn deserialize(ref serialized: Span) -> Option { - let mut snapshot = serialized.snapshot; - match crate::array::array_snapshot_pop_front(ref snapshot) { - Some(x) => { - serialized = Span { snapshot }; - Some(*x.unbox()) - }, - None => { - serialized = Span { snapshot }; - None - }, - } - } -} - -extern fn felt252_add(lhs: felt252, rhs: felt252) -> felt252 nopanic; - -impl Felt252Add of Add { - #[inline] - fn add(lhs: felt252, rhs: felt252) -> felt252 { - felt252_add(lhs, rhs) - } -} - -impl Felt252AddEq of AddEq { - #[inline] - fn add_eq(ref self: felt252, other: felt252) { - self = Add::add(self, other); - } -} - -extern fn felt252_sub(lhs: felt252, rhs: felt252) -> felt252 nopanic; - -impl Felt252Sub of Sub { - #[inline] - fn sub(lhs: felt252, rhs: felt252) -> felt252 { - felt252_sub(lhs, rhs) - } -} - -impl Felt252SubEq of SubEq { - #[inline] - fn sub_eq(ref self: felt252, other: felt252) { - self = Sub::sub(self, other); - } -} - -extern fn felt252_mul(lhs: felt252, rhs: felt252) -> felt252 nopanic; - -impl Felt252Mul of Mul { - #[inline] - fn mul(lhs: felt252, rhs: felt252) -> felt252 { - felt252_mul(lhs, rhs) - } -} - -impl Felt252MulEq of MulEq { - #[inline] - fn mul_eq(ref self: felt252, other: felt252) { - self = Mul::mul(self, other); - } -} - -impl Felt252Neg of Neg { - #[inline] - fn neg(a: felt252) -> felt252 { - a * -1 - } -} - -/// Performs division on `felt252` values in Cairo's finite field. -/// Unlike regular integer division, `felt252` division returns a field element n that satisfies -/// the equation: n * rhs ≡ lhs (mod P), where P is the `felt252` prime. -/// -/// # Examples -/// -/// ``` -/// use core::felt252_div; -/// -/// // Division with 0 remainder works the same way as integer division. -/// assert!(felt252_div(4, 2) == 2); -/// -/// // Division with non 0 remainder returns a field element n where n * 3 ≡ 4 (mod P) -/// assert!(felt252_div(4, 3) == -/// 1206167596222043737899107594365023368541035738443865566657697352045290673495); -/// -/// ``` -pub extern fn felt252_div(lhs: felt252, rhs: NonZero) -> felt252 nopanic; - -impl Felt252PartialEq of PartialEq { - #[inline] - fn eq(lhs: @felt252, rhs: @felt252) -> bool { - match *lhs - *rhs { - 0 => true, - _ => false, - } - } -} - -extern const fn felt252_is_zero(lhs: felt252) -> zeroable::IsZeroResult nopanic; - -impl Felt252TryIntoNonZero of TryInto> { - const fn try_into(self: felt252) -> Option> { - match felt252_is_zero(self) { - zeroable::IsZeroResult::Zero => None, - zeroable::IsZeroResult::NonZero(x) => Some(x), - } - } -} - -impl Felt252Default of Default { - #[inline] - fn default() -> felt252 nopanic { - 0 - } -} - -impl Felt252Felt252DictValue of Felt252DictValue { - #[inline] - fn zero_default() -> felt252 nopanic { - 0 - } -} - -pub mod blake; - -pub mod box; -#[allow(unused_imports)] -use box::{Box, BoxTrait}; - -pub mod nullable; -#[allow(unused_imports)] -use nullable::{Nullable, NullableTrait, match_nullable, null, nullable_from_box}; - -pub mod array; -#[allow(unused_imports)] -use array::{Array, ArrayTrait, Span, SpanTrait}; - -pub mod dict; -#[allow(unused_imports)] -use dict::{ - Felt252Dict, Felt252DictTrait, SquashedFelt252Dict, felt252_dict_new, felt252_dict_squash, -}; - -pub mod result; -#[allow(unused_imports)] -use result::{Result, ResultTrait}; - -pub mod option; -#[allow(unused_imports)] -use option::{Option, OptionTrait}; - -pub mod clone; -#[allow(unused_imports)] -use clone::Clone; - -pub mod ec; -#[allow(unused_imports)] -use ec::{EcOp, EcPoint, EcState}; - -pub mod ecdsa; - -#[feature("corelib-internal-use")] -pub mod integer; -#[allow(unused_imports)] -use integer::{ - Bitwise, Felt252IntoU256, Felt252TryIntoU128, Felt252TryIntoU16, Felt252TryIntoU32, - Felt252TryIntoU64, Felt252TryIntoU8, I128IntoFelt252, I16IntoFelt252, I32IntoFelt252, - I64IntoFelt252, I8IntoFelt252, NumericLiteral, U128IntoFelt252, U16IntoFelt252, U32IntoFelt252, - U64IntoFelt252, U8IntoFelt252, i128, i16, i32, i64, i8, u128, u128_is_zero, u16, u256, u32, u64, - u8, -}; -#[feature("corelib-internal-use")] -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -#[allow(unused_imports)] -use integer::{u128_sqrt, u256_sqrt}; - -pub mod cmp; - -pub mod gas; - -#[feature("corelib-internal-use")] -pub mod math; - -pub mod num; - -pub mod ops; -#[allow(unused_imports)] -use gas::{BuiltinCosts, GasBuiltin, get_builtin_costs}; - -pub mod panics; -#[allow(unused_imports)] -use panics::{Panic, PanicResult, panic}; - -pub enum never {} - -/// Panics with the given `felt252` as error message. -/// -/// # Examples -/// -/// ``` -/// use core::panic_with_felt252; -/// -/// panic_with_felt252('error message'); -/// ``` -#[inline(never)] -pub fn panic_with_felt252(err_code: felt252) -> never { - panic(array![err_code]) -} - -/// Panics with the given const argument `felt252` as error message. -/// -/// # Examples -/// -/// ``` -/// use core::panic_with_const_felt252; -/// -/// panic_with_const_felt252::<'error message'>(); -/// ``` -#[inline(never)] -pub fn panic_with_const_felt252() -> never { - panic_with_felt252(ERR_CODE) -} - -/// Panics if `cond` is false with the given `felt252` as error message. -/// -/// # Examples -/// -/// ``` -/// assert(false, 'error message'); -/// ``` -#[inline] -pub const fn assert(cond: bool, err_code: felt252) { - if !cond { - panic_with_felt252(err_code) - } -} - -pub mod hash; - -pub mod keccak; - -pub mod pedersen; - -pub mod qm31; - -pub mod serde; - -pub mod sha256; -#[allow(unused_imports)] -use pedersen::Pedersen; - -pub mod poseidon; -#[allow(unused_imports)] -use poseidon::Poseidon; - -pub mod debug; - -pub mod fmt; - -#[feature("corelib-internal-use")] -#[deprecated(feature: "corelib-internal-use", note: "Use `starknet` directly")] -pub mod starknet; -#[allow(unused_imports)] -#[feature("corelib-internal-use")] -use starknet::System; - -pub mod internal; - -pub mod zeroable; -#[allow(unused_imports)] -use zeroable::{NonZero, Zeroable}; - -pub mod bytes_31; -#[allow(unused_imports)] -use bytes_31::{ - Bytes31IndexView, Bytes31IntoFelt252, Bytes31Trait, Felt252TryIntoBytes31, bytes31, - bytes31_const, -}; - -pub mod byte_array; -#[allow(unused_imports)] -use byte_array::{ByteArray, ByteArrayIndexView, ByteArrayStringLiteral, ByteArrayTrait}; - -pub mod string; -#[allow(unused_imports)] -use string::StringLiteral; - -mod fixed_size_array; - -pub mod iter; - -mod keyword_docs; - -pub mod metaprogramming; - -#[allow(unused_imports)] -mod prelude; - -#[cfg(test)] -mod test; - -pub mod testing; - -pub mod to_byte_array; - -mod tuple; diff --git a/corelib/src/math.cairo b/corelib/src/math.cairo deleted file mode 100644 index 8c701e16f6..0000000000 --- a/corelib/src/math.cairo +++ /dev/null @@ -1,266 +0,0 @@ -//! Mathematical operations and utilities. -//! -//! Provides extended GCD, modular inverse, and modular arithmetic operations. - -use crate::RangeCheck; -use crate::integer::{U128MulGuarantee, u256_wide_mul, u512_safe_div_rem_by_u256}; -#[allow(unused_imports)] -use crate::option::OptionTrait; -#[allow(unused_imports)] -use crate::traits::{Into, TryInto}; -#[allow(unused_imports)] -use crate::zeroable::{IsZeroResult, NonZeroIntoImpl, Zeroable}; - -/// Computes the extended GCD and Bezout coefficients for two numbers. -/// -/// Uses the Extended Euclidean algorithm to find (g, s, t, sub_direction) where `g = gcd(a, b)`. -/// The relationship between inputs and outputs is: -/// * If `sub_direction` is true: `g = s * a - t * b` -/// * If `sub_direction` is false: `g = t * b - s * a` -/// -/// Returns a tuple (g, s, t, sub_direction) where g is the GCD and `(s, -t)` or `(-s, t)` are the -/// Bezout coefficients (according to `sub_direction`). -/// -/// # Examples -/// -/// ``` -/// use core::math::egcd; -/// -/// let (g, s, t, dir) = egcd::(12, 8); -/// assert!(g == 4); -/// if dir { -/// assert!(s * 12 - t * 8 == 4); -/// } else { -/// assert!(t * 8 - s * 12 == 4); -/// } -/// let (g, s, t, dir) = egcd::(-3, 15); -/// assert!(g == 3); -/// if dir { -/// assert!(s * -3 - t * 15 == 3); -/// } else { -/// assert!(t * 15 - s * -3 == 3); -/// } -/// ``` -pub fn egcd< - T, - +Copy, - +Drop, - +Add, - +Mul, - +DivRem, - +core::num::traits::Zero, - +core::num::traits::One, - +TryInto>, - +Sub, - +PartialOrd, ->( - a: NonZero, b: NonZero, -) -> (T, T, T, bool) { - let (q, r) = DivRem::::div_rem(a.into(), b); - let Some(r) = r.try_into() else { - let (abs_b, sign) = abs_and_sign(b.into()); - return (abs_b, core::num::traits::Zero::zero(), core::num::traits::One::one(), sign); - }; - - // `sign` (1 for true, -1 for false) is the sign of `g` in the current iteration. - // 0 is considered negative for this purpose. - let (g, s, t, sign) = egcd(b, r); - // From the recursive call, we know that `s*b - t*r = sign*g`. - // From the division above, we have `a = q*b + r`, which gives us `r = a - q*b`. - // Substituting `r` into the equation: - // `s*b - t*r = sign*g` - // `s*b - t*(a - q*b) = sign*g` - // `s*b - t*a + t*q*b = sign*g` - // `(s + q*t)*b - t*a = sign*g` - // Rearranging: - // `t*a - (s + q*t)*b = (-sign)*g` - // Thus we pick `new_s = t`, `new_t = s + q*t`, `new_sign = !sign`. - (g, t, s + q * t, !sign) -} - -/// Computes the modular multiplicative inverse of `a` modulo `n`. -/// -/// Returns `s` such that `a*s ≡ 1 (mod n)` where `s` is between `1` and `|n|-1` inclusive, or -/// `None` if `gcd(a,n) > 1` (inverse doesn't exist). -/// -/// # Note -/// -/// We consider the cases of negative `n` to be equivalent to the cases of positive `n`, as it -/// defines the same equivalence classes. -/// -/// # Examples -/// -/// ``` -/// use core::math::inv_mod; -/// -/// assert!(inv_mod::(3, 7) == Some(5)); -/// assert!(inv_mod::(3, 9) == None); -/// ``` -pub fn inv_mod< - T, - +Copy, - +Drop, - +Add, - +Sub, - +Mul, - +DivRem, - +core::num::traits::Zero, - +core::num::traits::One, - +TryInto>, - +PartialOrd, ->( - a: NonZero, n: NonZero, -) -> Option { - // In any case, normalizing `n` to be positive. - let (n_abs, _) = abs_and_sign(n.into()); - if core::num::traits::One::::is_one(@n_abs) { - return None; - } - let (g, s, _, sub_direction) = egcd(a, n); - if g.is_one() { - let (s_abs, s_sign) = abs_and_sign(s); - // `1 = g = gcd(a, n) = +-(s*a - t*n) => s*a = +-1 (mod n)`. - // The absolute values of Bezout coefficients are guaranteed to be `< n`. - // With n > 1 and gcd = 1, `s` can't be 0. - if sub_direction ^ s_sign { - // Both cases are valid: - // 1. `s` is the Bezout coefficient and `s > 0` so `0 < s < n`. - // 2. `-s` is the Bezout coefficient and `s < 0` so `0 < -s < n`. - Some(s_abs) - } else { - // Both cases are valid: - // 1. `-s` is the Bezout coefficient and `s > 0` so - // `-n < -s < 0 => 0 < n - s < n`, and `n - s = -s (mod n)`. - // 2. `s` is the Bezout coefficient and `s < 0` so - // `-n < s < 0 => 0 < n - (-s) < n`, and `n - (-s) = s (mod n)`. - Some(n_abs - s_abs) - } - } else { - None - } -} - -/// Returns `(|value|, value < 0)`. -fn abs_and_sign, +Drop, +PartialOrd, +Sub, +core::num::traits::Zero>( - value: T, -) -> (T, bool) { - let zero = core::num::traits::Zero::::zero(); - if value < zero { - (zero - value, true) - } else { - (value, false) - } -} - -/// Returns `1 / b (mod n)`, or `Err` if `b` is not invertible modulo `n`. -/// -/// All `b`s will be considered not invertible for `n == 1`. -/// Additionally returns several `U128MulGuarantee`s that are required for validating the -/// calculation. -extern fn u256_guarantee_inv_mod_n( - b: u256, n: NonZero, -) -> Result< - ( - NonZero, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - U128MulGuarantee, - ), - (U128MulGuarantee, U128MulGuarantee), -> implicits(RangeCheck) nopanic; - -/// Returns the inverse of `a` modulo `n`, or `None` if `a` is not invertible modulo `n`. -/// -/// All `a`s will be considered not invertible for `n == 1`. -/// -/// # Examples -/// -/// ``` -/// use core::math::u256_inv_mod; -/// -/// let inv = u256_inv_mod(3, 17); -/// assert!(inv == Some(6)); -/// ``` -#[inline] -pub fn u256_inv_mod(a: u256, n: NonZero) -> Option> { - match u256_guarantee_inv_mod_n(a, n) { - Ok((inv_a, _, _, _, _, _, _, _, _)) => Some(inv_a), - Err(_) => None(()), - } -} - -/// Returns `a / b (mod n)`, or `None` if `b` is not invertible modulo `n`. -/// -/// # Examples -/// -/// ``` -/// use core::math::u256_div_mod_n; -/// -/// let result = u256_div_mod_n(17, 7, 29); -/// assert!(result == Some(19)); -/// ``` -pub fn u256_div_mod_n(a: u256, b: u256, n: NonZero) -> Option { - Some(u256_mul_mod_n(a, u256_inv_mod(b, n)?.into(), n)) -} - -/// Returns `a * b (mod n)`. -/// -/// # Examples -/// -/// ``` -/// use core::math::u256_mul_mod_n; -/// -/// let result = u256_mul_mod_n(17, 23, 29); -/// assert!(result == 14); -/// ``` -pub fn u256_mul_mod_n(a: u256, b: u256, n: NonZero) -> u256 { - let (_, r) = u512_safe_div_rem_by_u256(u256_wide_mul(a, b), n); - r -} - -/// A trait for types that have a multiplicative identity element. -trait Oneable { - /// Returns the multiplicative identity element of Self, 1. - #[must_use] - fn one() -> T; - - /// Returns whether self is equal to 1, the multiplicative identity element. - #[must_use] - fn is_one(self: T) -> bool; - - /// Returns whether self is not equal to 1, the multiplicative identity element. - #[must_use] - fn is_non_one(self: T) -> bool; -} - -pub(crate) mod one_based { - pub(crate) impl OneableImpl< - T, impl OneImpl: crate::num::traits::One, +Drop, +Copy, - > of super::Oneable { - fn one() -> T { - OneImpl::one() - } - - #[inline] - fn is_one(self: T) -> bool { - OneImpl::is_one(@self) - } - - #[inline] - fn is_non_one(self: T) -> bool { - OneImpl::is_non_one(@self) - } - } -} - -impl U8Oneable = one_based::OneableImpl; -impl U16Oneable = one_based::OneableImpl; -impl U32Oneable = one_based::OneableImpl; -impl U64Oneable = one_based::OneableImpl; -impl U128Oneable = one_based::OneableImpl; -impl U256Oneable = one_based::OneableImpl; diff --git a/corelib/src/metaprogramming.cairo b/corelib/src/metaprogramming.cairo deleted file mode 100644 index e1619f0750..0000000000 --- a/corelib/src/metaprogramming.cairo +++ /dev/null @@ -1,57 +0,0 @@ -//! Metaprogramming utilities. - -/// A trait that can be used to disable implementations based on the types of the generic args. -/// Assumes that `TypeEqualImpl` is the only implementation of this trait. -/// -/// Primarily used for optimizations by enabling type-specific implementations. -/// Since `TypeEqualImpl` is the only implementation, adding `-TypeEqual` as a trait -/// bound ensures the implementation is only available when T and U are different types. -pub trait TypeEqual {} - -impl TypeEqualImpl of TypeEqual; - -/// Marker trait for types that are tuples. -/// Currently supports tuples of size 0 to 16. -pub(crate) trait IsTuple; - - -/// A trait for splitting a tuple into head element and a tail tuple, as well as reconstructing from -/// them. -pub(crate) trait TupleSplit { - /// The type of the first element of the tuple. - type Head; - /// The type of the rest of the tuple. - type Rest; - /// Splits the tuple into the head and the rest. - fn split_head(self: T) -> (Self::Head, Self::Rest) nopanic; - /// Reconstructs the tuple from the head and the rest. - fn reconstruct(head: Self::Head, rest: Self::Rest) -> T nopanic; -} - - -/// A trait for extending a tuple from the front. -pub(crate) trait TupleExtendFront { - /// The type of the resulting tuple. - type Result; - /// Creates a new tuple from the `value` tuple with `element` in front of it. - fn extend_front(value: T, element: E) -> Self::Result nopanic; -} - - -/// A trait for forwarding a wrapping snapshot from a tuple style struct into a tuple style struct -/// of the snapshots. -pub(crate) trait TupleSnapForward { - type SnapForward; - fn snap_forward(self: @T) -> Self::SnapForward nopanic; -} - - -/// A trait for removing a wrapping snapshot from the types in tuple style struct. -pub(crate) trait SnapRemove { - type Result; -} - -impl SnapRemoveSnap of SnapRemove<@T> { - type Result = T; -} - diff --git a/corelib/src/nullable.cairo b/corelib/src/nullable.cairo deleted file mode 100644 index 82fd3b10d6..0000000000 --- a/corelib/src/nullable.cairo +++ /dev/null @@ -1,240 +0,0 @@ -//! A wrapper type for handling optional values. -//! -//! `Nullable` is a wrapper type that can either contain a value stored in a `Box` -//! or be null. It provides a safe way to handle optional values without the risk of -//! dereferencing null pointers. -//! -//! This makes it particularly useful in dictionaries that store complex data structures that don't -//! implement the `Felt252DictValue` trait; instead, they can be wrapped inside a `Nullable`. -//! -//! # Examples -//! -//! Basic usage: -//! ``` -//! let value: Nullable = NullableTrait::new(10); -//! let unwrapped_value = value.deref(); -//! ``` -//! -//! Handling null values: -//! ``` -//! let null_value: Nullable = Default::default(); -//! let unwrapped_value = null_value.deref_or(1); -//! ``` -//! -//! Checking if the value is null: -//! ``` -//! let value: Nullable = NullableTrait::new(10); -//! let is_null = if value.is_null() { -//! // Handle null case -//! } else { -//! // Handle non-null case -//! }; -//! ``` - -use crate::box::BoxTrait; -use crate::traits::{Default, Felt252DictValue}; - -/// A type that can either be null or contain a boxed value. -pub extern type Nullable; - -impl NullableCopy> of Copy>; -impl NullableDrop> of Drop>; - -/// Represents the result of matching a `Nullable` value. -/// -/// Used to safely handle both null and non-null cases when using `match_nullable` on a -/// `Nullable`. -pub enum FromNullableResult { - /// Represents a null value - Null, - /// The boxed value when not null - NotNull: Box, -} - -pub extern fn null() -> Nullable nopanic; -pub(crate) extern fn nullable_from_box(value: Box) -> Nullable nopanic; -pub extern fn match_nullable(value: Nullable) -> FromNullableResult nopanic; -extern fn nullable_forward_snapshot(value: @Nullable) -> Nullable<@T> nopanic; - -impl NullableDeref of crate::ops::Deref> { - type Target = T; - /// Dereferences a `Nullable` to access its inner value. - /// - /// # Panics - /// - /// Panics if the value is null. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// let unwrapped: u32 = value.deref(); - /// assert!(unwrapped == 42); - /// - /// let null_value: Nullable = Default::default(); - /// let will_panic = null_value.deref(); // Panics - /// ``` - fn deref(self: Nullable) -> T { - match match_nullable(self) { - FromNullableResult::Null => crate::panic_with_felt252('Attempted to deref null value'), - FromNullableResult::NotNull(value) => value.unbox(), - } - } -} - -/// Trait for creating and manipulating `Nullable` values. -#[generate_trait] -pub impl NullableImpl of NullableTrait { - /// Wrapper for `Deref::deref`. Prefer using `Deref::deref` directly. - /// - /// This function exists for backwards compatibility. - /// - /// # Examples - /// - /// Preferred way: - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// let unwrapped = value.deref(); - /// ``` - /// - /// This function method does the same thing: - /// ``` - /// use core::nullable::NullableTrait; - /// let also_unwrapped = NullableTrait::deref(value); - /// ``` - fn deref(nullable: Nullable) -> T { - nullable.deref() - } - - /// Returns the contained value if not null, or returns the provided default value. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// assert!(value.deref_or(0) == 42); - /// - /// let null_value: Nullable = Default::default(); - /// assert!(null_value.deref_or(0) == 0); - /// ``` - fn deref_or<+Drop>(self: Nullable, default: T) -> T { - match match_nullable(self) { - FromNullableResult::Null => default, - FromNullableResult::NotNull(value) => value.unbox(), - } - } - - /// Returns the contained value if not null, or computes it from a closure. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// assert!(value.deref_or_else(|| 0) == 42); - /// - /// let null_value: Nullable = Default::default(); - /// assert!(null_value.deref_or_else(|| 0) == 0); - /// ``` - fn deref_or_else< - F, +Drop, impl func: core::ops::FnOnce[Output: T], +Drop, - >( - self: Nullable, f: F, - ) -> T { - match match_nullable(self) { - FromNullableResult::Null => f(), - FromNullableResult::NotNull(value) => value.unbox(), - } - } - - /// Creates a new non-null `Nullable` with the given value. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// assert!(!value.is_null()); - /// ``` - #[must_use] - fn new(value: T) -> Nullable { - nullable_from_box(BoxTrait::new(value)) - } - - /// Returns `true` if the value is null. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable = NullableTrait::new(42); - /// assert!(!value.is_null()); - /// - /// let null_value: Nullable = Default::default(); - /// assert!(null_value.is_null()); - /// ``` - #[must_use] - fn is_null(self: @Nullable) -> bool { - match match_nullable(self.as_snapshot()) { - FromNullableResult::Null => true, - FromNullableResult::NotNull(_) => false, - } - } - - /// Creates a new `Nullable` containing a snapshot of the value. - /// - /// This is useful when working with non-copyable types inside a `Nullable`. - /// This allows you to keep using the original value while also having access to a - /// snapshot of it, preventing the original value from being moved. - /// - /// # Examples - /// - /// ``` - /// let value: Nullable> = NullableTrait::new(array![1, 2, 3]); - /// let res = (@value).as_snapshot(); - /// assert!(res.deref() == @array![1, 2, 3]); - /// assert!(value.deref() == array![1, 2, 3]); - /// ``` - fn as_snapshot(self: @Nullable) -> Nullable<@T> nopanic { - nullable_forward_snapshot(self) - } -} - -impl NullableDefault of Default> { - /// Creates a new null value. - /// - /// # Examples - /// - /// ``` - /// let null_value: Nullable = Default::default(); - /// assert!(null_value.is_null()); - /// ``` - #[inline] - #[must_use] - fn default() -> Nullable nopanic { - null() - } -} - -impl NullableFelt252DictValue of Felt252DictValue> { - /// Creates a new null value for use in Felt252Dict. - /// - /// This implementation allows any type to be used as a value type in - /// dictionaries when wrapped in a `Nullable`, where uninitialized entries - /// return null. - #[inline] - #[must_use] - fn zero_default() -> Nullable nopanic { - null() - } -} - -impl NullableDebug> of crate::fmt::Debug> { - /// Formats a snapshot of a `Nullable` smart pointer for printing and debugging purposes. - fn fmt(self: @Nullable, ref f: crate::fmt::Formatter) -> Result<(), crate::fmt::Error> { - match match_nullable(self.as_snapshot()) { - FromNullableResult::Null => write!(f, "null"), - FromNullableResult::NotNull(value) => { - write!(f, "&")?; - TDebug::fmt(value.unbox(), ref f) - }, - } - } -} diff --git a/corelib/src/num.cairo b/corelib/src/num.cairo deleted file mode 100644 index f6ac8fc7b6..0000000000 --- a/corelib/src/num.cairo +++ /dev/null @@ -1 +0,0 @@ -pub mod traits; diff --git a/corelib/src/num/traits.cairo b/corelib/src/num/traits.cairo deleted file mode 100644 index 68b4a6971e..0000000000 --- a/corelib/src/num/traits.cairo +++ /dev/null @@ -1,25 +0,0 @@ -pub mod zero; -pub use zero::Zero; - -pub mod one; -pub use one::One; - -pub mod bit_size; -pub use bit_size::BitSize; - -mod bounded; -pub use bounded::Bounded; - -#[feature("corelib-internal-use")] -pub mod ops; -pub use ops::checked::{CheckedAdd, CheckedMul, CheckedSub}; -pub use ops::divrem::DivRem; -pub use ops::overflowing::{OverflowingAdd, OverflowingMul, OverflowingSub}; -pub use ops::pow::Pow; -pub use ops::saturating::{SaturatingAdd, SaturatingMul, SaturatingSub}; -#[allow(unused_imports)] -pub(crate) use ops::split::Split; -pub use ops::sqrt::Sqrt; -pub use ops::widemul::WideMul; -pub use ops::widesquare::WideSquare; -pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingSub}; diff --git a/corelib/src/num/traits/bit_size.cairo b/corelib/src/num/traits/bit_size.cairo deleted file mode 100644 index 5d1393c038..0000000000 --- a/corelib/src/num/traits/bit_size.cairo +++ /dev/null @@ -1,17 +0,0 @@ -//! Utilities for determining the bit size of types. - -/// A trait used to retrieve the size of a type in bits. -pub trait BitSize { - /// Returns the bit size of `T` as a `usize`. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::BitSize; - /// - /// let bits = BitSize::::bits(); - /// assert!(bits == 8); - /// ``` - #[must_use] - fn bits() -> usize; -} diff --git a/corelib/src/num/traits/bounded.cairo b/corelib/src/num/traits/bounded.cairo deleted file mode 100644 index 6e212e7ec2..0000000000 --- a/corelib/src/num/traits/bounded.cairo +++ /dev/null @@ -1,85 +0,0 @@ -//! Defines minimum and maximum values for numeric types. - -/// A trait defining minimum and maximum bounds for numeric types. -/// -/// This trait only supports types that can have constant values. -pub trait Bounded { - /// Returns the minimum value for type `T`. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::Bounded; - /// - /// let min = Bounded::::MIN; - /// assert!(min == 0); - /// ``` - const MIN: T; - - /// Returns the maximum value for type `T`. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::Bounded; - /// - /// let max = Bounded::::MAX; - /// assert!(max == 255); - /// ``` - const MAX: T; -} - -impl BoundedU8 of Bounded { - const MIN: u8 = 0x0; - const MAX: u8 = 0xff; -} - -impl BoundedU16 of Bounded { - const MIN: u16 = 0x0; - const MAX: u16 = 0xffff; -} - -impl BoundedU32 of Bounded { - const MIN: u32 = 0x0; - const MAX: u32 = 0xffffffff; -} - -impl BoundedU64 of Bounded { - const MIN: u64 = 0x0; - const MAX: u64 = 0xffffffffffffffff; -} - -impl BoundedU128 of Bounded { - const MIN: u128 = 0x0; - const MAX: u128 = 0xffffffffffffffffffffffffffffffff; -} - -impl BoundedU256 of Bounded { - const MIN: u256 = 0x0; - const MAX: u256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; -} - -impl BoundedI8 of Bounded { - const MIN: i8 = -0x80; - const MAX: i8 = 0x7f; -} - -impl BoundedI16 of Bounded { - const MIN: i16 = -0x8000; - const MAX: i16 = 0x7fff; -} - -impl BoundedI32 of Bounded { - const MIN: i32 = -0x80000000; - const MAX: i32 = 0x7fffffff; -} - -impl BoundedI64 of Bounded { - const MIN: i64 = -0x8000000000000000; - const MAX: i64 = 0x7fffffffffffffff; -} - -impl BoundedI128 of Bounded { - const MIN: i128 = -0x80000000000000000000000000000000; - const MAX: i128 = 0x7fffffffffffffffffffffffffffffff; -} diff --git a/corelib/src/num/traits/one.cairo b/corelib/src/num/traits/one.cairo deleted file mode 100644 index 82ff844849..0000000000 --- a/corelib/src/num/traits/one.cairo +++ /dev/null @@ -1,46 +0,0 @@ -//! Traits for types with a multiplicative identity element. - -/// Defines a multiplicative identity element for `T`. -/// -/// # Laws -/// -/// ```text -/// a * 1 = a ∀ a ∈ T -/// 1 * a = a ∀ a ∈ T -/// ``` -pub trait One { - /// Returns the multiplicative identity element of `T`, `1`. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::One; - /// - /// assert!(One::::one() == 1); - /// ``` - fn one() -> T; - - /// Returns true if `self` is equal to the multiplicative identity. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::One; - /// - /// assert!(1.is_one()); - /// assert!(!0.is_one()); - /// ``` - fn is_one(self: @T) -> bool; - - /// Returns false if `self` is equal to the multiplicative identity. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::One; - /// - /// assert!(0.is_non_one()); - /// assert!(!1.is_non_one()); - /// ``` - fn is_non_one(self: @T) -> bool; -} diff --git a/corelib/src/num/traits/ops.cairo b/corelib/src/num/traits/ops.cairo deleted file mode 100644 index d4e2cf686c..0000000000 --- a/corelib/src/num/traits/ops.cairo +++ /dev/null @@ -1,10 +0,0 @@ -pub mod checked; -pub mod divrem; -pub mod overflowing; -pub mod pow; -pub mod saturating; -pub(crate) mod split; -pub(crate) mod sqrt; -pub(crate) mod widemul; -pub(crate) mod widesquare; -pub mod wrapping; diff --git a/corelib/src/num/traits/ops/checked.cairo b/corelib/src/num/traits/ops/checked.cairo deleted file mode 100644 index dd4556d2f5..0000000000 --- a/corelib/src/num/traits/ops/checked.cairo +++ /dev/null @@ -1,123 +0,0 @@ -//! Safe arithmetic operations with overflow/underflow checking. -//! -//! This module provides traits for performing arithmetic operations with explicit -//! overflow and underflow protection. These operations return `None` when an overflow -//! or underflow occurs, allowing you to handle these cases gracefully without panicking. -//! -//! # Examples -//! -//! ``` -//! use core::num::traits::{CheckedAdd, CheckedSub, CheckedMul}; -//! -//! // Checked addition -//! let a: u8 = 1; -//! assert!(a.checked_add(2) == Some(3)); -//! assert!(a.checked_add(255) == None); // Overflow -//! -//! // Checked subtraction -//! let b: u8 = 1; -//! assert!(b.checked_sub(1) == Some(0)); -//! assert!(b.checked_sub(2) == None); // Underflow -//! -//! // Checked multiplication -//! let c: u8 = 10; -//! assert!(c.checked_mul(20) == Some(200)); -//! assert!(c.checked_mul(30) == None); // Overflow -//! ``` - -/// Performs addition that returns `None` instead of wrapping around on -/// overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::CheckedAdd; -/// -/// let result = 1_u8.checked_add(2); -/// assert!(result == Some(3)); -/// -/// let result = 255_u8.checked_add(1); -/// assert!(result == None); // Overflow -/// ``` -pub trait CheckedAdd { - /// Adds two numbers, checking for overflow. If overflow happens, `None` is - /// returned. - fn checked_add(self: T, v: T) -> Option; -} - -/// Performs subtraction that returns `None` instead of wrapping around on underflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::CheckedSub; -/// -/// let result = 1_u8.checked_sub(1); -/// assert!(result == Some(0)); -/// -/// let result = 1_u8.checked_sub(2); -/// assert!(result == None); // Underflow -/// ``` -pub trait CheckedSub { - /// Subtracts two numbers, checking for underflow. If underflow happens, - /// `None` is returned. - fn checked_sub(self: T, v: T) -> Option; -} - -/// Performs multiplication that returns `None` instead of wrapping around on underflow or -/// overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::CheckedMul; -/// -/// let result = 10_u8.checked_mul(20); -/// assert!(result == Some(200)); -/// -/// let result = 10_u8.checked_mul(30); -/// assert!(result == None); // Overflow -/// ``` -pub trait CheckedMul { - /// Multiplies two numbers, checking for underflow or overflow. If underflow - /// or overflow happens, `None` is returned. - fn checked_mul(self: T, v: T) -> Option; -} - -pub(crate) mod overflow_based { - pub(crate) impl TCheckedAdd< - T, +Drop, +crate::num::traits::OverflowingAdd, - > of crate::num::traits::CheckedAdd { - fn checked_add(self: T, v: T) -> Option { - let (result, overflow) = self.overflowing_add(v); - match overflow { - true => None, - false => Some(result), - } - } - } - - pub(crate) impl TCheckedSub< - T, +Drop, +crate::num::traits::OverflowingSub, - > of crate::num::traits::CheckedSub { - fn checked_sub(self: T, v: T) -> Option { - let (result, overflow) = self.overflowing_sub(v); - match overflow { - true => None, - false => Some(result), - } - } - } - - pub(crate) impl TCheckedMul< - T, +Drop, +crate::num::traits::OverflowingMul, - > of crate::num::traits::CheckedMul { - fn checked_mul(self: T, v: T) -> Option { - let (result, overflow) = self.overflowing_mul(v); - match overflow { - true => None, - false => Some(result), - } - } - } -} diff --git a/corelib/src/num/traits/ops/divrem.cairo b/corelib/src/num/traits/ops/divrem.cairo deleted file mode 100644 index 39fea46e34..0000000000 --- a/corelib/src/num/traits/ops/divrem.cairo +++ /dev/null @@ -1,69 +0,0 @@ -use crate::zeroable::NonZero; - -/// Performs truncated division **and** remainder. -/// -/// `T` – dividend type (left-hand operand) -/// `U` – divisor type (right-hand operand, must be wrapped in -/// [`NonZero`](core::num::non_zero::NonZero) at call-site) -/// -/// The division truncates toward zero, like Cairo’s `/` and `%`. -/// -/// # Associated types -/// * [`Quotient`] – the type produced by the division -/// * [`Remainder`] – the type produced by the modulo -/// -/// # Examples -/// -/// Identical operand types: -/// ```cairo -/// use core::traits::{DivRem, NonZero}; -/// -/// let lhs: u32 = 7; -/// let rhs: NonZero = 3.try_into().unwrap(); -/// assert!(DivRem::::div_rem(lhs, rhs) == (2, 1)); -/// ``` -/// -/// Heterogeneous division (`u256` by `u128`): -/// ```cairo -/// use core::traits::DivRem; -/// use integer::u256_as_non_zero; -/// -/// let big: u256 = 1_000_000; // dividend -/// let nz10: NonZero = u256_as_non_zero(10_u128.into()); // divisor -/// -/// let (q, r) = DivRem::::div_rem(big, nz10); -/// // q : u256, r : u128 -/// ``` -pub trait DivRem { - /// Quotient returned by the division. - type Quotient; - - /// Remainder returned by the modulo operation. - type Remainder; - - /// Computes both `/` and `%` in a single pass. - fn div_rem(self: T, other: NonZero) -> (Self::Quotient, Self::Remainder); -} - -// Compatibility bridge: DivRem → DivRemGeneric -mod by_divrem_legacy { - /// Generic adapter: if the old symmetric `DivRem` exists, - /// provide the corresponding `DivRemGeneric` implementation. - pub impl Impl> of super::DivRem { - type Quotient = T; - type Remainder = T; - - fn div_rem(self: T, other: NonZero) -> (T, T) { - core::traits::DivRem::::div_rem(self, other) - } - } -} - -// Instantiate the generic adapter for every concrete integer type -// that already has a symmetric `DivRem` implementation. -impl DivRemU8 = by_divrem_legacy::Impl; -impl DivRemU16 = by_divrem_legacy::Impl; -impl DivRemU32 = by_divrem_legacy::Impl; -impl DivRemU64 = by_divrem_legacy::Impl; -impl DivRemU128 = by_divrem_legacy::Impl; -impl DivRemU256 = by_divrem_legacy::Impl; diff --git a/corelib/src/num/traits/ops/overflowing.cairo b/corelib/src/num/traits/ops/overflowing.cairo deleted file mode 100644 index f3e54cc295..0000000000 --- a/corelib/src/num/traits/ops/overflowing.cairo +++ /dev/null @@ -1,58 +0,0 @@ -//! Arithmetic operations with overflow detection. -//! -//! This module provides traits for performing arithmetic operations that explicitly -//! track potential numeric overflow conditions. - -/// Performs addition with a flag for overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::OverflowingAdd; -/// -/// let (result, is_overflow) = 1_u8.overflowing_add(255_u8); -/// assert!(result == 0); -/// assert!(is_overflow); -/// ``` -pub trait OverflowingAdd { - /// Returns a tuple of the sum along with a boolean indicating whether an arithmetic overflow - /// would occur. - /// If an overflow would have occurred then the wrapped value is returned. - fn overflowing_add(self: T, v: T) -> (T, bool); -} - -/// Performs subtraction with a flag for overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::OverflowingSub; -/// -/// let (result, is_underflow) = 1_u8.overflowing_sub(2_u8); -/// assert!(result == 255); -/// assert!(is_underflow); -/// ``` -pub trait OverflowingSub { - /// Returns a tuple of the difference along with a boolean indicating whether an arithmetic - /// overflow would occur. - /// If an overflow would have occurred then the wrapped value is returned. - fn overflowing_sub(self: T, v: T) -> (T, bool); -} - -/// Performs multiplication with a flag for overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::OverflowingMul; -/// -/// let (result, is_overflow) = 1_u8.overflowing_mul(2_u8); -/// assert!(result == 2); -/// assert!(!is_overflow); -/// ``` -pub trait OverflowingMul { - /// Returns a tuple of the product along with a boolean indicating whether an arithmetic - /// overflow would occur. - /// If an overflow would have occurred then the wrapped value is returned. - fn overflowing_mul(self: T, v: T) -> (T, bool); -} diff --git a/corelib/src/num/traits/ops/pow.cairo b/corelib/src/num/traits/ops/pow.cairo deleted file mode 100644 index 3645f630c1..0000000000 --- a/corelib/src/num/traits/ops/pow.cairo +++ /dev/null @@ -1,122 +0,0 @@ -//! Trait and implementations for raising a value to a power. -//! -//! This module provides efficient exponentiation operations for numeric types using -//! the square-and-multiply algorithm, which achieves logarithmic time complexity O(log n). - -/// Raises a value to the power of `exp`. -/// -/// Note that `0⁰` (`pow(0, 0)`) returns `1`. Mathematically this is undefined. -/// -/// # Panics -/// -/// Panics if the result of the exponentiation operation overflows the output type. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::Pow; -/// -/// assert!(2_i8.pow(4_usize) == 16_i8); -/// assert!(6_u8.pow(3_usize) == 216_u8); -/// assert!(0_u8.pow(0_usize) == 1_u8); -/// ``` -pub trait Pow { - /// The type of the result of the power calculation. - type Output; - - /// Returns `self` to the power `exp`. - fn pow(self: Base, exp: Exp) -> Self::Output; -} - -mod mul_based { - /// Helper to implement const pow fns. - trait ConstPowHelper { - const fn one() -> T; - const fn mul(lhs: T, rhs: T) -> T; - } - - /// Square-and-multiply implementation for `Pow`. - pub impl PowByMul, +Copy, +Drop> of super::Pow { - type Output = T; - - const fn pow(self: T, exp: usize) -> T { - if exp == 0 { - H::one() - } else { - pow_non_zero_exp(self, exp) - } - } - } - - /// Equivalent of `PowByMul::pow` but assumes `exp` is non-zero. - const fn pow_non_zero_exp, +Copy, +Drop>( - base: T, exp: usize, - ) -> T { - let (tail_exp, head_exp) = DivRem::div_rem(exp, 2); - if head_exp == 0 { - pow_non_zero_exp(H::mul(base, base), tail_exp) - } else { - pow_given_sqrt_base(base, tail_exp, base) - } - } - - /// Returns `(sqrt_base * sqrt_base).pow(exp) * acc`. - /// - /// Receives the square root of the base to avoid overflow if the squaring is not required for - /// the calculation (mostly when `exp` is 0). - const fn pow_given_sqrt_base, +Copy, +Drop>( - sqrt_base: T, exp: usize, acc: T, - ) -> T { - if exp == 0 { - acc - } else { - let (tail_exp, head_exp) = DivRem::div_rem(exp, 2); - let base = H::mul(sqrt_base, sqrt_base); - if head_exp == 0 { - H::mul(pow_non_zero_exp(H::mul(base, base), tail_exp), acc) - } else { - pow_given_sqrt_base(base, tail_exp, H::mul(base, acc)) - } - } - } - - /// Macro for generating an implementation for `ConstPowHelper`. - /// Not using a trait for the implementation to allow `fn` to be `const`. - macro impl_const_pow_helper { - ($impl_name: ident, $ty: ident) => { - impl $impl_name of $defsite::ConstPowHelper<$ty> { - const fn one() -> $ty { - 1 - } - const fn mul(lhs: $ty, rhs: $ty) -> $ty { - lhs * rhs - } - } - }; - } - impl_const_pow_helper!(ConstPowHelperFelt252, felt252); - impl_const_pow_helper!(ConstPowHelperI8, i8); - impl_const_pow_helper!(ConstPowHelperU8, u8); - impl_const_pow_helper!(ConstPowHelperI16, i16); - impl_const_pow_helper!(ConstPowHelperU16, u16); - impl_const_pow_helper!(ConstPowHelperI32, i32); - impl_const_pow_helper!(ConstPowHelperU32, u32); - impl_const_pow_helper!(ConstPowHelperI64, i64); - impl_const_pow_helper!(ConstPowHelperU64, u64); - impl_const_pow_helper!(ConstPowHelperI128, i128); - impl_const_pow_helper!(ConstPowHelperU128, u128); - impl_const_pow_helper!(ConstPowHelperU256, u256); -} - -impl PowFelt252 = mul_based::PowByMul; -impl PowI8 = mul_based::PowByMul; -impl PowU8 = mul_based::PowByMul; -impl PowI16 = mul_based::PowByMul; -impl PowU16 = mul_based::PowByMul; -impl PowI32 = mul_based::PowByMul; -impl PowU32 = mul_based::PowByMul; -impl PowI64 = mul_based::PowByMul; -impl PowU64 = mul_based::PowByMul; -impl PowI128 = mul_based::PowByMul; -impl PowU128 = mul_based::PowByMul; -impl PowU256 = mul_based::PowByMul; diff --git a/corelib/src/num/traits/ops/saturating.cairo b/corelib/src/num/traits/ops/saturating.cairo deleted file mode 100644 index 97c40cd1b9..0000000000 --- a/corelib/src/num/traits/ops/saturating.cairo +++ /dev/null @@ -1,87 +0,0 @@ -//! Saturating arithmetic operations for numeric types. -//! -//! This module provides traits and implementations for arithmetic operations -//! that saturate at the numeric type's boundaries instead of overflowing. - -/// Performs addition that saturates at the numeric bounds instead of overflowing. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::SaturatingAdd; -/// -/// assert!(255_u8.saturating_add(1_u8) == 255); -/// ``` -pub trait SaturatingAdd { - /// Saturating addition. Computes `self + other`, saturating at the relevant high or low - /// boundary of the type. - fn saturating_add(self: T, other: T) -> T; -} - -/// Performs subtraction that saturates at the numeric bounds instead of overflowing. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::SaturatingSub; -/// -/// assert!(1_u8.saturating_sub(2_u8) == 0); -/// ``` -pub trait SaturatingSub { - /// Saturating subtraction. Computes `self - other`, saturating at the relevant high or low - /// boundary of the type. - fn saturating_sub(self: T, other: T) -> T; -} - -/// Performs multiplication that saturates at the numeric bounds instead of overflowing. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::SaturatingMul; -/// -/// assert!(100_u8.saturating_mul(3_u8) == 255); -/// ``` -pub trait SaturatingMul { - /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low - /// boundary of the type. - fn saturating_mul(self: T, other: T) -> T; -} - -pub(crate) mod overflow_based { - pub(crate) impl TSaturatingAdd< - T, +Drop, +crate::num::traits::OverflowingAdd, +crate::num::traits::Bounded, - > of crate::num::traits::SaturatingAdd { - fn saturating_add(self: T, other: T) -> T { - let (result, overflow) = self.overflowing_add(other); - match overflow { - true => crate::num::traits::Bounded::MAX, - false => result, - } - } - } - - pub(crate) impl TSaturatingSub< - T, +Drop, +crate::num::traits::OverflowingSub, +crate::num::traits::Bounded, - > of crate::num::traits::SaturatingSub { - fn saturating_sub(self: T, other: T) -> T { - let (result, overflow) = self.overflowing_sub(other); - match overflow { - true => crate::num::traits::Bounded::MIN, - false => result, - } - } - } - - pub(crate) impl TSaturatingMul< - T, +Drop, +crate::num::traits::OverflowingMul, +crate::num::traits::Bounded, - > of crate::num::traits::SaturatingMul { - fn saturating_mul(self: T, other: T) -> T { - let (result, overflow) = self.overflowing_mul(other); - match overflow { - true => crate::num::traits::Bounded::MAX, - false => result, - } - } - } -} diff --git a/corelib/src/num/traits/ops/split.cairo b/corelib/src/num/traits/ops/split.cairo deleted file mode 100644 index ebce3a54c3..0000000000 --- a/corelib/src/num/traits/ops/split.cairo +++ /dev/null @@ -1,49 +0,0 @@ -//! Split a numeric value into halves for unsigned numeric types. - -/// A trait for computing the split in bits of a number into halves. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::Split; -/// -/// assert!(0x908_u16.split() == (9, 8)); -/// ``` -pub trait Split { - /// The type of the result of the split operation. - type Half; - /// Computes the halving of the value. - fn split(self: T) -> (Self::Half, Self::Half); -} - -mod internal { - #[feature("bounded-int-utils")] - use crate::internal::bounded_int::{BoundedInt, DivRemHelper, UnitInt, div_rem, upcast}; - - impl Helper< - Full, const BOUND: felt252, const DIV: felt252, - > of DivRemHelper> { - type DivT = BoundedInt<0, BOUND>; - type RemT = BoundedInt<0, BOUND>; - } - - pub impl Impl< - Full, - Half, - const BOUND: felt252, - const DIV: felt252, - const DIV_VALUE: NonZero>, - > of super::Split { - type Half = Half; - fn split(self: Full) -> (Half, Half) { - let (high, low) = div_rem::>(self, DIV_VALUE); - (upcast(high), upcast(low)) - } - } -} - -impl U16Split = internal::Impl; -impl U32Split = internal::Impl; -impl U64Split = internal::Impl; -impl U128Split = - internal::Impl; diff --git a/corelib/src/num/traits/ops/sqrt.cairo b/corelib/src/num/traits/ops/sqrt.cairo deleted file mode 100644 index d15e1fe4a1..0000000000 --- a/corelib/src/num/traits/ops/sqrt.cairo +++ /dev/null @@ -1,59 +0,0 @@ -//! Square root operation for unsigned numeric types. - -/// A trait for computing the square root of a number. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::Sqrt; -/// -/// assert!(9_u8.sqrt() == 3); -/// ``` -pub trait Sqrt { - /// The type of the result of the square root operation. - type Target; - /// Computes the square root of a number. - fn sqrt(self: T) -> Self::Target; -} - -impl SqrtU8 of Sqrt { - type Target = u8; - fn sqrt(self: u8) -> u8 { - crate::integer::u8_sqrt(self) - } -} - -impl SqrtU16 of Sqrt { - type Target = u8; - fn sqrt(self: u16) -> u8 { - crate::integer::u16_sqrt(self) - } -} - -impl SqrtU32 of Sqrt { - type Target = u16; - fn sqrt(self: u32) -> u16 { - crate::integer::u32_sqrt(self) - } -} - -impl SqrtU64 of Sqrt { - type Target = u32; - fn sqrt(self: u64) -> u32 { - crate::integer::u64_sqrt(self) - } -} - -impl SqrtU128 of Sqrt { - type Target = u64; - fn sqrt(self: u128) -> u64 { - crate::integer::u128_sqrt(self) - } -} - -impl SqrtU256 of Sqrt { - type Target = u128; - fn sqrt(self: u256) -> u128 { - crate::integer::u256_sqrt(self) - } -} diff --git a/corelib/src/num/traits/ops/widemul.cairo b/corelib/src/num/traits/ops/widemul.cairo deleted file mode 100644 index ffef525514..0000000000 --- a/corelib/src/num/traits/ops/widemul.cairo +++ /dev/null @@ -1,132 +0,0 @@ -//! Trait for performing multiplication that results in a wider type. -//! -//! This module provides the [`WideMul`] trait which enables multiplication operations -//! that return a result type with double the bit width of the input types. -//! This is particularly useful when you need to perform multiplication without -//! worrying about overflow, as the result type can hold the full range of possible values. -//! -//! # Examples -//! -//! ``` -//! use core::num::traits::WideMul; -//! -//! // Multiplying two `u8` values to get a `u16` result -//! let a: u8 = 200; -//! let b: u8 = 100; -//! let result: u16 = a.wide_mul(b); -//! assert!(result == 20000); -//! -//! // Multiplying two `u128` values to get a `u256` result -//! let x: u128 = 0xffffffffffffffffffffffffffffffff; // max u128 -//! let y: u128 = 2; -//! let wide_result = x.wide_mul(y); // No overflow occurs -//! assert!(wide_result == 0x01fffffffffffffffffffffffffffffffe); -//! ``` -//! -//! # Available Implementations -//! -//! The trait is implemented for the following type pairs: -//! - `i8` → `i16` -//! - `i16` → `i32` -//! - `i32` → `i64` -//! - `i64` → `i128` -//! - `u8` → `u16` -//! - `u16` → `u32` -//! - `u32` → `u64` -//! - `u64` → `u128` -//! - `u128` → `u256` -//! - `u256` → `u512` - -/// A trait for types that can be multiplied together to produce a wider type. -/// -/// This trait enables multiplication operations where the result type has double -/// the bit width of the input types, preventing overflow in cases where the -/// result would exceed the input type's maximum value. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::WideMul; -/// -/// let a: u8 = 255; // maximum value for u8 -/// let b: u8 = 255; -/// let result: u16 = a.wide_mul(b); -/// assert!(result == 65025); -/// ``` -pub trait WideMul { - /// The type of the result of the multiplication. - type Target; - /// Multiply two values together, producing a wider type. - fn wide_mul(self: Lhs, other: Rhs) -> Self::Target; -} - -impl WideMulI8 of WideMul { - type Target = i16; - fn wide_mul(self: i8, other: i8) -> i16 { - crate::integer::i8_wide_mul(self, other) - } -} - -impl WideMulI16 of WideMul { - type Target = i32; - fn wide_mul(self: i16, other: i16) -> i32 { - crate::integer::i16_wide_mul(self, other) - } -} - -impl WideMulI32 of WideMul { - type Target = i64; - fn wide_mul(self: i32, other: i32) -> i64 { - crate::integer::i32_wide_mul(self, other) - } -} - -impl WideMulI64 of WideMul { - type Target = i128; - fn wide_mul(self: i64, other: i64) -> i128 { - crate::integer::i64_wide_mul(self, other) - } -} - -impl WideMulU8 of WideMul { - type Target = u16; - fn wide_mul(self: u8, other: u8) -> u16 { - crate::integer::u8_wide_mul(self, other) - } -} - -impl WideMulU16 of WideMul { - type Target = u32; - fn wide_mul(self: u16, other: u16) -> u32 { - crate::integer::u16_wide_mul(self, other) - } -} - -impl WideMulU32 of WideMul { - type Target = u64; - fn wide_mul(self: u32, other: u32) -> u64 { - crate::integer::u32_wide_mul(self, other) - } -} - -impl WideMulU64 of WideMul { - type Target = u128; - fn wide_mul(self: u64, other: u64) -> u128 { - crate::integer::u64_wide_mul(self, other) - } -} - -impl WideMulU128 of WideMul { - type Target = u256; - fn wide_mul(self: u128, other: u128) -> u256 { - let (high, low) = crate::integer::u128_wide_mul(self, other); - u256 { low, high } - } -} - -impl WideMulU256 of WideMul { - type Target = crate::integer::u512; - fn wide_mul(self: u256, other: u256) -> crate::integer::u512 { - crate::integer::u256_wide_mul(self, other) - } -} diff --git a/corelib/src/num/traits/ops/widesquare.cairo b/corelib/src/num/traits/ops/widesquare.cairo deleted file mode 100644 index bf865d1f54..0000000000 --- a/corelib/src/num/traits/ops/widesquare.cairo +++ /dev/null @@ -1,113 +0,0 @@ -//! Wide square operation. -//! -//! This module provides the [`WideSquare`] trait which enables squaring operations -//! that return a result type with double the bit width of the input type. -//! This is particularly useful when you need to square a number without -//! worrying about overflow, as the result type can hold the full range of possible values. -//! -//! # Examples -//! -//! ``` -//! use core::num::traits::WideSquare; -//! -//! // Squaring a `u8` value to get a `u16` result -//! let a: u8 = 200; -//! let result: u16 = a.wide_square(); -//! assert!(result == 40000); -//! -//! // Squaring a `u128` value to get a `u256` result -//! let x: u128 = 0xffffffffffffffffffffffffffffffff; // max u128 -//! let wide_result: u256 = x.wide_square(); // No overflow occurs -//! assert!(wide_result == 0xfffffffffffffffffffffffffffffffe00000000000000000000000000000001); -//! ``` -//! -//! # Available Implementations -//! -//! The trait is implemented for the following type pairs: -//! - `i8` → `i16` -//! - `i16` → `i32` -//! - `i32` → `i64` -//! - `i64` → `i128` -//! - `u8` → `u16` -//! - `u16` → `u32` -//! - `u32` → `u64` -//! - `u64` → `u128` -//! - `u128` → `u256` -//! - `u256` → `u512` - -use crate::num::traits::WideMul; - -/// A trait for a type that can be squared to produce a wider type. -/// -/// This trait enables squaring operations where the result type has double -/// the bit width of the input type, preventing overflow in cases where the -/// result would exceed the input type's maximum value. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::WideSquare; -/// -/// let a: u8 = 16; -/// let result: u16 = a.wide_square(); -/// assert!(result == 256); -/// ``` -pub trait WideSquare { - /// The type of the result of the square. - type Target; - /// Calculates the square, producing a wider type. - fn wide_square(self: T) -> Self::Target; -} - -mod wide_mul_based { - pub impl TWideSquare, +Copy> of super::WideSquare { - type Target = TWideMul::Target; - fn wide_square(self: T) -> Self::Target { - TWideMul::wide_mul(self, self) - } - } -} - -impl WideSquareI8 = wide_mul_based::TWideSquare; -impl WideSquareI16 = wide_mul_based::TWideSquare; -impl WideSquareI32 = wide_mul_based::TWideSquare; -impl WideSquareI64 = wide_mul_based::TWideSquare; -impl WideSquareU8 = wide_mul_based::TWideSquare; -impl WideSquareU16 = wide_mul_based::TWideSquare; -impl WideSquareU32 = wide_mul_based::TWideSquare; -impl WideSquareU64 = wide_mul_based::TWideSquare; -impl WideSquareU128 = wide_mul_based::TWideSquare; -impl WideSquareU256 of WideSquare { - type Target = crate::integer::u512; - fn wide_square(self: u256) -> Self::Target { - inner::u256_wide_square(self) - } -} - -#[feature("bounded-int-utils")] -mod inner { - use crate::integer::{u128_add_with_bounded_int_carry, u512}; - use crate::internal::bounded_int; - use crate::num::traits::{WideMul, WideSquare, WrappingAdd}; - - pub fn u256_wide_square(value: u256) -> u512 { - let u256 { high: limb1, low: limb0 } = value.low.wide_square(); - let u256 { high: limb2, low: limb1_part } = value.low.wide_mul(value.high); - let (limb1, limb1_overflow0) = u128_add_with_bounded_int_carry(limb1, limb1_part); - let (limb1, limb1_overflow1) = u128_add_with_bounded_int_carry(limb1, limb1_part); - let (limb2, limb2_overflow0) = u128_add_with_bounded_int_carry(limb2, limb2); - let u256 { high: limb3, low: limb2_part } = value.high.wide_square(); - let (limb2, limb2_overflow1) = u128_add_with_bounded_int_carry(limb2, limb2_part); - // Packing together the overflow bits, making a cheaper addition into limb2. - let limb1_overflow = bounded_int::add(limb1_overflow0, limb1_overflow1); - let (limb2, limb2_overflow2) = u128_add_with_bounded_int_carry( - limb2, bounded_int::upcast(limb1_overflow), - ); - // Packing together the overflow bits, making a cheaper addition into limb3. - let limb2_overflow = bounded_int::add(limb2_overflow0, limb2_overflow1); - let limb2_overflow = bounded_int::add(limb2_overflow, limb2_overflow2); - // No overflow since no limb4. - let limb3 = limb3.wrapping_add(bounded_int::upcast(limb2_overflow)); - u512 { limb0, limb1, limb2, limb3 } - } -} diff --git a/corelib/src/num/traits/ops/wrapping.cairo b/corelib/src/num/traits/ops/wrapping.cairo deleted file mode 100644 index 2fd274c65a..0000000000 --- a/corelib/src/num/traits/ops/wrapping.cairo +++ /dev/null @@ -1,112 +0,0 @@ -//! Arithmetic operations with overflow and underflow wrapping. -//! -//! This module provides traits for performing arithmetic operations that wrap around at the -//! boundary of the type in case of overflow or underflow. This is particularly useful when you want -//! to: -//! - Perform arithmetic operations without panicking on overflow/underflow -//! - Implement modular arithmetic -//! - Handle cases where overflow is expected and desired -//! -//! # Examples -//! -//! ``` -//! use core::num::traits::{WrappingAdd, WrappingSub, WrappingMul}; -//! -//! // Addition wrapping -//! let a: u8 = 255; -//! assert!(a.wrapping_add(1) == 0); -//! -//! // Subtraction wrapping -//! let b: u8 = 0; -//! assert!(b.wrapping_sub(1) == 255); -//! -//! // Multiplication wrapping -//! let c: u8 = 200; -//! assert!(c.wrapping_mul(2) == 144); // (200 * 2) % 256 = 144 -//! ``` - -/// Performs addition that wraps around on overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::WrappingAdd; -/// -/// let result = 255_u8.wrapping_add(1); -/// assert!(result == 0); -/// -/// let result = 100_u8.wrapping_add(200); -/// assert!(result == 44); // (100 + 200) % 256 = 44 -/// ``` -pub trait WrappingAdd { - /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of the - /// type. - fn wrapping_add(self: T, v: T) -> T; -} - -/// Performs subtraction that wraps around on overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::WrappingSub; -/// -/// let result = 0_u8.wrapping_sub(1); -/// assert!(result == 255); -/// -/// let result = 100_u8.wrapping_sub(150); -/// assert!(result == 206); -/// ``` -pub trait WrappingSub { - /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary of - /// the type. - fn wrapping_sub(self: T, v: T) -> T; -} - -/// Performs multiplication that wraps around on overflow. -/// -/// # Examples -/// -/// ``` -/// use core::num::traits::WrappingMul; -/// -/// let result = 10_u8.wrapping_mul(30); -/// assert!(result == 44); // (10 * 30) % 256 = 44 -/// -/// let result = 200_u8.wrapping_mul(2); -/// assert!(result == 144); // (200 * 2) % 256 = 144 -/// ``` -pub trait WrappingMul { - /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary - /// of the type. - fn wrapping_mul(self: T, v: T) -> T; -} - -pub(crate) mod overflow_based { - pub(crate) impl TWrappingAdd< - T, +crate::num::traits::OverflowingAdd, - > of crate::num::traits::WrappingAdd { - fn wrapping_add(self: T, v: T) -> T { - let (result, _) = self.overflowing_add(v); - result - } - } - - pub(crate) impl TWrappingSub< - T, +crate::num::traits::OverflowingSub, - > of crate::num::traits::WrappingSub { - fn wrapping_sub(self: T, v: T) -> T { - let (result, _) = self.overflowing_sub(v); - result - } - } - - pub(crate) impl TWrappingMul< - T, +crate::num::traits::OverflowingMul, - > of crate::num::traits::WrappingMul { - fn wrapping_mul(self: T, v: T) -> T { - let (result, _) = self.overflowing_mul(v); - result - } - } -} diff --git a/corelib/src/num/traits/zero.cairo b/corelib/src/num/traits/zero.cairo deleted file mode 100644 index 4bb1d40ac3..0000000000 --- a/corelib/src/num/traits/zero.cairo +++ /dev/null @@ -1,46 +0,0 @@ -//! Traits for types with an additive identity element. - -/// Defines an additive identity element for `T`. -/// -/// # Laws -/// -/// ```text -/// a + 0 = a ∀ a ∈ T -/// 0 + a = a ∀ a ∈ T -/// ``` -pub trait Zero { - /// Returns the additive identity element of `T`, `0`. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::Zero; - /// - /// assert!(Zero::::zero() == 0); - /// ``` - fn zero() -> T; - - /// Returns true if `self` is equal to the additive identity. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::Zero; - /// - /// assert!(0.is_zero()); - /// assert!(!5.is_zero()); - /// ``` - fn is_zero(self: @T) -> bool; - - /// Returns false if `self` is equal to the additive identity. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::Zero; - /// - /// assert!(5.is_non_zero()); - /// assert!(!0.is_non_zero()); - /// ``` - fn is_non_zero(self: @T) -> bool; -} diff --git a/corelib/src/ops.cairo b/corelib/src/ops.cairo deleted file mode 100644 index 32cde97f6a..0000000000 --- a/corelib/src/ops.cairo +++ /dev/null @@ -1,80 +0,0 @@ -//! Overloadable operators. -//! -//! Implementing these traits allows you to overload certain operators. -//! -//! > Note: Other overloadable operators are also defined in the [`core::traits`] module. -//! -//! Only operators backed by traits can be overloaded. For -//! example, the addition assignment operator (`+=`) can be overloaded through the [`AddAssign`] -//! trait, but since the assignment operator (`=`) has no backing trait, there -//! is no way of overloading its semantics. Additionally, this module does not -//! provide any mechanism to create new operators. -//! -//! Implementations of operator traits should be unsurprising in their -//! respective contexts, keeping in mind their usual meanings and -//! operator precedence. For example, when implementing [`MulAssign`], the operation -//! should have some resemblance to multiplication assignment. -//! -//! # Examples -//! -//! This example creates a `Point` struct that implements [`AddAssign`] and [`SubAssign`], -//! and then demonstrates adding and subtracting two `Point`s to themselves. -//! -//! ``` -//! use core::ops::{AddAssign, SubAssign}; -//! -//! #[derive(Debug, Drop, Copy, PartialEq)] -//! struct Point { -//! x: i32, -//! y: i32, -//! } -//! -//! impl AddAssignImpl of AddAssign { -//! fn add_assign(ref self: Point, rhs: Point) { -//! self = Point { x: self.x + rhs.x, y: self.y + rhs.y } -//! } -//! } -//! -//! impl SubAssignImpl of SubAssign { -//! fn sub_assign(ref self: Point, rhs: Point) { -//! self = Point { x: self.x - rhs.x, y: self.y - rhs.y } -//! } -//! } -//! -//! fn main() { -//! let mut point = Point {x : 3, y: 4}; -//! point += point; -//! assert!(point == Point {x: 6, y: 8}); -//! point -= point; -//! assert!(point == Point {x: 0, y: 0}); -//! } -//! ``` -//! -//! See the documentation for each trait for an example implementation. - -mod arith; -pub use arith::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; - -mod deref; -pub use deref::Deref; -#[feature("deref_mut")] -pub use deref::DerefMut; - -mod function; -pub use function::{Fn, FnOnce}; - -pub mod index; -pub use index::{Index, IndexView}; - -mod range; -pub use range::{ - Range, RangeInclusive, RangeInclusiveIterator, RangeInclusiveTrait, RangeIterator, RangeTrait, -}; -// `RangeOp` and `RangeInclusiveOp` are used internally by the compiler. -#[allow(unused_imports)] -use range::{RangeInclusiveOp, RangeOp}; - -#[unstable(feature: "corelib-get-trait")] -pub mod get; -#[feature("corelib-get-trait")] -pub use get::Get; diff --git a/corelib/src/ops/arith.cairo b/corelib/src/ops/arith.cairo deleted file mode 100644 index e7c4506437..0000000000 --- a/corelib/src/ops/arith.cairo +++ /dev/null @@ -1,107 +0,0 @@ -//! Assignment operator traits for arithmetic operations. -//! -//! This module provides traits for implementing assignment operators like `+=`, `-=`, -//! `*=`, `/=` and `%=`. These traits allow types to define how they handle -//! arithmetic operations that modify values in place. - -/// The addition assignment operator `+=`. -pub trait AddAssign { - /// Performs the `+=` operation. - /// - /// # Examples - /// - /// ``` - /// let mut x: u8 = 3; - /// x += x; - /// assert!(x == 6); - /// ``` - fn add_assign(ref self: Lhs, rhs: Rhs); -} - -/// The subtraction assignment operator `-=`. -pub trait SubAssign { - /// Performs the `-=` operation. - /// - /// # Examples - /// - /// ``` - /// let mut x: u8 = 3; - /// x -= x; - /// assert!(x == 0); - /// ``` - fn sub_assign(ref self: Lhs, rhs: Rhs); -} - -/// The multiplication assignment operator `*=`. -pub trait MulAssign { - /// Performs the `*=` operation. - /// - /// # Examples - /// - /// ``` - /// let mut x: u8 = 3; - /// x *= x; - /// assert!(x == 9); - /// ``` - fn mul_assign(ref self: Lhs, rhs: Rhs); -} - -/// The division assignment operator `/=`. -pub trait DivAssign { - /// Performs the `/=` operation. - /// - /// # Examples - /// - /// ``` - /// let mut x: u8 = 3; - /// x /= x; - /// assert!(x == 1); - /// ``` - fn div_assign(ref self: Lhs, rhs: Rhs); -} - -/// The remainder assignment operator `%=`. -pub trait RemAssign { - /// Performs the `%=` operation. - /// - /// # Examples - /// - /// ``` - /// let mut x: u8 = 3; - /// x %= x; - /// assert!(x == 0); - /// ``` - fn rem_assign(ref self: Lhs, rhs: Rhs); -} -#[feature("deprecated-op-assign-traits")] -use crate::traits::{AddEq, DivEq, MulEq, RemEq, SubEq}; - -impl DeprecatedAddAssign> of AddAssign { - fn add_assign(ref self: T, rhs: T) { - Deprecated::add_eq(ref self, rhs) - } -} - -impl DeprecatedSubAssign> of SubAssign { - fn sub_assign(ref self: T, rhs: T) { - Deprecated::sub_eq(ref self, rhs) - } -} - -impl DeprecatedMulAssign> of MulAssign { - fn mul_assign(ref self: T, rhs: T) { - Deprecated::mul_eq(ref self, rhs) - } -} - -impl DeprecatedDivAssign> of DivAssign { - fn div_assign(ref self: T, rhs: T) { - Deprecated::div_eq(ref self, rhs) - } -} - -impl DeprecatedRemAssign> of RemAssign { - fn rem_assign(ref self: T, rhs: T) { - Deprecated::rem_eq(ref self, rhs) - } -} diff --git a/corelib/src/ops/deref.cairo b/corelib/src/ops/deref.cairo deleted file mode 100644 index c67ba96ee5..0000000000 --- a/corelib/src/ops/deref.cairo +++ /dev/null @@ -1,109 +0,0 @@ -//! Dereferencing traits for transparent access to wrapped values. -//! -//! This module provides traits that enable accessing the content of wrapped types -//! as if they were the inner type directly. This is particularly useful for: -//! -//! - Smart pointers and wrapper types (e.g., `Box`) -//! - Nested data structures -//! - Enum variants sharing common fields -//! -//! # Core Traits -//! -//! - [`Deref`]: Provides read-only access to the wrapped value -//! - [`DerefMut`]: Provides read-only access to the wrapped value in mutable contexts -//! -//! # Examples -//! -//! ``` -//! // Accessing nested struct fields through deref -//! #[derive(Drop, Copy)] -//! struct Inner { value: felt252 } -//! -//! #[derive(Drop, Copy)] -//! struct Outer { inner: Inner } -//! -//! impl OuterDeref of Deref { -//! type Target = Inner; -//! fn deref(self: Outer) -> Inner { self.inner } -//! } -//! -//! let outer = Outer { inner: Inner { value: 42 } }; -//! assert!(outer.value == 42); // Access Inner's field directly -//! ``` - -/// A trait for dereferencing a value to provide transparent access to its contents. -/// -/// Implementing this trait allows a type to behave like its inner type, enabling direct access to -/// the inner type's fields. -/// -/// Note: The `Deref` mechanism is limited and cannot be used to implicitly convert a type to its -/// target type when passing arguments to functions. For example, if you have a function that takes -/// an `Inner`, you cannot pass an `Outer` to it even if `Outer` implements `Deref`. -/// -/// # Examples -/// -/// ``` -/// struct Wrapper { inner: T } -/// -/// impl WrapperDeref of Deref> { -/// type Target = T; -/// fn deref(self: Wrapper) -> T { self.inner } -/// } -/// -/// let wrapped = Wrapper { inner: 42 }; -/// assert!(wrapped.deref() == 42); -/// ``` -pub trait Deref { - /// The type of the dereferenced value. - type Target; - /// Returns the dereferenced value. - fn deref(self: T) -> Self::Target; -} - -/// A trait for dereferencing in mutable contexts. -/// -/// This trait is similar to `Deref` but specifically handles cases where the value -/// accessed is mutable. Despite its name, `DerefMut` does NOT allow modifying the -/// inner value - it only indicates that the container itself is mutable. -/// -/// # Examples -/// -/// ``` -/// #[derive(Copy, Drop)] -/// struct MutWrapper { -/// value: T -/// } -/// -/// impl MutWrapperDerefMut> of DerefMut> { -/// type Target = T; -/// fn deref_mut(ref self: MutWrapper) -> T { -/// self.value -/// } -/// } -/// -/// // This will work since x is mutable -/// let mut x = MutWrapper { value: 42 }; -/// let val = x.deref_mut(); -/// assert!(val == 42); -/// -/// // This would fail to compile since y is not mutable -/// let y = MutWrapper { value: 42 }; -/// let val = y.deref_mut(); // Compile error -/// ``` -#[unstable(feature: "deref_mut")] -pub trait DerefMut { - /// The type of the dereferenced value. - type Target; - /// Returns the dereferenced value. - fn deref_mut(ref self: T) -> Self::Target; -} - -/// Implementation of `Deref` for copyable snapshots. -// TODO(Gil): This should not use the `*` operator as the `*` operator will later be calling -// `Deref`. -impl SnapshotTDeref> of Deref<@T> { - type Target = T; - fn deref(self: @T) -> Self::Target { - *self - } -} diff --git a/corelib/src/ops/function.cairo b/corelib/src/ops/function.cairo deleted file mode 100644 index 4719492bce..0000000000 --- a/corelib/src/ops/function.cairo +++ /dev/null @@ -1,113 +0,0 @@ -//! Function traits and types. -//! -//! This module defines traits for function-like types that can be called. -//! The two main traits are: -//! -//! * [`FnOnce`] - For single-use functions that consume their environment -//! * [`Fn`] - For reusable functions that can be called multiple times -//! -//! # Examples -//! -//! ``` -//! // Using Fn for a reusable operation -//! fn apply_twice, +core::ops::Fn[Output: u32]>(f: F, x: u32) -> u32 { -//! f(f(x)) -//! } -//! -//! let double = |x| x * 2; -//! assert!(apply_twice(double, 2) == 8); -//! ``` - -/// The version of the call operator that takes a by-value receiver. -/// -/// Instances of `FnOnce` can be called, but might not be callable multiple -/// times. Because of this, if the only thing known about a type is that it -/// implements `FnOnce`, it can only be called once. -/// -/// `FnOnce` is implemented automatically by closures that might consume captured -/// variables. -/// -/// ``` -/// # Examples -/// -/// fn consume_with_relish< -/// F, O, +Drop, +core::ops::FnOnce[Output: O], +core::fmt::Display, +Drop, -/// >( -/// func: F, -/// ) { -/// // `func` consumes its captured variables, so it cannot be run more -/// // than once. -/// println!("Consumed: {}", func()); -/// -/// println!("Delicious!"); -/// // Attempting to invoke `func()` again will throw a `Variable was previously moved.` -/// // error for `func`. -/// } -/// -/// let x: ByteArray = "x"; -/// let consume_and_return_x = || x; -/// consume_with_relish(consume_and_return_x); -/// // `consume_and_return_x` can no longer be invoked at this point -pub trait FnOnce { - /// The returned type after the call operator is used. - type Output; - /// Performs the call operation. - fn call(self: T, args: Args) -> Self::Output; -} - -/// An implementation of `FnOnce` when `Fn` is implemented. -/// Makes sure we can always pass an `Fn` to a function that expects an `FnOnce`. -impl FnOnceImpl, +Fn> of FnOnce { - type Output = Fn::::Output; - fn call(self: T, args: Args) -> Self::Output { - Fn::call(@self, args) - } -} - -/// The version of the call operator that takes a by-snapshot receiver. -/// -/// Instances of `Fn` can be called repeatedly. -/// -/// `Fn` is implemented automatically by closures whose captured variables are all `Copy`. -/// Additionally, for any type `F` that implements `Fn`, `@F` implements `Fn`, too. -/// -/// Since [`FnOnce`] is implemented for all implementers of `Fn`, any instance of `Fn` can be used -/// as a parameter where a [`FnOnce`] is expected. -/// -/// Use `Fn` as a bound when you want to accept a parameter of function-like type and need to call -/// it repeatedly. If you do not need such strict requirements, use [`FnOnce`] as bounds. -/// -/// # Examples -/// -/// ## Calling a closure -/// -/// ``` -/// let square = |x| x * x; -/// assert_eq!(square(5), 25); -/// ``` -/// -/// ## Using a `Fn` parameter -/// -/// ``` -/// fn call_with_one, +core::ops::Fn[Output: usize]>(func: F) -> usize { -/// func(1) -/// } -/// -/// let double = |x| x * 2; -/// assert_eq!(call_with_one(double), 2); -/// ``` -pub trait Fn { - /// The returned type after the call operator is used. - type Output; - /// Performs the call operation. - fn call(self: @T, args: Args) -> Self::Output; -} - -/// Implementation of `Fn` for snapshots. -/// This allows using a snapshot of a type that implements `Fn` as a function. -impl FnSnapshotImpl> of Fn<@T, Args> { - type Output = F::Output; - fn call(self: @@T, args: Args) -> Self::Output { - F::call(*self, args) - } -} diff --git a/corelib/src/ops/get.cairo b/corelib/src/ops/get.cairo deleted file mode 100644 index 793cd0f797..0000000000 --- a/corelib/src/ops/get.cairo +++ /dev/null @@ -1,46 +0,0 @@ -/// A trait for fallible indexing operations with different index types. -/// -/// Unlike [`IndexView`] and [`Index`] which panic on out-of-bounds access, `Get` -/// returns an `Option`, providing safe indexing operations. This trait enables containers -/// to support multiple index types (e.g., `Range`, `RangeInclusive`, -/// or `usize`) through a unified interface. -/// -/// [`IndexView`]: crate::ops::IndexView -/// [`Index`]: crate::ops::Index -/// -/// # Examples -/// -/// The following example shows how `ByteSpan` implements `Get` for `usize`, `Range`, -/// and `RangeInclusive`, enabling safe indexing and slicing operations that return `None` -/// when out of bounds. -/// -/// ``` -/// use core::byte_array::{ByteSpan, ByteSpanTrait}; -/// -/// let ba: ByteArray = "hello"; -/// let span = ba.span(); -/// -/// // Using usize. -/// let byte = span.get(1).unwrap(); -/// assert!(byte == 'e'); -/// -/// // Using Range. -/// let slice = span.get(1..4).unwrap(); -/// assert_eq!(slice.to_byte_array(), "ell"); -/// -/// // Using RangeInclusive. -/// let slice = span.get(1..=3).unwrap(); -/// assert_eq!(slice.to_byte_array(), "ell"); -/// -/// // Out of bounds returns None. -/// assert!(span.get(10).is_none()); -/// assert!(span.get(10..20).is_none()); -/// ``` -#[unstable(feature: "corelib-get-trait")] -pub trait Get { - /// The returned type after indexing. - type Output; - - /// Returns the output at this index, if in bounds. - fn get(self: @C, index: I) -> Option; -} diff --git a/corelib/src/ops/index.cairo b/corelib/src/ops/index.cairo deleted file mode 100644 index 60ad076bef..0000000000 --- a/corelib/src/ops/index.cairo +++ /dev/null @@ -1,166 +0,0 @@ -//! Indexing traits for indexing operations on collections. -//! -//! This module provides traits for implementing the indexing operator `[]`, offering two distinct -//! approaches to access elements in collections: -//! -//! * [`IndexView`] - For snapshot-based access -//! * [`Index`] - For reference-based access -//! -//! For safe indexing operations that return `Option`, see the unstable [`Get`] trait -//! in the [`get`] module. -//! -//! # When to use which trait -//! -//! - Use [`IndexView`] when the collection can be accessed in a read-only context and is not -//! mutated by a read access. This is the most common case in Cairo. -//! - Use [`Index`] when the input type needs to be passed as `ref`. This is mainly useful for types -//! depending on a [`Felt252Dict`], where dictionary accesses are modifying the data structure -//! itself. -//! -//! Only one of these traits should be implemented for any given type, not both. -//! -//! [`Felt252Dict`]: core::dict::Felt252Dict -//! [`Get`]: crate::ops::get::Get -//! [`get`]: crate::ops::get - -#[feature("deprecated-index-traits")] -use crate::traits::{Index as DeprecatedIndex, IndexView as DeprecatedIndexView}; - -/// A trait for indexing operations (`container[index]`) where the input type is not modified. -/// -/// `container[index]` is syntactic sugar for `container.index(index)`. -/// -/// # Examples -/// -/// The following example implements `IndexView` on a `NucleotideCount` container, which can be -/// indexed without modifying the input, enabling individual counts to be retrieved with index -/// syntax. -/// -/// ``` -/// use core::ops::IndexView; -/// -/// #[derive(Copy, Drop)] -/// enum Nucleotide { -/// A, -/// C, -/// G, -/// T, -/// } -/// -/// #[derive(Copy, Drop)] -/// struct NucleotideCount { -/// a: usize, -/// c: usize, -/// g: usize, -/// t: usize, -/// } -/// -/// impl NucleotideIndex of IndexView { -/// type Target = usize; -/// -/// fn index(self: @NucleotideCount, index: Nucleotide) -> Self::Target { -/// match index { -/// Nucleotide::A => *self.a, -/// Nucleotide::C => *self.c, -/// Nucleotide::G => *self.g, -/// Nucleotide::T => *self.t, -/// } -/// } -/// } -/// -/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12}; -/// assert!(nucleotide_count[Nucleotide::A] == 14); -/// assert!(nucleotide_count[Nucleotide::C] == 9); -/// assert!(nucleotide_count[Nucleotide::G] == 10); -/// assert!(nucleotide_count[Nucleotide::T] == 12); -/// ``` -pub trait IndexView { - /// The returned type after indexing. - type Target; - - /// Performs the indexing (`container[index]`) operation. - /// - /// # Panics - /// - /// May panic if the index is out of bounds. - fn index(self: @C, index: I) -> Self::Target; -} - -impl DeprecatedIndexViewImpl< - C, I, V, impl Deprecated: DeprecatedIndexView, -> of crate::ops::IndexView { - type Target = V; - fn index(self: @C, index: I) -> Self::Target { - Deprecated::index(self, index) - } -} - -/// A trait for indexing operations (`container[index]`) where the input type is mutated. -/// -/// This trait should be implemented when you want to implement indexing operations on a type that's -/// mutated by a read access. This is useful for any type depending on a [`Felt252Dict`], where -/// dictionary accesses are modifying the data structure itself. -/// -/// `container[index]` is syntactic sugar for `container.index(index)`. -/// -/// # Examples -/// -/// The following example implements `Index` on a `Stack` type. This `Stack` is implemented based on -/// a [`Felt252Dict`], where dictionary accesses are modifying the dictionary itself. As such, we -/// must implement the `Index` trait instead of the `IndexView` trait. -/// -/// [`Felt252Dict`]: core::dict::Felt252Dict -/// -/// ``` -/// use core::ops::Index; -/// -/// #[derive(Destruct, Default)] -/// struct Stack { -/// items: Felt252Dict, -/// len: usize -/// } -/// -/// #[generate_trait] -/// impl StackImpl of StackTrait { -/// fn push(ref self: Stack, item: u128) { -/// self.items.insert(self.len.into(), item); -/// self.len += 1; -/// } -/// } -/// -/// impl StackIndex of Index { -/// type Target = u128; -/// -/// fn index(ref self: Stack, index: usize) -> Self::Target { -/// if index >= self.len { -/// panic!("Index out of bounds"); -/// } -/// self.items.get(index.into()) -/// } -/// } -/// -/// let mut stack: Stack = Default::default(); -/// stack.push(1); -/// assert!(stack[0] == 1); -/// ``` -pub trait Index { - /// The returned type after indexing. - type Target; - - /// Performs the indexing (`container[index]`) operation. - /// - /// # Panics - /// - /// May panic if the index is out of bounds. - fn index(ref self: C, index: I) -> Self::Target; -} - -#[feature("deprecated-index-traits")] -impl DeprecatedIndexImpl< - C, I, V, impl Deprecated: DeprecatedIndex, -> of crate::ops::Index { - type Target = V; - fn index(ref self: C, index: I) -> Self::Target { - Deprecated::index(ref self, index) - } -} diff --git a/corelib/src/ops/range.cairo b/corelib/src/ops/range.cairo deleted file mode 100644 index 3673605cbb..0000000000 --- a/corelib/src/ops/range.cairo +++ /dev/null @@ -1,320 +0,0 @@ -//! Range and iteration utilities. -//! -//! This module provides functionality for creating and iterating over ranges of values. -//! A range represents an interval of values from a start point to an end point. -//! -//! # Range Operator Forms -//! -//! There are currently two range operator forms: -//! `start..end`, representing a range from `start` (inclusive) to `end` (exclusive). -//! `start..=end`, representing a range from `start` (inclusive) to `end` (inclusive). - -use core::iter::{IntoIterator, Iterator}; -use core::num::traits::One; -use core::traits::Add; - -/// A (half-open) range bounded inclusively below and exclusively above -/// (`start..end`). -/// -/// The range `start..end` contains all values with `start <= x < end`. -/// It is empty if `start >= end`. -/// -/// # Examples -/// -/// The `start..end` syntax is a `Range`: -/// -/// ``` -/// assert!((3..5) == core::ops::Range { start: 3, end: 5 }); -/// -/// let mut sum = 0; -/// for i in 3..6 { -/// sum += i; -/// } -/// assert!(sum == 3 + 4 + 5); -/// ``` -#[derive(Clone, Drop, PartialEq)] -pub struct Range { - /// The lower bound of the range (inclusive). - pub start: T, - /// The upper bound of the range (exclusive). - pub end: T, -} - -#[generate_trait] -pub impl RangeImpl, +PartialOrd<@T>> of RangeTrait { - /// Returns `true` if `item` is contained in the range. - /// - /// # Examples - /// - /// ``` - /// assert!(!(3..5).contains(@2)); - /// assert!( (3..5).contains(@3)); - /// assert!( (3..5).contains(@4)); - /// assert!(!(3..5).contains(@5)); - /// - /// assert!(!(3..3).contains(@3)); - /// assert!(!(3..2).contains(@3)); - /// ``` - fn contains(self: @Range, item: @T) -> bool { - @self.start <= item && item < @self.end - } - - /// Returns `true` if the range contains no items. - /// - /// # Examples - /// - /// ``` - /// assert!(!(3_u8..5_u8).is_empty()); - /// assert!( (3_u8..3_u8).is_empty()); - /// assert!( (3_u8..2_u8).is_empty()); - /// ``` - #[inline] - fn is_empty(self: @Range) -> bool { - !(@self.start < @self.end) - } -} - -impl RangeDebug> of crate::fmt::Debug> { - fn fmt(self: @Range, ref f: crate::fmt::Formatter) -> Result<(), crate::fmt::Error> { - self.start.fmt(ref f)?; - write!(f, "..")?; - self.end.fmt(ref f)?; - Ok(()) - } -} - -/// Handles the range binary operator (`..`). -/// Used by the compiler to create a `Range` from the given `start` (inclusive) and `end` -/// (exclusive) values. -pub trait RangeOp { - fn range(start: T, end: T) -> Range; -} -impl RangeOpImpl of RangeOp { - fn range(start: T, end: T) -> Range { - Range { start, end } - } -} - -/// Represents an iterator located at `cur`, whose end is `end` (`cur <= end`). -#[derive(Clone, Drop, PartialEq)] -pub struct RangeIterator { - /// The current value of the iterator. - cur: T, - /// The upper bound of the range (exclusive). - end: T, -} - -impl RangeIteratorImpl< - T, impl OneT: One, +Add, +Copy, +Drop, +PartialEq, -> of Iterator> { - type Item = T; - - fn next(ref self: RangeIterator) -> Option { - if self.cur != self.end { - let value = self.cur; - self.cur = value + OneT::one(); - Some(value) - } else { - None - } - } -} - -impl RangeIntoIterator< - T, - +One, - +Add, - +Copy, - +Drop, - +PartialEq, - +PartialOrd, - -SierraIntRangeSupport, -> of IntoIterator> { - type IntoIter = RangeIterator; - fn into_iter(self: Range) -> Self::IntoIter { - let start = self.start; - let end = self.end; - if start < end { - Self::IntoIter { cur: start, end } - } else { - // Invalid range, return an empty range. - Self::IntoIter { cur: end, end } - } - } -} - -/// Represents the range [start, end]. -#[derive(Clone, Drop, PartialEq)] -pub struct RangeInclusive { - /// The lower bound of the range (inclusive). - pub start: T, - /// The upper bound of the range (inclusive). - pub end: T, -} - -#[derive(Clone, Drop)] -pub struct RangeInclusiveIterator { - /// The current value of the iterator. - pub(crate) cur: T, - /// The upper bound of the range (inclusive). - pub(crate) end: T, - // This field is: - // - `false` upon construction - // - `false` when iteration has yielded an element and the iterator is not exhausted - // - `true` when iteration has been used to exhaust the iterator - // - // This is required to differentiate between the last element and the end of the range. - pub(crate) exhausted: bool, -} - -/// Handles the range inclusive operator (`..=`). -pub trait RangeInclusiveOp { - /// Handles the `..=` operator. Returns the value of the expression `start..=end`. - fn range_inclusive(start: T, end: T) -> RangeInclusive; -} -impl RangeInclusiveOpImpl of RangeInclusiveOp { - fn range_inclusive(start: T, end: T) -> RangeInclusive { - RangeInclusive { start, end } - } -} - -#[generate_trait] -pub impl RangeInclusiveImpl, +PartialOrd<@T>> of RangeInclusiveTrait { - /// Returns `true` if `item` is contained in the range. - /// - /// # Examples - /// - /// ``` - /// assert!(!(3..=5).contains(@2)); - /// assert!( (3..=5).contains(@3)); - /// assert!( (3..=5).contains(@4)); - /// assert!( (3..=5).contains(@5)); - /// assert!(!(3..=5).contains(@6)); - /// - /// assert!( (3..=3).contains(@3)); - /// assert!(!(3..=2).contains(@3)); - /// ``` - fn contains(self: @RangeInclusive, item: @T) -> bool { - @self.start <= item && item <= @self.end - } - - /// Returns `true` if the range contains no items. - /// - /// # Examples - /// - /// ``` - /// assert!(!(3_u8..=5_u8).is_empty()); - /// assert!(!(3_u8..=3_u8).is_empty()); - /// assert!( (3_u8..=2_u8).is_empty()); - /// ``` - #[inline] - fn is_empty(self: @RangeInclusive) -> bool { - @self.start > @self.end - } -} - - -impl RangeInclusiveDebug< - T, impl TDebug: crate::fmt::Debug, -> of crate::fmt::Debug> { - fn fmt( - self: @RangeInclusive, ref f: crate::fmt::Formatter, - ) -> Result<(), crate::fmt::Error> { - self.start.fmt(ref f)?; - write!(f, "..=")?; - self.end.fmt(ref f)?; - Ok(()) - } -} - -impl RangeInclusiveIteratorImpl< - T, +One, +Add, +Copy, +Drop, +PartialEq, +PartialOrd, -> of Iterator> { - type Item = T; - - fn next(ref self: RangeInclusiveIterator) -> Option { - if self.exhausted { - return None; - } - - let current = self.cur; - - // If this is the last element, mark as exhausted for next iteration - if current == self.end { - self.exhausted = true; - return Some(current); - } - - // We know current < self.end here, because the iterator is not exhausted - self.cur = current + One::one(); - Some(current) - } -} - -pub impl RangeInclusiveIntoIterator< - T, +One, +Add, +Copy, +Drop, +PartialEq, +PartialOrd, -> of IntoIterator> { - type IntoIter = RangeInclusiveIterator; - - fn into_iter(self: RangeInclusive) -> Self::IntoIter { - let exhausted = self.start > self.end; - Self::IntoIter { cur: self.start, end: self.end, exhausted } - } -} - - -// Sierra optimization. - -mod internal { - use core::internal::OptionRev; - use core::iter::Iterator; - - pub extern type IntRange; - - impl IntRangeCopy of Copy>; - impl IntRangeDrop of Drop>; - - pub extern fn int_range_try_new( - x: T, y: T, - ) -> Result, IntRange> implicits(core::RangeCheck) nopanic; - pub extern fn int_range_pop_front(range: IntRange) -> OptionRev<(IntRange, T)> nopanic; - - impl IntRangeIteratorImpl, +Drop> of Iterator> { - type Item = T; - - fn next(ref self: IntRange) -> Option { - match int_range_pop_front(self) { - OptionRev::None => None, - OptionRev::Some((new_range, value)) => { - self = new_range; - Some(value) - }, - } - } - } -} - -/// Marker trait to enable using the Sierra libfuncs for integer range iteration (`IntRange`). -trait SierraIntRangeSupport; -impl SierraIntRangeSupportU8 of SierraIntRangeSupport; -impl SierraIntRangeSupportU16 of SierraIntRangeSupport; -impl SierraIntRangeSupportU32 of SierraIntRangeSupport; -impl SierraIntRangeSupportU64 of SierraIntRangeSupport; -impl SierraIntRangeSupportU128 of SierraIntRangeSupport; -impl SierraIntRangeSupportI8 of SierraIntRangeSupport; -impl SierraIntRangeSupportI16 of SierraIntRangeSupport; -impl SierraIntRangeSupportI32 of SierraIntRangeSupport; -impl SierraIntRangeSupportI64 of SierraIntRangeSupport; -impl SierraIntRangeSupportI128 of SierraIntRangeSupport; - -impl SierraRangeIntoIterator< - T, +Copy, +Drop, +SierraIntRangeSupport, -> of IntoIterator> { - type IntoIter = internal::IntRange; - fn into_iter(self: Range) -> Self::IntoIter { - match internal::int_range_try_new(self.start, self.end) { - Ok(range) => range, - Err(range) => range, - } - } -} diff --git a/corelib/src/option.cairo b/corelib/src/option.cairo deleted file mode 100644 index 18386544c0..0000000000 --- a/corelib/src/option.cairo +++ /dev/null @@ -1,901 +0,0 @@ -//! Optional values. -//! -//! The [`Option`] type represents an optional value: every [`Option`] is either [`Some`] and -//! contains a value, or [`None`], and does not. [`Option`] types are very common in Cairo code, as -//! they have a number of uses: -//! -//! * Initial values -//! * Return values for functions that are not defined -//! over their entire input range (partial functions) -//! * Return value for otherwise reporting simple errors, where [`None`] is -//! returned on error -//! * Optional struct fields -//! * Optional function arguments -//! -//! Options are commonly paired with pattern matching to query the presence of a value and take -//! action, always accounting for the `None` case. -//! -//! ``` -//! fn divide(numerator: u64, denominator: u64) -> Option { -//! if denominator == 0 { -//! None -//! } else { -//! Some(numerator / denominator) -//! } -//! } -//! -//! // The return value of the function is an option -//! let result = divide(2, 3); -//! -//! // Pattern match to retrieve the value -//! match result { -//! // The division was valid -//! Some(x) => println!("Result: {x}"), -//! // The division was invalid -//! None => println!("Cannot divide by 0"), -//! } -//! ``` -//! -//! # The question mark operator, `?` -//! -//! Similar to the [`Result`] type, when writing code that calls many functions that return the -//! [`Option`] type, handling `Some`/`None` can be tedious. The question mark -//! operator, `?`, hides some of the boilerplate of propagating values -//! up the call stack. -//! -//! It replaces this: -//! -//! ``` -//! fn add_last_numbers(mut array: Array) -> Option { -//! let a = array.pop_front(); -//! let b = array.pop_front(); -//! -//! match (a, b) { -//! (Some(x), Some(y)) => Some(x + y), -//! _ => None, -//! } -//! } -//! -//! ``` -//! -//! With this: -//! -//! ``` -//! fn add_last_numbers(mut array: Array) -> Option { -//! Some(array.pop_front()? + array.pop_front()?) -//! } -//! ``` -//! -//! *It's much nicer!* -//! -//! Ending the expression with `?` will result in the [`Some`]'s unwrapped value, unless the -//! result is [`None`], in which case [`None`] is returned early from the enclosing function. -//! `?` can be used in functions that return [`Option`] because of the -//! early return of [`None`] that it provides. -//! -//! [`Some`]: Some -//! [`None`]: None -//! -//! # Method overview -//! -//! In addition to working with pattern matching, [`Option`] provides a wide -//! variety of different methods. -//! -//! ## Querying the variant -//! -//! The [`is_some`] and [`is_none`] methods return `true` if the [`Option`] -//! is [`Some`] or [`None`], respectively. -//! -//! [`is_none`]: OptionTrait::is_none -//! [`is_none_or`]: OptionTrait::is_none_or -//! [`is_some`]: OptionTrait::is_some -//! [`is_some_and`]: OptionTrait::is_some_and -//! -//! ## Extracting the contained value -//! -//! These methods extract the contained value in an [`Option`] when it -//! is the [`Some`] variant. If the [`Option`] is [`None`]: -//! -//! * [`expect`] panics with a provided custom message -//! * [`unwrap`] panics with a generic message -//! * [`unwrap_or`] returns the provided default value -//! * [`unwrap_or_default`] returns the default value of the type `T` -//! (which must implement the [`Default`] trait) -//! * [`unwrap_or_else`] returns the result of evaluating the provided -//! function -//! -//! [`expect`]: OptionTrait::expect -//! [`unwrap`]: OptionTrait::unwrap -//! [`unwrap_or`]: OptionTrait::unwrap_or -//! [`unwrap_or_default`]: OptionTrait::unwrap_or_default -//! [`unwrap_or_else`]: OptionTrait::unwrap_or_else -//! -//! ## Transforming contained values -//! -//! These methods transform [`Option`] to [`Result`]: -//! -//! * [`ok_or`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to -//! [`Err(err)`] using the provided default `err` value. -//! * [`ok_or_else`] transforms [`Some(v)`] to [`Ok(v)`], and [`None`] to -//! a value of [`Err`] using the provided function -//! -//! [`Err(err)`]: Err -//! [`Ok(v)`]: Ok -//! [`Some(v)`]: Some -//! [`ok_or`]: OptionTrait::ok_or -//! [`ok_or_else`]: OptionTrait::ok_or_else -//! -//! These methods transform the [`Some`] variant: -//! -//! * [`map`] transforms [`Option`] to [`Option`] by applying the -//! provided function to the contained value of [`Some`] and leaving -//! [`None`] values unchanged -//! -//! [`map`]: OptionTrait::map -//! -//! These methods transform [`Option`] to a value of a possibly -//! different type `U`: -//! -//! * [`map_or`] applies the provided function to the contained value of -//! [`Some`], or returns the provided default value if the [`Option`] is -//! [`None`] -//! * [`map_or_else`] applies the provided function to the contained value -//! of [`Some`], or returns the result of evaluating the provided -//! fallback function if the [`Option`] is [`None`] -//! -//! [`map_or`]: OptionTrait::map_or -//! [`map_or_else`]: OptionTrait::map_or_else -//! -//! ## Boolean operators -//! -//! These methods treat the [`Option`] as a boolean value, where [`Some`] -//! acts like [`true`] and [`None`] acts like [`false`]. There are two -//! categories of these methods: ones that take an [`Option`] as input, and -//! ones that take a function as input (to be lazily evaluated). -//! -//! The [`and`], [`or`], and [`xor`] methods take another [`Option`] as -//! input, and produce an [`Option`] as output. Only the [`and`] method can -//! produce an [`Option`] value having a different inner type `U` than -//! [`Option`]. -//! -//! | method | self | input | output | -//! |---------|-----------|-----------|-----------| -//! | [`and`] | `None` | (ignored) | `None` | -//! | [`and`] | `Some(x)` | `None` | `None` | -//! | [`and`] | `Some(x)` | `Some(y)` | `Some(y)` | -//! | [`or`] | `None` | `None` | `None` | -//! | [`or`] | `None` | `Some(y)` | `Some(y)` | -//! | [`or`] | `Some(x)` | (ignored) | `Some(x)` | -//! | [`xor`] | `None` | `None` | `None` | -//! | [`xor`] | `None` | `Some(y)` | `Some(y)` | -//! | [`xor`] | `Some(x)` | `None` | `Some(x)` | -//! | [`xor`] | `Some(x)` | `Some(y)` | `None` | -//! -//! [`and`]: OptionTrait::and -//! [`or`]: OptionTrait::or -//! [`xor`]: OptionTrait::xor -//! -//! The [`and_then`] and [`or_else`] methods take a function as input, and -//! only evaluate the function when they need to produce a new value. Only -//! the [`and_then`] method can produce an [`Option`] value having a -//! different inner type `U` than [`Option`]. -//! -//! | method | self | function input | function result | output | -//! |--------------|-----------|----------------|-----------------|-----------| -//! | [`and_then`] | `None` | (not provided) | (not evaluated) | `None` | -//! | [`and_then`] | `Some(x)` | `x` | `None` | `None` | -//! | [`and_then`] | `Some(x)` | `x` | `Some(y)` | `Some(y)` | -//! | [`or_else`] | `None` | (not provided) | `None` | `None` | -//! | [`or_else`] | `None` | (not provided) | `Some(y)` | `Some(y)` | -//! | [`or_else`] | `Some(x)` | (not provided) | (not evaluated) | `Some(x)` | -//! -//! [`and_then`]: OptionTrait::and_then -//! [`or_else`]: OptionTrait::or_else -//! ## Iterating over `Option` -//! -//! An [`Option`] can be iterated over. This can be helpful if you need an -//! iterator that is conditionally empty. The iterator will either produce -//! a single value (when the [`Option`] is [`Some`]), or produce no values -//! (when the [`Option`] is [`None`]). For example, [`into_iter`] -//! contains [`Some(v)`] if the [`Option`] is [`Some(v)`], and [`None`] if the -//! [`Option`] is [`None`]. -//! -//! [`into_iter`]: IntoIterator::into_iter - -/// The `Option` enum representing either `Some(value)` or `None`. -#[must_use] -#[derive(Copy, Drop, Debug, Serde, PartialEq)] -pub enum Option { - Some: T, - None, -} - -impl OptionDefault of Default> { - fn default() -> Option { - None - } -} - -pub impl DestructOption, -Drop>> of Destruct> { - #[inline] - fn destruct(self: Option) nopanic { - match self { - Some(x) => x.destruct(), - None => (), - } - } -} -/// A trait for handling `Option` related operations. -pub trait OptionTrait { - /// Returns the contained `Some` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the option value is `None` with a custom `felt252` panic message `err`. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// let value = option.expect('no value'); - /// assert!(value == 123); - /// ``` - const fn expect(self: Option, err: felt252) -> T; - - /// Returns the contained `Some` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the `self` value equals `None`. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// let value = option.unwrap(); - /// assert!(value == 123); - /// ``` - const fn unwrap(self: Option) -> T; - - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err)`. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(Some('foo').ok_or(0), Ok('foo')); - /// - /// let option: Option = None; - /// assert_eq!(option.ok_or(0), Err(0)); - /// ``` - fn ok_or>(self: Option, err: E) -> Result; - - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err())`. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(Some('foo').ok_or_else(|| 0), Ok('foo')); - /// - /// let option: Option = None; - /// assert_eq!(option.ok_or_else(|| 0), Err(0)); - /// ``` - fn ok_or_else, +core::ops::FnOnce[Output: E], +Drop>( - self: Option, err: F, - ) -> Result; - - /// Returns [`None`] if the option is [`None`], otherwise returns `optb`. - /// - /// Arguments passed to `and` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`and_then`], which is - /// lazily evaluated. - /// - /// [`and_then`]: OptionTrait::and_then - /// - /// # Examples - /// - /// ``` - /// let x = Some(2); - /// let y: Option = None; - /// assert_eq!(x.and(y), None); - /// - /// let x: Option = None; - /// let y: Option = Some("foo"); - /// assert_eq!(x.and(y), None); - /// - /// let x = Some(2); - /// let y: Option = Some("foo"); - /// assert_eq!(x.and(y), Some("foo")); - /// - /// let x: Option = None; - /// let y: Option = None; - /// assert_eq!(x.and(y), None); - /// ``` - fn and, +Drop>(self: Option, optb: Option) -> Option; - - /// Returns [`None`] if the option is [`None`], otherwise calls `f` with the - /// wrapped value and returns the result. - /// - /// Some languages call this operation flatmap. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::CheckedMul; - /// - /// let option: Option = checked_mul(2_u32, 2_u32) - /// .and_then(|v| Some(format!("{}", v))); - /// assert_eq!(option, Some("4")); - /// - /// let option: Option = checked_mul(65536_u32, 65536_u32) - /// .and_then(|v| Some(format!("{}", v))); - /// assert_eq!(option, None); // overflowed! - /// - /// let option: Option = Option::::None - /// .and_then(|v| Some(format!("{}", v))); - /// assert_eq!(option, None); - /// ``` - fn and_then, +core::ops::FnOnce[Output: Option]>( - self: Option, f: F, - ) -> Option; - - /// Returns the option if it contains a value, otherwise returns `optb`. - /// - /// Arguments passed to `or` are eagerly evaluated; if you are passing the - /// result of a function call, it is recommended to use [`or_else`], which is - /// lazily evaluated. - /// - /// [`or_else`]: OptionTrait::or_else - /// - /// # Examples - /// - /// ``` - /// let x = Some(2); - /// let y = None; - /// assert_eq!(x.or(y), Some(2)); - /// - /// let x = None; - /// let y = Some(100); - /// assert_eq!(x.or(y), Some(100)); - /// - /// let x = Some(2); - /// let y = Some(100); - /// assert_eq!(x.or(y), Some(2)); - /// - /// let x: Option = None; - /// let y = None; - /// assert_eq!(x.or(y), None); - /// ``` - fn or<+Drop>(self: Option, optb: Option) -> Option; - - /// Returns the option if it contains a value, otherwise calls `f` and - /// returns the result. - /// - /// # Examples - /// - /// ``` - /// let nobody = || Option::::None; - /// let vikings = || Option::::Some("vikings"); - /// - /// assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians")); - /// assert_eq!(None.or_else(vikings), Some("vikings")); - /// assert_eq!(None.or_else(nobody), None); - /// ``` - fn or_else, +core::ops::FnOnce[Output: Option]>( - self: Option, f: F, - ) -> Option; - - /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns [`None`]. - /// - /// # Examples - /// - /// ``` - /// let x = Some(2); - /// let y: Option = None; - /// assert_eq!(x.xor(y), Some(2)); - /// - /// let x: Option = None; - /// let y = Some(2); - /// assert_eq!(x.xor(y), Some(2)); - /// - /// let x = Some(2); - /// let y = Some(2); - /// assert_eq!(x.xor(y), None); - /// - /// let x: Option = None; - /// let y: Option = None; - /// assert_eq!(x.xor(y), None); - /// ``` - fn xor<+Drop>(self: Option, optb: Option) -> Option; - - /// Returns `true` if the `Option` is `Some`, `false` otherwise. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// assert!(option.is_some()); - /// ``` - #[must_use] - fn is_some(self: @Option) -> bool; - - /// Returns `true` if the `Option` is `Some` and the value inside of it matches a - /// predicate. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(Some(2_u8).is_some_and(|x| x > 1), true); - /// assert_eq!(Some(0_u8).is_some_and(|x| x > 1), false); - /// - /// let option: Option = None; - /// assert_eq!(option.is_some_and(|x| x > 1), false); - /// ``` - #[must_use] - fn is_some_and, +core::ops::FnOnce[Output: bool]>( - self: Option, f: F, - ) -> bool; - - /// Returns `true` if the `Option` is `None`, `false` otherwise. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// assert!(!option.is_none()); - /// ``` - #[must_use] - fn is_none(self: @Option) -> bool; - - /// Returns `true` if the `Option` is `None` or the value inside of it matches a - /// predicate. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(Some(2_u8).is_none_or(|x| x > 1), true); - /// assert_eq!(Some(0_u8).is_none_or(|x| x > 1), false); - /// - /// let option: Option = None; - /// assert_eq!(option.is_none_or(|x| x > 1), true); - /// ``` - #[must_use] - fn is_none_or, +core::ops::FnOnce[Output: bool]>( - self: Option, f: F, - ) -> bool; - - /// Returns the contained `Some` value if `self` is `Some(x)`. Otherwise, returns the - /// provided default. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// assert!(option.unwrap_or(456) == 123); - /// - /// let option = None; - /// assert!(option.unwrap_or(456) == 456); - /// ``` - const fn unwrap_or<+Destruct>(self: Option, default: T) -> T; - - /// Returns the contained `Some` value if `self` is `Some(x)`. Otherwise, returns - /// `Default::::default()`. - /// - /// # Examples - /// - /// ``` - /// let option = Some(123); - /// assert!(option.unwrap_or_default() == 123); - /// - /// let option: Option = None; - /// assert!(option.unwrap_or_default() == Default::default()); - /// ``` - fn unwrap_or_default<+Default>(self: Option) -> T; - - /// Returns the contained [`Some`] value or computes it from a closure. - /// - /// # Examples - /// - /// ``` - /// let k = 10; - /// assert!(Some(4).unwrap_or_else(|| 2 * k) == 4); - /// assert!(None.unwrap_or_else(|| 2 * k) == 20); - /// ``` - fn unwrap_or_else< - F, +Drop, impl func: core::ops::FnOnce[Output: T], +Drop, - >( - self: Option, f: F, - ) -> T; - - ///////////////////////////////////////////////////////////////////////// - // Transforming contained values - ///////////////////////////////////////////////////////////////////////// - - /// Maps an `Option` to `Option` by applying a function to a contained value (if `Some`) - /// or returns `None` (if `None`). - /// - /// # Examples - /// - /// ``` - /// let maybe_some_string: Option = Some("Hello, World!"); - /// // `Option::map` takes self *by value*, consuming `maybe_some_string` - /// let maybe_some_len = maybe_some_string.map(|s: ByteArray| s.len()); - /// assert!(maybe_some_len == Some(13)); - /// - /// let x: Option = None; - /// assert!(x.map(|s: ByteArray| s.len()) == None); - /// ``` - fn map, +core::ops::FnOnce[Output: U]>( - self: Option, f: F, - ) -> Option; - - /// Returns the provided default result (if none), - /// or applies a function to the contained value (if any). - /// - /// Arguments passed to `map_or` are eagerly evaluated; if you are passing - /// the result of a function call, it is recommended to use [`map_or_else`], - /// which is lazily evaluated. - /// - /// [`map_or_else`]: OptionTrait::map_or_else - /// - /// # Examples - /// - /// ``` - /// assert_eq!(Some("foo").map_or(42, |v: ByteArray| v.len()), 3); - /// - /// let x: Option = None; - /// assert_eq!(x.map_or(42, |v: ByteArray| v.len()), 42); - /// ``` - #[must_use] - fn map_or, +Drop, +core::ops::FnOnce[Output: U]>( - self: Option, default: U, f: F, - ) -> U; - - /// Computes a default function result (if none), or - /// applies a different function to the contained value (if any). - /// - /// # Basic examples - /// - /// ``` - /// let k = 21; - /// - /// let x = Some("foo"); - /// assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 3); - /// - /// let x: Option = None; - /// assert_eq!(x.map_or_else( || 2 * k, |v: ByteArray| v.len()), 42); - /// ``` - fn map_or_else< - U, - D, - F, - +Drop, - +Drop, - +Drop, - +core::ops::FnOnce[Output: U], - +core::ops::FnOnce[Output: U], - >( - self: Option, default: D, f: F, - ) -> U; - - /// Takes the value out of the option, leaving a [`None`] in its place. - /// - /// # Examples - /// - /// ``` - /// let mut x = Some(2); - /// let y = x.take(); - /// assert_eq!(x, None); - /// assert_eq!(y, Some(2)); - /// - /// let mut x: Option = None; - /// let y = x.take(); - /// assert_eq!(x, None); - /// assert_eq!(y, None); - /// ``` - fn take(ref self: Option) -> Option; - - /// Returns [`None`] if the option is [`None`], otherwise calls `predicate` - /// with the wrapped value and returns: - /// - /// - [`Some(t)`] if `predicate` returns `true` (where `t` is the wrapped - /// value), and - /// - [`None`] if `predicate` returns `false`. - /// - /// # Example - /// - /// ``` - /// let is_even = |n: @u32| -> bool { - /// *n % 2 == 0 - /// }; - /// - /// assert_eq!(None.filter(is_even), None); - /// assert_eq!(Some(3).filter(is_even), None); - /// assert_eq!(Some(4).filter(is_even), Some(4)); - /// ``` - fn filter[Output: bool], +Destruct, +Destruct

>( - self: Option, predicate: P, - ) -> Option; - - /// Converts from `Option>` to `Option`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x: Option> = Some(Some(6)); - /// assert_eq!(Some(6), x.flatten()); - /// - /// let x: Option> = Some(None); - /// assert_eq!(None, x.flatten()); - /// - /// let x: Option> = None; - /// assert_eq!(None, x.flatten()); - /// ``` - /// - /// Flattening only removes one level of nesting at a time: - /// - /// ``` - /// let x: Option>> = Some(Some(Some(6))); - /// assert_eq!(Some(Some(6)), x.flatten()); - /// assert_eq!(Some(6), x.flatten().flatten()); - /// ``` - fn flatten(self: Option>) -> Option; -} - -pub impl OptionTraitImpl of OptionTrait { - #[inline(always)] - const fn expect(self: Option, err: felt252) -> T { - match self { - Some(x) => x, - None => crate::panic_with_felt252(err), - } - } - - #[inline(always)] - const fn unwrap(self: Option) -> T { - self.expect('Option::unwrap failed.') - } - - #[inline] - fn ok_or>(self: Option, err: E) -> Result { - match self { - Some(v) => Ok(v), - None => Err(err), - } - } - - #[inline] - fn ok_or_else, +core::ops::FnOnce[Output: E], +Drop>( - self: Option, err: F, - ) -> Result { - match self { - Some(v) => Ok(v), - None => Err(err()), - } - } - - #[inline] - fn and, +Drop>(self: Option, optb: Option) -> Option { - match self { - Some(_) => optb, - None => None, - } - } - - #[inline] - fn and_then, +core::ops::FnOnce[Output: Option]>( - self: Option, f: F, - ) -> Option { - match self { - Some(x) => f(x), - None => None, - } - } - - #[inline] - fn or<+Drop>(self: Option, optb: Option) -> Option { - match self { - Some(x) => Some(x), - None => optb, - } - } - - #[inline] - fn or_else, +core::ops::FnOnce[Output: Option]>( - self: Option, f: F, - ) -> Option { - match self { - Some(x) => Some(x), - None => f(), - } - } - - #[inline] - fn xor<+Drop>(self: Option, optb: Option) -> Option { - match (self, optb) { - (Some(x), None) => Some(x), - (None, Some(x)) => Some(x), - _ => None, - } - } - - #[inline] - fn is_some(self: @Option) -> bool { - match self { - Some(_) => true, - None => false, - } - } - - #[inline] - fn is_some_and, +core::ops::FnOnce[Output: bool]>( - self: Option, f: F, - ) -> bool { - match self { - None => false, - Some(x) => f(x), - } - } - - #[inline] - fn is_none(self: @Option) -> bool { - match self { - Some(_) => false, - None => true, - } - } - - #[inline] - fn is_none_or, +core::ops::FnOnce[Output: bool]>( - self: Option, f: F, - ) -> bool { - match self { - Some(x) => f(x), - None => true, - } - } - - #[inline] - const fn unwrap_or<+Destruct>(self: Option, default: T) -> T { - match self { - Some(x) => x, - None => default, - } - } - - #[inline] - fn unwrap_or_default<+Default>(self: Option) -> T { - match self { - Some(x) => x, - None => Default::default(), - } - } - - #[inline] - fn unwrap_or_else< - F, +Drop, impl func: core::ops::FnOnce[Output: T], +Drop, - >( - self: Option, f: F, - ) -> T { - match self { - Some(x) => x, - None => f(), - } - } - - #[inline] - fn map, +core::ops::FnOnce[Output: U]>( - self: Option, f: F, - ) -> Option { - match self { - Some(x) => Some(f(x)), - None => None, - } - } - - #[inline] - fn map_or, +Drop, +core::ops::FnOnce[Output: U]>( - self: Option, default: U, f: F, - ) -> U { - match self { - Some(x) => f(x), - None => default, - } - } - - #[inline] - fn map_or_else< - U, - D, - F, - +Drop, - +Drop, - +Drop, - +core::ops::FnOnce[Output: U], - +core::ops::FnOnce[Output: U], - >( - self: Option, default: D, f: F, - ) -> U { - match self { - Some(x) => f(x), - None => default(), - } - } - - #[inline] - fn take(ref self: Option) -> Option { - let value = self; - self = None; - value - } - - #[inline] - fn filter[Output: bool], +Destruct, +Destruct

>( - self: Option, predicate: P, - ) -> Option { - if let Some(value) = self { - if predicate(@value) { - return Some(value); - } - } - - None - } - - #[inline] - fn flatten(self: Option>) -> Option { - match self { - Some(x) => x, - None => None, - } - } -} - -impl TIntoOption of Into> { - /// Moves `self` into a new [`Some`]. - /// - /// # Examples - /// - /// ``` - /// let o: Option = 67_u8.into() - /// assert_eq!(Some(67), o); - /// ``` - #[inline] - fn into(self: T) -> Option { - Some(self) - } -} - - -/// An iterator over the value in the [`Some`] variant of an [`Option`]. -/// -/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. -/// -/// This struct is created by the [`into_iter`] method on [`Option`] (provided by the -/// [`IntoIterator`] trait). -/// -/// [`into_iter`]: IntoIterator::into_iter -#[derive(Drop)] -pub struct OptionIter { - inner: Option, -} - -impl OptionIterator of crate::iter::Iterator> { - type Item = T; - fn next(ref self: OptionIter) -> Option { - let item = self.inner; - self.inner = None; - item - } -} - -impl OptionIntoIterator of crate::iter::IntoIterator> { - type IntoIter = OptionIter; - #[inline] - fn into_iter(self: Option) -> Self::IntoIter { - OptionIter { inner: self } - } -} diff --git a/corelib/src/panics.cairo b/corelib/src/panics.cairo deleted file mode 100644 index 2fb51be372..0000000000 --- a/corelib/src/panics.cairo +++ /dev/null @@ -1,70 +0,0 @@ -//! Core panic mechanism. -//! -//! This module provides the core panic functionality used for error handling in Cairo. -//! It defines the basic types and functions used to trigger and manage panics, which -//! are Cairo's mechanism for handling unrecoverable errors. -//! -//! Panics can be triggered in several ways: -//! -//! Using the `panic` function: -//! -//! ``` -//! use core::panics::panic; -//! -//! panic(array!['An error occurred']); -//! ``` -//! -//! Or using the `panic!` macro: -//! -//! ``` -//! panic!("Panic message"); -//! ``` -//! -//! This macro internally converts the message into a `ByteArray` and uses `panic_with_byte_array`. - -use crate::array::Array; - -/// Represents a panic condition in Cairo. -/// -/// A `Panic` is created when the program encounters an unrecoverable error condition -/// and needs to terminate execution. -pub struct Panic {} - -/// Result type for operations that can trigger a panic. -pub enum PanicResult { - Ok: T, - Err: (Panic, Array), -} - -/// Triggers an immediate panic with the provided data and terminates execution. -/// -/// # Examples -/// -/// ``` -/// use core::panics::panic; -/// -/// panic(array!['An error occurred']); -/// ``` -pub extern fn panic(data: Array) -> crate::never; - -extern fn unsafe_panic() -> crate::never nopanic; - -/// Panics with a `ByteArray` message. -/// -/// Constructs a panic message by prepending the `BYTE_ARRAY_MAGIC` value and -/// serializing the provided `ByteArray` into the panic data. -/// -/// # Examples -/// -/// ``` -/// use core::panics::panic_with_byte_array; -/// -/// let error_msg = "An error occurred"; -/// panic_with_byte_array(@error_msg); -/// ``` -#[inline(never)] -pub fn panic_with_byte_array(err: @ByteArray) -> crate::never { - let mut serialized = array![crate::byte_array::BYTE_ARRAY_MAGIC]; - err.serialize(ref serialized); - panic(serialized) -} diff --git a/corelib/src/pedersen.cairo b/corelib/src/pedersen.cairo deleted file mode 100644 index 778f0594dc..0000000000 --- a/corelib/src/pedersen.cairo +++ /dev/null @@ -1,100 +0,0 @@ -//! Pedersen hash related traits implementations. -//! -//! This module provides an implementation of the Pedersen hash function, which is a -//! collision-resistant cryptographic hash function. -//! -//! The `HashState` struct represents the state of a Pedersen hash computation. It contains a -//! single `felt252` field `state` that holds the current hash value. -//! -//! The `PedersenTrait` provides a `new` method to create a new `HashState` from a base value. -//! -//! The [`HashStateTrait`] defined in the Hash module provides the `update` and `finalize` methods -//! to update the hash state and obtain the final hash value, respectively. -//! -//! -//! # Examples -//! -//! ``` -//! use core::hash::HashStateTrait; -//! use core::pedersen::PedersenTrait; -//! -//! let mut state = PedersenTrait::new(0); -//! state = state.update(1); -//! state = state.update(2); -//! let hash = state.finalize(); -//! assert!(hash == 0x07546be9ecb576c12cd00962356afd90b615d8ef50605bc13badfd1fd218c0d5); -//! ``` - -pub extern type Pedersen; - -pub extern fn pedersen(a: felt252, b: felt252) -> felt252 implicits(Pedersen) nopanic; - -/// Represents the current state of a Pedersen hash computation. -/// -/// The state is maintained as a single `felt252` value, which is updated -/// through the [`HashStateTrait::finalize`] method. -#[derive(Copy, Drop, Debug)] -pub struct HashState { - /// The current hash state - pub state: felt252, -} - -/// A trait for creating a new Pedersen hash state. -#[generate_trait] -pub impl PedersenImpl of PedersenTrait { - /// Creates a new Pedersen hash state with the given base value. - /// - /// # Examples - /// - /// ``` - /// use core::pedersen::PedersenTrait; - /// - /// let mut state = PedersenTrait::new(0); - /// assert!(state.state == 0); - /// ``` - #[inline] - fn new(base: felt252) -> HashState { - HashState { state: base } - } -} - -impl HashStateImpl of crate::hash::HashStateTrait { - /// Updates the hash state with a new value. - /// - /// Applies the Pedersen commitment function to the current state and new value. - /// - /// - /// # Examples - /// - /// ``` - /// use core::hash::HashStateTrait; - /// use core::pedersen::PedersenTrait; - /// - /// let mut state = PedersenTrait::new(0); - /// state = state.update(1); - /// ``` - #[inline] - fn update(self: HashState, value: felt252) -> HashState { - HashState { state: pedersen(self.state, value) } - } - - /// Finalizes the hash computation. - /// - /// For Pedersen, this simply returns the current state as the final hash value. - /// - /// # Examples - /// - /// ``` - /// use core::hash::HashStateTrait; - /// use core::pedersen::PedersenTrait; - /// - /// let mut state = PedersenTrait::new(0); - /// state = state.update(1); - /// let hash = state.finalize(); - /// ``` - #[inline] - fn finalize(self: HashState) -> felt252 { - self.state - } -} - diff --git a/corelib/src/poseidon.cairo b/corelib/src/poseidon.cairo deleted file mode 100644 index 42be7d479c..0000000000 --- a/corelib/src/poseidon.cairo +++ /dev/null @@ -1,151 +0,0 @@ -//! Poseidon hash related traits implementations and functions. -//! -//! This module provides cryptographic hash functions based on the Poseidon permutation. -//! -//! The Poseidon hash function is an arithmetic-friendly hash function optimized for use in -//! zero-knowledge proof systems. This module implements the Poseidon hash using a sponge -//! construction for arbitrary-length inputs. -//! -//! # Examples -//! -//! ``` -//! use core::hash::HashStateTrait; -//! use core::poseidon::PoseidonTrait; -//! -//! // Create a new hash state -//! let mut state = PoseidonTrait::new(); -//! -//! // Update with values -//! state = state.update(1); -//! state = state.update(2); -//! -//! // Finalize to get the hash -//! let hash = state.finalize(); -//! ``` - -use crate::array::{Span, SpanTrait}; -use crate::hash::HashStateTrait; - -pub extern type Poseidon; - -pub extern fn hades_permutation( - s0: felt252, s1: felt252, s2: felt252, -) -> (felt252, felt252, felt252) implicits(Poseidon) nopanic; - -/// State for Poseidon hash. -#[derive(Copy, Drop, Debug)] -pub struct HashState { - pub s0: felt252, - pub s1: felt252, - pub s2: felt252, - pub odd: bool, -} - -/// A trait for creating a new Poseidon hash state. -#[generate_trait] -pub impl PoseidonImpl of PoseidonTrait { - /// Creates an initial state with all fields set to 0. - /// - /// # Examples - /// - /// ``` - /// use core::poseidon::PoseidonTrait; - /// - /// let mut state = PoseidonTrait::new(); - /// ``` - #[inline] - fn new() -> HashState { - HashState { s0: 0, s1: 0, s2: 0, odd: false } - } -} - -impl HashStateDefault of Default { - fn default() -> HashState { - PoseidonTrait::new() - } -} - -impl HashStateImpl of HashStateTrait { - /// Takes the current state and updates it with a `felt252` value using the Hades permutation. - /// - /// # Examples - /// - /// ``` - /// use core::hash::HashStateTrait; - /// use core::poseidon::PoseidonTrait; - /// - /// let mut state = PoseidonTrait::new(); - /// state = state.update(1); - /// ``` - #[inline] - fn update(self: HashState, value: felt252) -> HashState { - if self.odd { - let (s0, s1, s2) = hades_permutation(self.s0, self.s1 + value, self.s2); - HashState { s0, s1, s2, odd: false } - } else { - HashState { s0: self.s0 + value, s1: self.s1, s2: self.s2, odd: true } - } - } - - /// Takes the current state, applies the Hades permutation and returns the hash result. - /// - /// # Examples - /// - /// ``` - /// use core::hash::HashStateTrait; - /// use core::poseidon::PoseidonTrait; - /// - /// let mut state = PoseidonTrait::new(); - /// let hash = state.update(1).update(2).finalize(); - /// - /// assert!(hash == 0x0371cb6995ea5e7effcd2e174de264b5b407027a75a231a70c2c8d196107f0e7); - /// ``` - #[inline] - fn finalize(self: HashState) -> felt252 { - if self.odd { - let (r, _, _) = hades_permutation(self.s0, self.s1 + 1, self.s2); - r - } else { - let (r, _, _) = hades_permutation(self.s0 + 1, self.s1, self.s2); - r - } - } -} - -/// Computes the Poseidon hash on the given span input. -/// Applies the sponge construction to digest many elements. -/// To distinguish between use cases, the capacity element is initialized to 0. -/// To distinguish between different input sizes always pads with 1, and possibly with another 0 to -/// complete to an even-sized input. -/// -/// # Examples -/// -/// ``` -/// let span = [1, 2].span(); -/// let hash = poseidon_hash_span(span); -/// -/// assert!(hash == 0x0371cb6995ea5e7effcd2e174de264b5b407027a75a231a70c2c8d196107f0e7); -/// ``` -pub fn poseidon_hash_span(mut span: Span) -> felt252 { - _poseidon_hash_span_inner(crate::gas::get_builtin_costs(), (0, 0, 0), ref span) -} - -/// Helper function for `poseidon_hash_span`. -fn _poseidon_hash_span_inner( - builtin_costs: crate::gas::BuiltinCosts, - state: (felt252, felt252, felt252), - ref span: Span, -) -> felt252 { - let (s0, s1, s2) = state; - let Some(x) = span.pop_front() else { - return HashState { s0, s1, s2, odd: false }.finalize(); - }; - let Some(y) = span.pop_front() else { - return HashState { s0: s0 + *x, s1, s2, odd: true }.finalize(); - }; - let next_state = hades_permutation(s0 + *x, s1 + *y, s2); - let Some(_) = crate::gas::withdraw_gas_all(builtin_costs) else { - core::panic_with_felt252('Out of gas'); - }; - _poseidon_hash_span_inner(builtin_costs, next_state, ref span) -} diff --git a/corelib/src/prelude.cairo b/corelib/src/prelude.cairo deleted file mode 100644 index adf41a0dab..0000000000 --- a/corelib/src/prelude.cairo +++ /dev/null @@ -1,3 +0,0 @@ -mod v2023_01; -mod v2023_10; -mod v2024_07; diff --git a/corelib/src/prelude/v2023_01.cairo b/corelib/src/prelude/v2023_01.cairo deleted file mode 100644 index f6a0a4c986..0000000000 --- a/corelib/src/prelude/v2023_01.cairo +++ /dev/null @@ -1,86 +0,0 @@ -pub use starknet::storage::{ - StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, -}; -use crate::array::{self, Array, ArrayTrait, Span, SpanTrait, ToSpanTrait}; -use crate::box::{self, Box, BoxTrait}; -use crate::byte_array::{ - self, ByteArray, ByteArrayIndexView, ByteArrayStringLiteral, ByteArrayTrait, -}; -use crate::bytes_31::{ - self, Bytes31IndexView, Bytes31IntoFelt252, Bytes31Trait, Felt252TryIntoBytes31, bytes31, - bytes31_const, -}; -use crate::clone::{self, Clone}; -use crate::dict::{ - self, Felt252Dict, Felt252DictTrait, SquashedFelt252Dict, felt252_dict_new, felt252_dict_squash, -}; -use crate::ec::{self, EcOp, EcPoint, EcState}; -use crate::gas::{self, BuiltinCosts, GasBuiltin, get_builtin_costs}; -use crate::integer::{ - self, Bitwise, Felt252IntoU256, Felt252TryIntoU128, Felt252TryIntoU16, Felt252TryIntoU32, - Felt252TryIntoU64, Felt252TryIntoU8, I128IntoFelt252, I16IntoFelt252, I32IntoFelt252, - I64IntoFelt252, I8IntoFelt252, NumericLiteral, U128IntoFelt252, U16IntoFelt252, U32IntoFelt252, - U64IntoFelt252, U8IntoFelt252, i128, i16, i32, i64, i8, u128, u128_is_zero, u16, u256, u32, u64, - u8, -}; -#[feature("corelib-internal-use")] -#[deprecated(feature: "corelib-internal-use", note: "Use `core::num::traits::Sqrt` instead")] -use crate::integer::{u128_sqrt, u256_sqrt}; -use crate::iter::{FromIterator, IntoIterator, Iterator}; -use crate::nullable::{self, Nullable, NullableTrait, match_nullable, null, nullable_from_box}; -pub use crate::ops::Deref; -use crate::option::Option::{self, None, Some}; -use crate::option::{self, OptionTrait}; -use crate::panics::{self, Panic, PanicResult, panic}; -use crate::pedersen::{self, Pedersen}; -use crate::poseidon::{self, Poseidon}; -use crate::result::Result::{self, Err, Ok}; -use crate::result::{self, ResultTrait}; -use crate::serde::{self, Serde}; -#[feature("corelib-internal-use")] -use crate::starknet::{self, System}; -use crate::string::{self, StringLiteral}; -#[cfg(test)] -use crate::test; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::AddAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::AddEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::DivAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::DivEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::MulAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::MulEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::RemAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::RemEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::SubAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::SubEq; -use crate::traits::{ - self, Add, BitAnd, BitNot, BitOr, BitXor, Copy, Default, Destruct, Div, DivRem, Drop, - Felt252DictValue, Into, Mul, Neg, Not, PanicDestruct, PartialEq, PartialOrd, Rem, Sub, TryInto, -}; -#[feature("deprecated-index-traits")] -use crate::traits::{Index, IndexView}; -use crate::zeroable::{self, NonZero, Zeroable}; -use crate::{ - BoolBitAnd, BoolBitOr, BoolBitXor, BoolFelt252DictValue, BoolIntoFelt252, BoolNot, - BoolPartialEq, BoolSerde, Felt252Add, Felt252AddEq, Felt252Default, Felt252Felt252DictValue, - Felt252Mul, Felt252MulEq, Felt252Neg, Felt252PartialEq, Felt252Serde, Felt252Sub, Felt252SubEq, - Felt252TryIntoNonZero, RangeCheck, SegmentArena, assert, bool, bool_and_impl, bool_not_impl, - bool_or_impl, bool_to_felt252, bool_xor_impl, cmp, debug, ecdsa, felt252, felt252_add, - felt252_const, felt252_div, felt252_is_zero, felt252_mul, felt252_sub, hash, internal, keccak, - math, never, panic_with_felt252, testing, to_byte_array, usize, -}; diff --git a/corelib/src/prelude/v2023_10.cairo b/corelib/src/prelude/v2023_10.cairo deleted file mode 100644 index 657e0c50c6..0000000000 --- a/corelib/src/prelude/v2023_10.cairo +++ /dev/null @@ -1,68 +0,0 @@ -pub use starknet::storage::{ - StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, -}; -pub use crate::array::{Array, ArrayTrait, Span, SpanTrait, ToSpanTrait}; -pub use crate::box::{Box, BoxTrait}; -pub use crate::byte_array::{ByteArray, ByteArrayTrait}; -pub use crate::bytes_31::{Bytes31Trait, bytes31}; -pub use crate::clone::Clone; -pub use crate::dict::{Felt252Dict, Felt252DictTrait, SquashedFelt252Dict}; -pub use crate::gas::GasBuiltin; -pub use crate::integer::{Bitwise, i128, i16, i32, i64, i8, u128, u16, u256, u32, u64, u8}; -pub use crate::iter::{FromIterator, IntoIterator, Iterator}; -pub use crate::nullable::{Nullable, NullableTrait}; -pub use crate::ops::Deref; -pub use crate::option::Option::{self, None, Some}; -pub use crate::option::OptionTrait; -pub use crate::panics::{Panic, PanicResult, panic}; -pub use crate::pedersen::Pedersen; -pub use crate::poseidon::Poseidon; -pub use crate::result::Result::{self, Err, Ok}; -pub use crate::result::ResultTrait; -pub use crate::serde::Serde; -#[feature("corelib-internal-use")] -pub use crate::starknet::{self, System}; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::AddAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::AddEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::DivAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::DivEq; -#[deprecated( - feature: "deprecated-index-traits", note: "Use `core::ops::index::Index`.", since: "2.7.0", -)] -#[feature("deprecated-index-traits")] -pub use crate::traits::Index; -#[deprecated( - feature: "deprecated-index-traits", note: "Use `core::ops::index::IndexView`.", since: "2.7.0", -)] -#[feature("deprecated-index-traits")] -pub use crate::traits::IndexView; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::MulAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::MulEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::RemAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::RemEq; -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::SubAssign`.", since: "2.7.0", -)] -#[feature("deprecated-op-assign-traits")] -pub use crate::traits::SubEq; -pub use crate::traits::{ - Add, BitAnd, BitNot, BitOr, BitXor, Copy, Default, Destruct, Div, DivRem, Drop, - Felt252DictValue, Into, Mul, Neg, Not, PanicDestruct, PartialEq, PartialOrd, Rem, Sub, TryInto, -}; -pub use crate::zeroable::NonZero; -pub use crate::{ - RangeCheck, SegmentArena, assert, bool, felt252, keccak, math, to_byte_array, usize, -}; diff --git a/corelib/src/prelude/v2024_07.cairo b/corelib/src/prelude/v2024_07.cairo deleted file mode 100644 index 0c695b3559..0000000000 --- a/corelib/src/prelude/v2024_07.cairo +++ /dev/null @@ -1,25 +0,0 @@ -pub use crate::array::{Array, ArrayTrait, Span, SpanTrait, ToSpanTrait}; -pub use crate::box::{Box, BoxTrait}; -pub use crate::byte_array::{ByteArray, ByteArrayTrait}; -pub use crate::bytes_31::{Bytes31Trait, bytes31}; -pub use crate::clone::Clone; -pub use crate::dict::Felt252DictTrait; -pub use crate::integer::{i128, i16, i32, i64, i8, u128, u16, u256, u32, u64, u8}; -pub use crate::iter::{FromIterator, IntoIterator, Iterator}; -pub use crate::nullable::{Nullable, NullableTrait}; -pub use crate::ops::Deref; -pub use crate::option::Option::{self, None, Some}; -pub use crate::option::OptionTrait; -pub use crate::panics::{Panic, PanicResult, panic}; -pub use crate::result::Result::{self, Err, Ok}; -pub use crate::result::ResultTrait; -pub use crate::serde::Serde; -#[feature("corelib-internal-use")] -pub use crate::starknet::{self, System}; -pub use crate::traits::{ - Add, Copy, Default, Destruct, Div, DivRem, Drop, Felt252DictValue, Into, Mul, Neg, Not, - PanicDestruct, PartialEq, PartialOrd, Rem, Sub, TryInto, -}; - -pub use crate::zeroable::NonZero; -pub use crate::{assert, bool, felt252, usize}; diff --git a/corelib/src/qm31.cairo b/corelib/src/qm31.cairo deleted file mode 100644 index 18a9266a8e..0000000000 --- a/corelib/src/qm31.cairo +++ /dev/null @@ -1,121 +0,0 @@ -//! Definition for the `qm31` type. -//! Only available for local proofs. -//! -//! The implementations defined in this module can be accessed by using the traits directly. - -/// The `qm31` type, defining an extension field over 4 `m31`s. -pub extern type qm31; - -/// The field for the Mersenne prime with `n` 31. -#[feature("bounded-int-utils")] -pub type m31 = - core::internal::bounded_int::BoundedInt<0, 0x7ffffffe>; - -pub trait QM31Trait { - /// Returns a new `qm31` composed of the given parts. - fn new(w0: m31, w1: m31, w2: m31, w3: m31) -> qm31; - /// Returns the parts of the given `qm31` as `m31`s. - fn unpack(self: qm31) -> [m31; 4]; -} -impl QM31Impl of QM31Trait { - fn new(w0: m31, w1: m31, w2: m31, w3: m31) -> qm31 { - qm31_pack(w0, w1, w2, w3) - } - - fn unpack(self: qm31) -> [m31; 4] { - let (w0, w1, w2, w3) = qm31_unpack(self); - [w0, w1, w2, w3] - } -} - -/// Returns a `qm31` given its values as constants. -pub extern fn qm31_const< - const W0: m31, const W1: m31, const W2: m31, const W3: m31, ->() -> qm31 nopanic; - -extern fn qm31_is_zero(a: qm31) -> core::internal::OptionRev> nopanic; -extern fn qm31_add(a: qm31, b: qm31) -> qm31 nopanic; -extern fn qm31_sub(a: qm31, b: qm31) -> qm31 nopanic; -extern fn qm31_mul(a: qm31, b: qm31) -> qm31 nopanic; -extern fn qm31_div(a: qm31, b: NonZero) -> qm31 nopanic; -extern fn qm31_pack(w0: m31, w1: m31, w2: m31, w3: m31) -> qm31 nopanic; -extern fn qm31_unpack(a: qm31) -> (m31, m31, m31, m31) implicits(crate::RangeCheck) nopanic; -extern fn qm31_from_m31(a: m31) -> qm31 nopanic; - -impl qm31Copy of Copy; -impl qm31Drop of Drop; -impl qm31Add of Add { - fn add(lhs: qm31, rhs: qm31) -> qm31 { - qm31_add(lhs, rhs) - } -} -impl qm31Sub of Sub { - fn sub(lhs: qm31, rhs: qm31) -> qm31 { - qm31_sub(lhs, rhs) - } -} -impl qm31Mul of Mul { - fn mul(lhs: qm31, rhs: qm31) -> qm31 { - qm31_mul(lhs, rhs) - } -} -impl qm31Div of Div { - fn div(lhs: qm31, rhs: qm31) -> qm31 { - qm31_div(lhs, rhs.try_into().expect('qm31_div by 0')) - } -} - -impl QM31TryIntoNonZero of TryInto> { - fn try_into(self: qm31) -> Option> { - match qm31_is_zero(self) { - core::internal::OptionRev::None => None, - core::internal::OptionRev::Some(x) => Some(x), - } - } -} -impl QM31PartialEq of PartialEq { - fn eq(lhs: @qm31, rhs: @qm31) -> bool { - (*lhs - *rhs).is_zero() - } -} - -impl QM31Zero of crate::num::traits::Zero { - fn zero() -> qm31 { - qm31_const::<0, 0, 0, 0>() - } - - #[inline] - fn is_zero(self: @qm31) -> bool { - match qm31_is_zero(*self) { - core::internal::OptionRev::None => true, - core::internal::OptionRev::Some(_) => false, - } - } - - #[inline] - fn is_non_zero(self: @qm31) -> bool { - !self.is_zero() - } -} - -impl M31IntoQM31 of Into { - fn into(self: m31) -> qm31 { - qm31_from_m31(self) - } -} - -/// Additional `m31` actions for specific implementations based on `qm31` opcode. -pub mod m31_ops { - use super::m31; - - /// Addition of `m31`s in field. - extern fn m31_add(a: m31, b: m31) -> m31 nopanic; - /// Subtraction of `m31`s in field. - extern fn m31_sub(a: m31, b: m31) -> m31 nopanic; - /// Multiplication of `m31`s in field. - extern fn m31_mul(a: m31, b: m31) -> m31 nopanic; - /// Division of `m31`s in field. - extern fn m31_div(a: m31, b: NonZero) -> m31 nopanic; - - pub use {m31_add as add, m31_div as div, m31_mul as mul, m31_sub as sub}; -} diff --git a/corelib/src/result.cairo b/corelib/src/result.cairo deleted file mode 100644 index f6c82f99da..0000000000 --- a/corelib/src/result.cairo +++ /dev/null @@ -1,725 +0,0 @@ -//! Error handling with the `Result` type. -//! -//! [`Result`] is the type used for returning and propagating -//! errors. It is an enum with the variants, [`Ok(T)`], representing -//! success and containing a value, and [`Err(E)`], representing error -//! and containing an error value. -//! -//! ``` -//! enum Result { -//! Ok: T, -//! Err: E, -//! } -//! ``` -//! -//! Functions return [`Result`] whenever errors are expected and -//! recoverable. -//! -//! A simple function returning [`Result`] might be -//! defined and used like so: -//! -//! ``` -//! fn parse_version(header: felt252) -> Result { -//! match header { -//! 0 => Ok(0), -//! 1 => Ok(1), -//! _ => Err('invalid version'), -//! } -//! } -//! -//! let version = parse_version(1); -//! match version { -//! Ok(v) => println!("working with version {}", v), -//! Err(e) => println!("error parsing version: {:?}", e) -//! } -//! ``` -//! -//! # Results must be used -//! -//! A common problem with using return values to indicate errors is -//! that it is easy to ignore the return value, thus failing to handle -//! the error. [`Result`] is annotated with the `#[must_use]` attribute, -//! which will cause the compiler to issue a warning when a Result -//! value is ignored. -//! -//! # Method overview -//! -//! In addition to working with pattern matching, [`Result`] provides a wide -//! variety of different methods. -//! -//! ## Querying the variant -//! -//! The [`is_ok`] and [`is_err`] methods return `true` if the [`Result`] -//! is [`Ok`] or [`Err`], respectively. -//! -//! ## Extracting contained values -//! -//! These methods extract the contained value in a [`Result`] when it -//! is the [`Ok`] variant. If the [`Result`] is [`Err`]: -//! -//! * [`expect`] panics with a provided felt252 error message -//! * [`unwrap`] panics with a generic message -//! * [`unwrap_or`] returns the provided default value -//! * [`unwrap_or_default`] returns the default value of the type `T` (which must implement the -//! [`Default`] trait) -//! * [`unwrap_or_else`] returns the result of evaluating the provided function -//! -//! [`expect`]: ResultTrait::expect -//! [`unwrap`]: ResultTrait::unwrap -//! [`unwrap_or`]: ResultTrait::unwrap_or -//! [`unwrap_or_default`]: ResultTrait::unwrap_or_default -//! [`unwrap_or_else`]: ResultTrait::unwrap_or_else -//! -//! These methods extract the contained value in a [`Result`] when it -//! is the [`Err`] variant. If the [`Result`] is [`Ok`]: -//! -//! * [`expect_err`] panics with a provided felt252 error message -//! * [`unwrap_err`] panics with a generic message -//! -//! [`expect_err`]: ResultTrait::expect_err -//! [`unwrap_err`]: ResultTrait::unwrap_err -//! -//! ## Transforming contained values -//! -//! These methods transform [`Result`] to [`Option`]: -//! -//! * [`ok`] transforms [`Result`] into [`Option`], mapping -//! [`Ok(v)`] to [`Some(v)`] and [`Err(e)`] to [`None`] -//! * [`err`] transforms [`Result`] into [`Option`], mapping -//! [`Ok(v)`] to [`None`] and [`Err(e)`] to [`Some(e)`] -//! -//! This method transforms the contained value of the [`Ok`] variant: -//! -//! * [`map`] transforms [`Result`] into [`Result`] by applying -//! the provided function to the contained value of [`Ok`] and leaving -//! [`Err`] values unchanged -//! -//! [`map`]: ResultTrait::map -//! -//! This method transforms the contained value of the [`Err`] variant: -//! -//! * [`map_err`] transforms [`Result`] into [`Result`] by -//! applying the provided function to the contained value of [`Err`] and -//! leaving [`Ok`] values unchanged -//! -//! [`map_err`]: ResultTrait::map_err -//! -//! These methods transform a [`Result`] into a value of a possibly -//! different type `U`: -//! -//! * [`map_or`] applies the provided function to the contained value of -//! [`Ok`], or returns the provided default value if the [`Result`] is -//! [`Err`] -//! * [`map_or_else`] applies the provided function to the contained value -//! of [`Ok`], or applies the provided default fallback function to the -//! contained value of [`Err`] -//! -//! [`map_or`]: ResultTrait::map_or -//! [`map_or_else`]: ResultTrait::map_or_else -//! -//! ## Boolean operators -//! -//! These methods treat the [`Result`] as a boolean value, where [`Ok`] -//! acts like [`true`] and [`Err`] acts like [`false`]. There are two -//! categories of these methods: ones that take a [`Result`] as input, and -//! ones that take a function as input. -//! -//! The [`and`] and [`or`] methods take another [`Result`] as input, and -//! produce a [`Result`] as output. The [`and`] method can produce a -//! [`Result`] value having a different inner type `U` than -//! [`Result`]. The [`or`] method can produce a [`Result`] -//! value having a different error type `F` than [`Result`]. -//! -//! | method | self | input | output | -//! |---------|----------|-----------|----------| -//! | [`and`] | `Err(e)` | (ignored) | `Err(e)` | -//! | [`and`] | `Ok(x)` | `Err(d)` | `Err(d)` | -//! | [`and`] | `Ok(x)` | `Ok(y)` | `Ok(y)` | -//! | [`or`] | `Err(e)` | `Err(d)` | `Err(d)` | -//! | [`or`] | `Err(e)` | `Ok(y)` | `Ok(y)` | -//! | [`or`] | `Ok(x)` | (ignored) | `Ok(x)` | -//! -//! [`and`]: ResultTrait::and -//! [`or`]: ResultTrait::or -//! -//! The [`and_then`] and [`or_else`] methods take a function as input, and -//! only evaluate the function when they need to produce a new value. The -//! [`and_then`] method can produce a [`Result`] value having a -//! different inner type `U` than [`Result`]. The [`or_else`] method -//! can produce a [`Result`] value having a different error type `F` -//! than [`Result`]. -//! -//! | method | self | function input | function result | output | -//! |--------------|----------|----------------|-----------------|----------| -//! | [`and_then`] | `Err(e)` | (not provided) | (not evaluated) | `Err(e)` | -//! | [`and_then`] | `Ok(x)` | `x` | `Err(d)` | `Err(d)` | -//! | [`and_then`] | `Ok(x)` | `x` | `Ok(y)` | `Ok(y)` | -//! | [`or_else`] | `Err(e)` | `e` | `Err(d)` | `Err(d)` | -//! | [`or_else`] | `Err(e)` | `e` | `Ok(y)` | `Ok(y)` | -//! | [`or_else`] | `Ok(x)` | (not provided) | (not evaluated) | `Ok(x)` | -//! -//! [`and_then`]: ResultTrait::and_then -//! [`or_else`]: ResultTrait::or_else -//! -//! # The question mark operator, `?` -//! -//! When writing code that calls many functions that return the [`Result`] type, -//! handling `Ok`/`Err` can be tedious. The question mark operator, `?`, -//! hides some of the boilerplate of propagating errors up the call stack. -//! -//! It replaces this: -//! -//! ``` -//! use core::integer::u8_overflowing_add; -//! -//! fn add_three_numbers(a: u8, b: u8, c: u8) -> Result { -//! match u8_overflowing_add(a, b) { -//! Ok(sum_ab) => { -//! match u8_overflowing_add(sum_ab, c) { -//! Ok(total) => Ok(total), -//! Err(e) => Err(e), -//! } -//! }, -//! Err(e) => Err(e), -//! } -//! } -//! ``` -//! -//! With this: -//! -//! ``` -//! use core::integer::u8_overflowing_add; -//! -//! fn add_three_numbers_2(a: u8, b: u8, c: u8) -> Result { -//! let total = u8_overflowing_add(u8_overflowing_add(a, b)?, c)?; -//! Ok(total) -//! } -//! ``` -//! -//! *It's much nicer!* -//! -//! [`Ok`]: Ok -//! [`Err`]: Err -//! -//! ## Iterating over `Result` -//! -//! A [`Result`] can be iterated over. This can be helpful if you need an -//! iterator that is conditionally empty. The iterator will either produce -//! a single value (when the [`Result`] is [`Ok`]), or produce no values -//! (when the [`Result`] is [`Err`]). For example, [`into_iter`] -//! contains [`Some(v)`] if the [`Result`] is [`Ok(v)`], and [`None`] if the -//! [`Result`] is [`Err`]. -//! -//! [`into_iter`]: IntoIterator::into_iter - -#[allow(unused_imports)] -use crate::array::{ArrayTrait, SpanTrait}; -#[allow(unused_imports)] -use crate::serde::Serde; - -/// The type used for returning and propagating errors. It is an enum with the variants `Ok: T`, -/// representing success and containing a value, and `Err: E`, representing error and containing an -/// error value. -#[must_use] -#[derive(Copy, Drop, Debug, Serde, PartialEq)] -pub enum Result { - Ok: T, - Err: E, -} - -/// A trait for handling `Result` related operations. -#[generate_trait] -pub impl ResultTraitImpl of ResultTrait { - /// Returns the contained `Ok` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an `Err`, with the provided `felt252` panic message. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.expect('no value') == 123); - /// ``` - const fn expect<+PanicDestruct>(self: Result, err: felt252) -> T { - match self { - Ok(x) => x, - Err(_) => crate::panic_with_felt252(err), - } - } - - /// Returns the contained `Ok` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an `Err`, with a standard `Result::unwrap failed` panic message. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.unwrap() == 123); - /// ``` - const fn unwrap<+Destruct>(self: Result) -> T { - self.expect('Result::unwrap failed.') - } - - /// Returns the contained `Ok` value or a provided default. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.unwrap_or(456) == 123); - /// - /// let result: Result = Err('no value'); - /// assert!(result.unwrap_or(456) == 456); - /// ``` - const fn unwrap_or<+Destruct, +Destruct>(self: Result, default: T) -> T { - match self { - Ok(x) => x, - Err(_) => default, - } - } - - /// Returns the contained `Ok` value or `Default::::default()`. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.unwrap_or_default() == 123); - /// - /// let result: Result = Err('no value'); - /// assert!(result.unwrap_or_default() == 0); - /// ``` - fn unwrap_or_default<+Destruct, +Default>(self: Result) -> T { - match self { - Ok(x) => x, - Err(_) => Default::default(), - } - } - - /// Returns the contained [`Ok`] value or computes it from a closure. - /// - /// - /// # Examples - /// - /// ``` - /// assert!(Ok(2).unwrap_or_else(|e: ByteArray| e.len()) == 2); - /// assert!(Err("foo").unwrap_or_else(|e: ByteArray| e.len()) == 3); - /// ``` - #[inline] - fn unwrap_or_else, +Drop, +core::ops::FnOnce[Output: T]>( - self: Result, f: F, - ) -> T { - match self { - Ok(x) => x, - Err(e) => f(e), - } - } - - /// Returns `other` if the result is `Ok`, otherwise returns the `Err` value of `self`. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Ok(2); - /// let y: Result = Err("late error"); - /// assert!(x.and(y) == Err("late error")); - /// - /// let x: Result = Err("early error"); - /// let y: Result = Ok("foo"); - /// assert!(x.and(y) == Err("early error")); - /// - /// let x: Result = Err("not a 2"); - /// let y: Result = Err("late error"); - /// assert!(x.and(y) == Err("not a 2")); - /// - /// let x: Result = Ok(2); - /// let y: Result = Ok("different result type"); - /// assert!(x.and(y) == Ok("different result type")); - /// ``` - #[inline] - fn and, +Drop, +Drop>( - self: Result, other: Result, - ) -> Result { - match self { - Ok(_) => other, - Err(e) => Err(e), - } - } - - /// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`. - /// - /// This function can be used for control flow based on `Result` values. - /// - /// # Examples - /// - /// ``` - /// use core::num::traits::CheckedMul; - /// - /// fn sq_then_string(x: u32) -> Result { - /// let res = x.checked_mul(x).ok_or("overflowed"); - /// res.and_then(|v| Ok(format!("{}", v))) - /// } - /// - /// let x = sq_then_string(4); - /// assert!(x == Ok("16")); - /// - /// let y = sq_then_string(65536); - /// assert!(y == Err("overflowed")); - /// ``` - #[inline] - fn and_then, +core::ops::FnOnce[Output: Result]>( - self: Result, op: F, - ) -> Result { - match self { - Ok(t) => op(t), - Err(e) => Err(e), - } - } - - /// Returns `other` if the result is `Err`, otherwise returns the `Ok` value of `self`. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Ok(2); - /// let y: Result = Err("late error"); - /// assert!(x.or(y) == Ok(2)); - /// - /// let x: Result = Err("early error"); - /// let y: Result = Ok(2); - /// assert!(x.or(y) == Ok(2)); - /// - /// let x: Result = Err("not a 2"); - /// let y: Result = Err("late error"); - /// assert!(x.or(y) == Err("late error")); - /// - /// let x: Result = Ok(2); - /// let y: Result = Ok(100); - /// assert!(x.or(y) == Ok(2)); - /// ``` - #[inline] - fn or, +Drop, +Destruct>( - self: Result, other: Result, - ) -> Result { - match self { - Ok(v) => Ok(v), - Err(_) => other, - } - } - - /// Calls `op` if the result is `Err`, otherwise returns the `Ok` value of `self`. - /// - /// This function can be used for control flow based on result values. - /// - /// # Examples - /// - /// ``` - /// let x: Result:: = Result::::Err("bad input") - /// .or_else(|_e| Ok(42)); - /// assert!(x == Ok(42)); - /// - /// let y: Result:: = Result::::Err("bad input") - /// .or_else(|_e| Err("not 42")); - /// assert!(y == Err("not 42")); - /// - /// let z: Result:: = Result::::Ok(100) - /// .or_else(|_e| Ok(42)); - /// assert!(z == Ok(100)); - /// ``` - #[inline] - fn or_else, +core::ops::FnOnce[Output: Result]>( - self: Result, op: O, - ) -> Result { - match self { - Ok(t) => Ok(t), - Err(e) => op(e), - } - } - - /// Returns the contained `Err` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an `Ok`, with the provided `felt252` panic message. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Err('no value'); - /// assert!(result.expect_err('result is ok') == 'no value'); - /// ``` - const fn expect_err<+PanicDestruct>(self: Result, err: felt252) -> E { - match self { - Ok(_) => crate::panic_with_felt252(err), - Err(x) => x, - } - } - - /// Returns the contained `Err` value, consuming the `self` value. - /// - /// # Panics - /// - /// Panics if the value is an `Ok`, with a standard `Result::unwrap_err failed.` panic message. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Err('no value'); - /// assert!(result.unwrap_err() == 'no value'); - /// ``` - const fn unwrap_err<+PanicDestruct>(self: Result) -> E { - self.expect_err('Result::unwrap_err failed.') - } - - /// Returns `true` if the `Result` is `Ok`. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.is_ok()); - /// ``` - #[inline] - fn is_ok(self: @Result) -> bool { - match self { - Ok(_) => true, - Err(_) => false, - } - } - - /// Returns `true` if the `Result` is `Err`. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(!result.is_err()); - /// ``` - #[inline] - fn is_err(self: @Result) -> bool { - match self { - Ok(_) => false, - Err(_) => true, - } - } - - /// Returns `true` if the `Result` is `Ok`, and consumes the value. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(result.into_is_ok()); - /// ``` - #[inline] - fn into_is_ok<+Destruct, +Destruct>(self: Result) -> bool { - match self { - Ok(_) => true, - Err(_) => false, - } - } - - /// Returns `true` if the `Result` is `Err`, and consumes the value. - /// - /// # Examples - /// - /// ``` - /// let result: Result = Ok(123); - /// assert!(!result.into_is_err()); - /// ``` - #[inline] - fn into_is_err<+Destruct, +Destruct>(self: Result) -> bool { - match self { - Ok(_) => false, - Err(_) => true, - } - } - - /// Converts from `Result` to `Option`. - /// - /// Converts `self` into an `Option`, consuming `self`, - /// and discarding the error, if any. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Ok(2); - /// assert!(x.ok() == Some(2)); - /// - /// let x: Result = Err("Nothing here"); - /// assert!(x.ok().is_none()); - /// ``` - fn ok<+Destruct, +Destruct>(self: Result) -> Option { - match self { - Ok(x) => Some(x), - Err(_) => None, - } - } - - /// Converts from `Result` to `Option`. - /// - /// Converts `self` into an `Option`, consuming `self`, - /// and discarding the success value, if any. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Err("Nothing here"); - /// assert!(x.err() == Some("Nothing here")); - /// - /// let x: Result = Ok(2); - /// assert!(x.err().is_none()); - /// ``` - fn err<+Destruct, +Destruct>(self: Result) -> Option { - match self { - Ok(_) => None, - Err(x) => Some(x), - } - } - - /// Maps a `Result` to `Result` by applying a function to a - /// contained [`Ok`] value, leaving an [`Err`] value untouched. - /// - /// This function can be used to compose the results of two functions. - /// - /// # Examples - /// - /// Print the square of the number contained in the `Result`, otherwise print the error. - /// - /// ``` - /// let inputs: Array> = array![ - /// Ok(1), Err("error"), Ok(3), Ok(4), - /// ]; - /// for i in inputs { - /// match i.map(|i| i * 2) { - /// Ok(x) => println!("{x}"), - /// Err(e) => println!("{e}"), - /// } - /// } - /// ``` - #[inline] - fn map, +core::ops::FnOnce[Output: U]>( - self: Result, f: F, - ) -> Result { - match self { - Ok(x) => Ok(f(x)), - Err(e) => Err(e), - } - } - - /// Returns the provided default (if [`Err`]), or - /// applies a function to the contained value (if [`Ok`]). - /// - /// # Examples - /// - /// ``` - /// let x: Result<_, ByteArray> = Ok("foo"); - /// assert!(x.map_or(42, |v: ByteArray| v.len()) == 3); - /// - /// let x: Result<_, ByteArray> = Err("bar"); - /// assert!(x.map_or(42, |v: ByteArray| v.len()) == 42); - /// ``` - #[inline] - fn map_or, +Destruct, +Drop, +core::ops::FnOnce[Output: U]>( - self: Result, default: U, f: F, - ) -> U { - match self { - Ok(x) => f(x), - Err(_) => default, - } - } - - /// Maps a `Result` to `U` by applying fallback function `default` to - /// a contained [`Err`] value, or function `f` to a contained [`Ok`] value. - /// - /// This function can be used to unpack a successful result - /// while handling an error. - /// - /// - /// # Examples - /// - /// ``` - /// let k = 21; - /// - /// let x: Result = Ok("foo"); - /// assert!(x.map_or_else(|_e: ByteArray| k * 2, |v: ByteArray| v.len()) == 3); - /// - /// let x: Result<_, ByteArray> = Err("bar"); - /// assert!(x.map_or_else(|_e: ByteArray| k * 2, |v: ByteArray| v.len()) == 42); - /// ``` - #[inline] - fn map_or_else< - U, - D, - F, - +Drop, - +Drop, - +core::ops::FnOnce[Output: U], - +core::ops::FnOnce[Output: U], - >( - self: Result, default: D, f: F, - ) -> U { - match self { - Ok(t) => f(t), - Err(e) => default(e), - } - } - - /// Maps a `Result` to `Result` by applying a function to a - /// contained [`Err`] value, leaving an [`Ok`] value untouched. - /// - /// This function can be used to pass through a successful result while handling - /// an error. - /// - /// - /// # Examples - /// - /// ``` - /// let stringify = |x: u32| -> ByteArray { format!("error code: {x}") }; - /// let x: Result = Ok(2); - /// assert!(x.map_err(stringify) == Result::::Ok(2)); - /// - /// let x: Result = Err(13); - /// assert!(x.map_err(stringify) == Err("error code: 13")); - /// ``` - fn map_err, +core::ops::FnOnce[Output: F]>( - self: Result, op: O, - ) -> Result { - match self { - Ok(x) => Ok(x), - Err(e) => Err(op(e)), - } - } -} - - -impl ResultIntoIterator< - T, E, +Destruct, +Destruct, -> of crate::iter::IntoIterator> { - type IntoIter = crate::option::OptionIter; - - /// Returns a consuming iterator over the possibly contained value. - /// - /// The iterator yields one value if the result is [`Ok`], otherwise none. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Ok(5); - /// let mut x_iter = x.into_iter(); - /// assert!(x_iter.next() == Some(5)); - /// - /// let x: Result = Err("nothing!"); - /// let mut x_iter = x.into_iter(); - /// assert!(x_iter.next() == None); - /// ``` - #[inline] - fn into_iter(self: Result) -> crate::option::OptionIter { - self.ok().into_iter() - } -} diff --git a/corelib/src/serde.cairo b/corelib/src/serde.cairo deleted file mode 100644 index 24e674de24..0000000000 --- a/corelib/src/serde.cairo +++ /dev/null @@ -1,134 +0,0 @@ -//! Serialization and deserialization of data structures. -//! -//! This module provides traits and implementations for converting Cairo types into a sequence of -//! `felt252` values (serialization) and back (deserialization). -//! -//! When passing values between Cairo and an external environment, serialization and deserialization -//! are necessary to convert Cairo's data types into a sequence of `felt252` values, as `felt252` is -//! the fundamental type of the language. -//! -//! # The `Serde` Trait -//! -//! All types that need to be serialized must implement the `Serde` trait. This includes both simple -//! types that serialize to a single `felt252` and compound types (like `u256`) that require -//! multiple `felt252` values. - -#[allow(unused_imports)] -use crate::array::{ArrayTrait, SpanTrait}; - -/// A trait that allows for serializing and deserializing values of any type. -/// -/// The `Serde` trait defines two core operations: -/// - `serialize`: Converts a value into a sequence of `felt252`s -/// - `deserialize`: Reconstructs a value from a sequence of `felt252`s -/// -/// # Examples -/// -/// ## Simple Types (u8, u16, u32, u64, u128) -/// -/// Simple types are serialized into a single `felt252`: -/// -/// ``` -/// let value: u8 = 42; -/// let mut output: Array = array![]; -/// value.serialize(ref output); -/// assert!(output == array![42]); // Single value -/// ``` -/// -/// ## Compound Types (u256) -/// -/// Compound types may be serialized into multiple `felt252` values: -/// -/// ``` -/// let value: u256 = u256 { low: 1, high: 2 }; -/// let mut output: Array = array![]; -/// value.serialize(ref output); -/// assert!(output == array![1, 2]); // Two `felt252`s: low and high -/// ``` -/// -/// # Implementing `Serde` -/// -/// ## Using the `Derive` Macro -/// -/// In most cases, you can use the `#[derive(Serde)]` attribute to automatically generate the -/// implementation for your type: -/// -/// ``` -/// #[derive(Serde)] -/// struct Point { -/// x: u32, -/// y: u32 -/// } -/// ``` -/// -/// ## Manual Implementation -/// -/// Should you need to customize the serialization behavior for a type in a way that derive does not -/// support, you can implement the `Serde` yourself: -/// -/// ``` -/// impl PointSerde of Serde { -/// fn serialize(self: @Point, ref output: Array) { -/// output.append((*self.x).into()); -/// output.append((*self.y).into()); -/// } -/// -/// fn deserialize(ref serialized: Span) -> Option { -/// let x = (*serialized.pop_front()?).try_into()?; -/// let y = (*serialized.pop_front()?).try_into()?; -/// -/// Some(Point { x, y }) -/// } -/// } -/// ``` -pub trait Serde { - /// Serializes a value into a sequence of `felt252`s. - /// - /// # Examples - /// - /// ``` - /// let value: u256 = 1; - /// let mut serialized: Array = array![]; - /// value.serialize(ref serialized); - /// assert!(serialized == array![1, 0]); // `serialized` contains the [low, high] parts of the - /// `u256` value ``` - fn serialize(self: @T, ref output: Array); - - /// Deserializes a value from a sequence of `felt252`s. - /// If the value cannot be deserialized, returns `None`. - /// - /// # Examples - /// - /// ``` - /// let mut serialized: Span = array![1, 0].span(); - /// let value: u256 = Serde::deserialize(ref serialized).unwrap(); - /// assert!(value == 1); - /// ``` - fn deserialize(ref serialized: Span) -> Option; -} - - -pub mod into_felt252_based { - use crate::array::ArrayTrait; - use crate::traits::{Into, TryInto}; - - /// A generic `Serde` implementation for types that can be converted into `felt252` using the - /// `Into` trait and from `felt252` using the `TryInto` trait. - /// - /// # Examples - /// - /// ``` - /// impl MyTypeSerde = core::serde::into_felt252_based::SerdeImpl; - /// ``` - pub impl SerdeImpl, +Into, +TryInto> of super::Serde { - #[inline] - fn serialize(self: @T, ref output: Array) { - output.append((*self).into()); - } - - #[inline] - fn deserialize(ref serialized: Span) -> Option { - Some((*serialized.pop_front()?).try_into()?) - } - } -} diff --git a/corelib/src/sha256.cairo b/corelib/src/sha256.cairo deleted file mode 100644 index 6071ef6337..0000000000 --- a/corelib/src/sha256.cairo +++ /dev/null @@ -1,319 +0,0 @@ -//! Implementation of the SHA-256 cryptographic hash function. -//! -//! This module provides functions to compute SHA-256 hashes of data. -//! The input data can be an array of 32-bit words, or a `ByteArray`. -//! -//! # Examples -//! -//! ``` -//! use core::sha256::compute_sha256_byte_array; -//! -//! let data = "Hello"; -//! let hash = compute_sha256_byte_array(@data); -//! assert!(hash == [0x185f8db3, 0x2271fe25, 0xf561a6fc, 0x938b2e26, 0x4306ec30, 0x4eda5180, -//! 0x7d17648, 0x26381969]); -//! ``` -#[feature("byte-span")] -use core::byte_array::ToByteSpanTrait; -#[feature("bounded-int-utils")] -use core::internal::bounded_int::{BoundedInt, downcast, upcast}; -use starknet::SyscallResultTrait; - -/// A handle to the state of a SHA-256 hash. -pub(crate) extern type Sha256StateHandle; - -impl Sha256StateHandleCopy of Copy; -impl Sha256StateHandleDrop of Drop; - -/// Initializes a new SHA-256 state handle with the given initial state. -extern fn sha256_state_handle_init(state: Box<[u32; 8]>) -> Sha256StateHandle nopanic; - -/// Returns the final state of a SHA-256 hash computation. -extern fn sha256_state_handle_digest(state: Sha256StateHandle) -> Box<[u32; 8]> nopanic; - -/// Initial hash values for SHA-256 as specified in FIPS 180-4. -const SHA256_INITIAL_STATE: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -]; - -/// Computes the SHA-256 hash of an input provided as 32-bit words, with optional trailing bytes. -/// -/// # Note -/// -/// For better type safety, consider using `compute_sha256_u32_array_safe` when -/// `last_input_num_bytes` is guaranteed to be in the range 0..=3. -/// -/// # Arguments -/// -/// * `input` - The main input, expressed as an array of `u32` words. -/// * `last_input_word` - A partial final word containing any remaining bytes when the input is not -/// word-aligned. -/// * `last_input_num_bytes` - The number of valid bytes in `last_input_word`. Must be in the range -/// 0..=3. -/// -/// # Panics -/// -/// * If `last_input_num_bytes` is greater than 3. -/// -/// # Returns -/// -/// * The SHA-256 hash of `input` followed by the `last_input_num_bytes` most significant bytes of -/// `last_input_word`, interpreted in big-endian order. -/// -/// # Examples -/// -/// ``` -/// use core::sha256::compute_sha256_u32_array; -/// -/// let hash = compute_sha256_u32_array(array![0x68656c6c], 0x6f, 1); -/// assert!(hash == [0x2cf24dba, 0x5fb0a30e, 0x26e83b2a, 0xc5b9e29e, 0x1b161e5c, 0x1fa7425e, -/// 0x73043362, 0x938b9824]); -/// ``` -pub fn compute_sha256_u32_array( - mut input: Array, last_input_word: u32, last_input_num_bytes: u32, -) -> [u32; 8] { - let last_input_num_bytes = downcast(last_input_num_bytes).expect('`last_input_num_bytes` > 3'); - compute_sha256_u32_array_safe(input, last_input_word, last_input_num_bytes) -} - -/// A type representing a bounded integer in the range `0..=3`. -pub type u2 = BoundedInt<0, 3>; - -/// Computes the SHA-256 hash of an input provided as 32-bit words, with optional trailing bytes. -/// -/// # Arguments -/// -/// * `input` - The main input, expressed as an array of `u32` words. -/// * `last_input_word` - A partial final word containing any remaining bytes when the input is not -/// word-aligned. -/// * `last_input_num_bytes` - The number of valid bytes in `last_input_word`. -/// -/// # Returns -/// -/// * The SHA-256 hash of `input` followed by the `last_input_num_bytes` most significant bytes of -/// `last_input_word`, interpreted in big-endian order. -/// -/// # Examples -/// -/// ``` -/// use core::sha256::compute_sha256_u32_array_safe; -/// -/// let hash = compute_sha256_u32_array_safe(array![0x68656c6c], 0x6f, 1); -/// assert!(hash == [0x2cf24dba, 0x5fb0a30e, 0x26e83b2a, 0xc5b9e29e, 0x1b161e5c, 0x1fa7425e, -/// 0x73043362, 0x938b9824]); -/// ``` -pub fn compute_sha256_u32_array_safe( - mut input: Array, last_input_word: u32, last_input_num_bytes: u2, -) -> [u32; 8] { - add_sha256_padding(ref input, last_input_word, last_input_num_bytes); - - let mut input = input.span(); - let mut state = sha256_state_handle_init(BoxTrait::new(SHA256_INITIAL_STATE)); - - while let Some(chunk) = input.multi_pop_front() { - state = starknet::syscalls::sha256_process_block_syscall(state, *chunk).unwrap_syscall(); - } - - sha256_state_handle_digest(state).unbox() -} - -/// Computes the SHA-256 hash of the input `ByteArray`. -/// -/// # Examples -/// -/// ``` -/// use core::sha256::compute_sha256_byte_array; -/// -/// let data = "Hello"; -/// let hash = compute_sha256_byte_array(@data); -/// assert!(hash == [0x185f8db3, 0x2271fe25, 0xf561a6fc, 0x938b2e26, 0x4306ec30, 0x4eda5180, -/// 0x7d17648, 0x26381969]); -/// ``` -pub fn compute_sha256_byte_array(arr: @ByteArray) -> [u32; 8] { - let mut iter = arr.span().into_iter(); - let mut word_arr = array![]; - - let (last_word, last_word_len) = loop { - let Some(b0) = iter.next() else { - break (0, 0); - }; - let Some(b1) = iter.next() else { - break (upcast(b0), 1); - }; - let b0_b1 = conversions::shift_append_byte(b0, b1); - let Some(b2) = iter.next() else { - break (upcast(b0_b1), 2); - }; - let b0_b1_b2 = conversions::shift_append_byte(b0_b1, b2); - let Some(b3) = iter.next() else { - break (upcast(b0_b1_b2), 3); - }; - - word_arr.append(upcast(conversions::shift_append_byte(b0_b1_b2, b3))); - }; - - compute_sha256_u32_array_safe(word_arr, last_word, last_word_len) -} - -/// Adds padding to the input array according to the SHA-256 specification. -/// -/// The padding follows FIPS 180-4: -/// 1. Append a single '1' bit to the message. -/// 2. Append zeros until data length ≡ 448 (mod 512). -/// 3. Append the original message length as a 64-bit big-endian integer. -/// This implementation is made for provable execution and assumes the message bit length -/// fits in 32 bits, with the high 32 bits of the 64-bit length field being zero. -/// -/// # Arguments -/// * `arr` - Array to pad (modified in place) -/// * `last_input_word` - A partial final word containing any remaining bytes when the input is not -/// word-aligned. -/// * `last_input_num_bytes` - The number of valid bytes in `last_input_word`. -fn add_sha256_padding(ref arr: Array, last_input_word: u32, last_input_num_bytes: u2) { - let bitlen = conversions::bitlen(arr.len(), last_input_num_bytes); - arr.append(conversions::to_last_word(last_input_word, last_input_num_bytes)); - // Now writing the length in bits, at the end of a block. - // We always need to append a zero to the array, as the length is actually the two last u32 - // words, in which we assume the least significant is enough. - let zero = 0; - arr.append(zero); - // Now we make sure we fill all the remaining space in the block, without the last word. - let mut remaining = 15 - (arr.len() % 16).into(); - repeatedly_append_value(ref arr, remaining, zero); - arr.append(bitlen); -} - -/// Appends `count` `value`s to the array. -fn repeatedly_append_value(ref arr: Array, count: felt252, value: u32) { - let mut remaining = count; - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 0`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 1`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 2`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 3`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 4`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 5`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 6`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 7`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 8`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 9`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 10`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 11`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 12`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 13`. - dec_and_append_or_return!(remaining, arr, value); // returns if `count == 14`. -} - -/// Macro to decrement a counter and append a value to an array, or return if the counter is value. -macro dec_and_append_or_return { - ($remaining: ident, $arr: ident, $value: ident) => { - if $remaining == 0 { - return; - } - $remaining -= 1; - $arr.append($value); - }; -} - -mod conversions { - #[feature("bounded-int-utils")] - use core::internal::bounded_int::{ - self, AddHelper, BoundedInt, DivRemHelper, MulHelper, UnitInt, - }; - use super::u2; - - impl U8Shift of MulHelper> { - type Result = BoundedInt<0, 0xFF00>; - } - impl U8ShiftAddU8 of AddHelper { - type Result = BoundedInt<0, 0xFFFF>; - } - impl U16Shift of MulHelper> { - type Result = BoundedInt<0, 0xFFFF00>; - } - impl U16ShiftAddU8 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFF>; - } - impl U24Shift of MulHelper> { - type Result = BoundedInt<0, 0xFFFFFF00>; - } - impl U24ShiftAddU8 of AddHelper { - type Result = BoundedInt<0, 0xFFFFFFFF>; - } - trait ShiftAppendByte { - impl Mul: MulHelper>; - impl Add: AddHelper; - } - - // Blanket implementation for any type with appropriate helpers. - impl ShiftAppendByteImpl< - T, impl MH: MulHelper>, impl AH: AddHelper, - > of ShiftAppendByte {} - - /// Shifts a word left by one byte position and appends a new byte. - pub fn shift_append_byte< - T, - MulResult, - impl SAB: ShiftAppendByte, - +core::metaprogramming::TypeEqual, - >( - word: T, byte: u8, - ) -> SAB::Add::Result { - bounded_int::add::<_, _, SAB::Add>(bounded_int::mul::<_, _, SAB::Mul>(word, 0x100), byte) - } - - impl DoubleU32 of MulHelper> { - type Result = BoundedInt<0, 0x1FFFFFFFE>; - } - - impl DoubleU32Inc of AddHelper, UnitInt<1>> { - type Result = BoundedInt<1, 0x1FFFFFFFF>; - } - - impl DoubleU32IncRightPadded of MulHelper, BoundedInt<0, 0x800000>> { - type Result = BoundedInt<0, 0xFFFFFFFF800000>; - } - - impl DoubleU32IncRightPaddedTrim of DivRemHelper< - BoundedInt<0, 0xFFFFFFFF800000>, UnitInt<0x100000000>, - > { - type DivT = BoundedInt<0, 0xFFFFFF>; - type RemT = BoundedInt<0, 0xFFFFFFFF>; - } - - /// Returns the last word to append to the input `u32` array given the last word input. - pub fn to_last_word(word: u32, len: u2) -> u32 { - let shift: BoundedInt<0, 0x800000> = match len { - 0 => { return 0x80000000; }, - 1 => 0x800000, - 2 => 0x8000, - _ => 0x80, - }; - let doubled = bounded_int::mul::<_, _, DoubleU32>(word, 2); - let incremented = bounded_int::add::<_, _, DoubleU32Inc>(doubled, 1); - let result = bounded_int::mul::<_, _, DoubleU32IncRightPadded>(incremented, shift); - // For backwards compatibility, we make sure to ignore high bits. - let (_, r) = bounded_int::div_rem::<_, _, DoubleU32IncRightPaddedTrim>(result, 0x100000000); - bounded_int::upcast(r) - } - - impl ArrBitLen of MulHelper> { - type Result = BoundedInt<0, 0x1FFFFFFFE0>; - } - - impl WordBitLen of MulHelper> { - type Result = BoundedInt<0, 0x18>; - } - - impl FullBitLen of AddHelper, BoundedInt<0, 0x18>> { - type Result = BoundedInt<0, { 0x1FFFFFFFE0 + 0x18 }>; - } - - /// Returns the bit length of the input message, given the length of the representation u32 - /// array and last word bytes. - pub fn bitlen(arr_len: u32, last_word_bytes: u2) -> u32 { - let arr_bits = bounded_int::mul::<_, _, ArrBitLen>(arr_len, 32); - let last_word_bits = bounded_int::mul::<_, _, WordBitLen>(last_word_bytes, 8); - bounded_int::downcast(bounded_int::add::<_, _, FullBitLen>(arr_bits, last_word_bits)) - .unwrap() - } -} diff --git a/corelib/src/starknet.cairo b/corelib/src/starknet.cairo deleted file mode 100644 index b5ed931079..0000000000 --- a/corelib/src/starknet.cairo +++ /dev/null @@ -1,152 +0,0 @@ -//! Functionalities for interacting with the Starknet network. -//! -//! # Core Components -//! -//! - **Storage**: The `storage` module defines abstractions on how to interact with Starknet -//! contract storage. -//! - **Syscalls**: The `syscalls` module contains the extern declarations for all the system calls -//! available in Starknet. -//! - **Contract Addresses**: The `contract_address` and `eth_address` modules provide types and -//! utilities for working with Starknet contract addresses and Ethereum addresses. -//! - **Cryptography**: The `secp256k1`, `secp256r1`, `secp256_trait`, and `eth_signature` modules -//! handle various elliptic curve operations. -//! - **Execution Info**: The `info` module exposes functions for accessing information about the -//! current contract execution, such as the caller address, contract address, block info, and -//! transaction info. - -#[allow(unused_imports)] -use core::array::Span; -#[allow(unused_imports)] -use core::box::Box; -#[allow(unused_imports)] -use core::option::OptionTrait; -#[allow(unused_imports)] -use core::traits::{Into, TryInto}; -#[allow(unused_imports)] -use core::zeroable::Zeroable; - -pub mod storage_access; -pub use storage_access::{StorageAddress, Store}; -#[allow(unused_imports)] -use storage_access::{ - StorageBaseAddress, StorePacking, storage_address_from_base, - storage_address_from_base_and_offset, storage_address_to_felt252, - storage_address_try_from_felt252, storage_base_address_const, storage_base_address_from_felt252, -}; - -pub mod syscalls; -#[allow(unused_imports)] -use syscalls::{ - call_contract_syscall, deploy_syscall, emit_event_syscall, get_block_hash_syscall, - get_class_hash_at_syscall, get_execution_info_syscall, keccak_syscall, library_call_syscall, - replace_class_syscall, send_message_to_l1_syscall, storage_read_syscall, storage_write_syscall, -}; - -pub mod contract_address; - -pub mod secp256_trait; -pub mod secp256k1; -pub mod secp256r1; -pub use contract_address::ContractAddress; -#[deprecated( - feature: "deprecated-starknet-consts", - note: "Use `TryInto::try_into` in const context instead.", -)] -#[feature("deprecated-starknet-consts")] -pub use contract_address::contract_address_const; -#[allow(unused_imports)] -use contract_address::{ - ContractAddressIntoFelt252, Felt252TryIntoContractAddress, contract_address_to_felt252, - contract_address_try_from_felt252, -}; - -pub mod eth_address; -pub use eth_address::EthAddress; -#[allow(unused_imports)] -use eth_address::{ - EthAddressIntoFelt252, EthAddressSerde, EthAddressZeroable, Felt252TryIntoEthAddress, -}; - -pub mod eth_signature; -#[allow(unused_imports)] -use eth_signature::verify_eth_signature; - -pub mod class_hash; -pub use class_hash::ClassHash; -#[allow(unused_imports)] -#[deprecated( - feature: "deprecated-starknet-consts", - note: "Use `TryInto::try_into` in const context instead.", -)] -#[feature("deprecated-starknet-consts")] -use class_hash::class_hash_const; -#[allow(unused_imports)] -use class_hash::{ - ClassHashIntoFelt252, Felt252TryIntoClassHash, class_hash_to_felt252, - class_hash_try_from_felt252, -}; - -// Not `pub` on purpose, only used for direct reexport by the next line. -mod info; -pub use info::v2::{ExecutionInfo, ResourceBounds as ResourcesBounds, TxInfo}; -pub use info::{ - BlockInfo, get_block_info, get_block_number, get_block_timestamp, get_caller_address, - get_contract_address, get_execution_info, get_tx_info, -}; - -pub mod event; -pub use event::Event; - -pub mod account; -pub use account::AccountContract; - -pub mod storage; - -pub extern type System; - -// A helper function to force the inclusion of `System` in the list of implicits. -#[deprecated( - feature: "use_system_implicit", - note: "Use `core::internal::require_implicit::` instead.", -)] -fn use_system_implicit() implicits(System) {} - -/// The `Result` type for a syscall. -pub type SyscallResult = Result>; - -/// Trait for handling syscall results. -pub trait SyscallResultTrait { - /// Unwraps a syscall result, yielding the content of an `Ok`. - /// - /// # Panics - /// - /// Panics with the syscall error message if the value is an `Err`. - /// - /// # Examples - /// - /// ``` - /// let result = starknet::syscalls::get_execution_info_v2_syscall(); - /// let info = result.unwrap_syscall(); - /// ``` - fn unwrap_syscall(self: SyscallResult) -> T; -} - -impl SyscallResultTraitImpl of SyscallResultTrait { - fn unwrap_syscall(self: SyscallResult) -> T { - match self { - Ok(x) => x, - Err(revert_reason) => panic(revert_reason), - } - } -} - -/// The expected return value of the `__validate__` function in account contracts. -/// -/// This constant is used to indicate that a transaction validation was successful. -/// Account contracts must return this value from their `__validate__` function to -/// signal that the transaction should proceed. -pub const VALIDATED: felt252 = 'VALID'; - -pub mod deployment; - -pub mod testing; diff --git a/corelib/src/starknet/account.cairo b/corelib/src/starknet/account.cairo deleted file mode 100644 index c984957df1..0000000000 --- a/corelib/src/starknet/account.cairo +++ /dev/null @@ -1,919 +0,0 @@ -//! Account module defining the [`Call`] struct and the [`AccountContract`] trait. -//! -//! The `Call` struct represents a call to a contract, with the following fields: -//! - `to`: The address of the contract to call. -//! - `selector`: The entry point selector in the called contract. -//! - `calldata`: The calldata to pass to the entry point. -//! -//! The `AccountContract` trait defines the standard interface for account contracts. It assumes -//! that the calldata for invoke transactions is an `Array`, following the SNIP6 standard. -//! -//! Implementing this trait allows contracts to function as account contracts in the Starknet -//! network, supporting class declarations and batched call execution. - -use starknet::ContractAddress; - -/// A struct representing a call to a contract. -#[derive(Drop, Copy, Serde, Debug)] -pub struct Call { - /// The address of the contract to call. - pub to: ContractAddress, - /// The entry point selector in the called contract. - pub selector: felt252, - /// The calldata to pass to the entry point. - pub calldata: Span, -} - -/// A trait for account contracts that support class declarations (only `__validate__` and -/// `__execute__` are mandatory for an account). -/// -/// This trait assumes that the calldata for invoke transactions is `Array`. -/// This is the network standard following SNIP6. -/// It is not enforced by Starknet, but deviating from the standard interface may lead to -/// incompatibility with standard tooling. -#[starknet::interface] -pub trait AccountContract { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__(self: @TContractState, class_hash: felt252) -> felt252; - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__(ref self: TContractState, calls: Array) -> felt252; - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__(ref self: TContractState, calls: Array) -> Array>; -} - - -// Generate code. - -impl AccountContractDispatcherStore<> of starknet::Store { - fn read( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { - value: starknet::Store::< - starknet::ContractAddress, - >::read(__store_derive_address_domain__, __store_derive_base__)?, - }; - starknet::SyscallResult::Ok( - AccountContractDispatcher { contract_address: contract_address.value }, - ) - } - fn write( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - value: AccountContractDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let AccountContractDispatcher { contract_address } = value; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { value: contract_address }; - starknet::Store::< - starknet::ContractAddress, - >::write(__store_derive_address_domain__, __store_derive_base__, contract_address.value)?; - starknet::SyscallResult::Ok(()) - } - fn read_at_offset( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, offset: u8, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { - value: starknet::Store::< - starknet::ContractAddress, - >::read_at_offset( - __store_derive_address_domain__, __store_derive_base__, __store_derive_offset__, - )?, - }; - starknet::SyscallResult::Ok( - AccountContractDispatcher { contract_address: contract_address.value }, - ) - } - #[inline(always)] - fn write_at_offset( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - offset: u8, - value: AccountContractDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let AccountContractDispatcher { contract_address } = value; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { value: contract_address }; - starknet::Store::< - starknet::ContractAddress, - >::write_at_offset( - __store_derive_address_domain__, - __store_derive_base__, - __store_derive_offset__, - contract_address.value, - )?; - starknet::SyscallResult::Ok(()) - } - #[inline(always)] - fn size() -> u8 { - starknet::Store::::size() - } -} - -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractDispatcherSubPointers { - pub contract_address: starknet::storage::StoragePointer, -} -#[doc(hidden)] -impl AccountContractDispatcherSubPointersImpl of starknet::storage::SubPointers< - AccountContractDispatcher, -> { - type SubPointersType = AccountContractDispatcherSubPointers; - fn sub_pointers( - self: starknet::storage::StoragePointer, - ) -> AccountContractDispatcherSubPointers { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __contract_address_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractDispatcherSubPointers { contract_address: __contract_address_value__ } - } -} -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractDispatcherSubPointersMut { - pub contract_address: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, -} -#[doc(hidden)] -impl AccountContractDispatcherSubPointersMutImpl of starknet::storage::SubPointersMut< - AccountContractDispatcher, -> { - type SubPointersType = AccountContractDispatcherSubPointersMut; - fn sub_pointers_mut( - self: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, - ) -> AccountContractDispatcherSubPointersMut { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __contract_address_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractDispatcherSubPointersMut { contract_address: __contract_address_value__ } - } -} - -impl AccountContractLibraryDispatcherStore<> of starknet::Store { - fn read( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let class_hash = core::internal::InferDestruct::< - starknet::ClassHash, - > { - value: starknet::Store::< - starknet::ClassHash, - >::read(__store_derive_address_domain__, __store_derive_base__)?, - }; - starknet::SyscallResult::Ok( - AccountContractLibraryDispatcher { class_hash: class_hash.value }, - ) - } - fn write( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - value: AccountContractLibraryDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let AccountContractLibraryDispatcher { class_hash } = value; - let class_hash = core::internal::InferDestruct:: { value: class_hash }; - starknet::Store::< - starknet::ClassHash, - >::write(__store_derive_address_domain__, __store_derive_base__, class_hash.value)?; - starknet::SyscallResult::Ok(()) - } - fn read_at_offset( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, offset: u8, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let class_hash = core::internal::InferDestruct::< - starknet::ClassHash, - > { - value: starknet::Store::< - starknet::ClassHash, - >::read_at_offset( - __store_derive_address_domain__, __store_derive_base__, __store_derive_offset__, - )?, - }; - starknet::SyscallResult::Ok( - AccountContractLibraryDispatcher { class_hash: class_hash.value }, - ) - } - #[inline(always)] - fn write_at_offset( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - offset: u8, - value: AccountContractLibraryDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let AccountContractLibraryDispatcher { class_hash } = value; - let class_hash = core::internal::InferDestruct:: { value: class_hash }; - starknet::Store::< - starknet::ClassHash, - >::write_at_offset( - __store_derive_address_domain__, - __store_derive_base__, - __store_derive_offset__, - class_hash.value, - )?; - starknet::SyscallResult::Ok(()) - } - #[inline(always)] - fn size() -> u8 { - starknet::Store::::size() - } -} - -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractLibraryDispatcherSubPointers { - pub class_hash: starknet::storage::StoragePointer, -} -#[doc(hidden)] -impl AccountContractLibraryDispatcherSubPointersImpl of starknet::storage::SubPointers< - AccountContractLibraryDispatcher, -> { - type SubPointersType = AccountContractLibraryDispatcherSubPointers; - fn sub_pointers( - self: starknet::storage::StoragePointer, - ) -> AccountContractLibraryDispatcherSubPointers { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __class_hash_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractLibraryDispatcherSubPointers { class_hash: __class_hash_value__ } - } -} -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractLibraryDispatcherSubPointersMut { - pub class_hash: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, -} -#[doc(hidden)] -impl AccountContractLibraryDispatcherSubPointersMutImpl of starknet::storage::SubPointersMut< - AccountContractLibraryDispatcher, -> { - type SubPointersType = AccountContractLibraryDispatcherSubPointersMut; - fn sub_pointers_mut( - self: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, - ) -> AccountContractLibraryDispatcherSubPointersMut { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __class_hash_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractLibraryDispatcherSubPointersMut { class_hash: __class_hash_value__ } - } -} - -impl AccountContractSafeLibraryDispatcherStore<> of starknet::Store< - AccountContractSafeLibraryDispatcher, -> { - fn read( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let class_hash = core::internal::InferDestruct::< - starknet::ClassHash, - > { - value: starknet::Store::< - starknet::ClassHash, - >::read(__store_derive_address_domain__, __store_derive_base__)?, - }; - starknet::SyscallResult::Ok( - AccountContractSafeLibraryDispatcher { class_hash: class_hash.value }, - ) - } - fn write( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - value: AccountContractSafeLibraryDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let AccountContractSafeLibraryDispatcher { class_hash } = value; - let class_hash = core::internal::InferDestruct:: { value: class_hash }; - starknet::Store::< - starknet::ClassHash, - >::write(__store_derive_address_domain__, __store_derive_base__, class_hash.value)?; - starknet::SyscallResult::Ok(()) - } - fn read_at_offset( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, offset: u8, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let class_hash = core::internal::InferDestruct::< - starknet::ClassHash, - > { - value: starknet::Store::< - starknet::ClassHash, - >::read_at_offset( - __store_derive_address_domain__, __store_derive_base__, __store_derive_offset__, - )?, - }; - starknet::SyscallResult::Ok( - AccountContractSafeLibraryDispatcher { class_hash: class_hash.value }, - ) - } - #[inline(always)] - fn write_at_offset( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - offset: u8, - value: AccountContractSafeLibraryDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let AccountContractSafeLibraryDispatcher { class_hash } = value; - let class_hash = core::internal::InferDestruct:: { value: class_hash }; - starknet::Store::< - starknet::ClassHash, - >::write_at_offset( - __store_derive_address_domain__, - __store_derive_base__, - __store_derive_offset__, - class_hash.value, - )?; - starknet::SyscallResult::Ok(()) - } - #[inline(always)] - fn size() -> u8 { - starknet::Store::::size() - } -} - -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractSafeLibraryDispatcherSubPointers { - pub class_hash: starknet::storage::StoragePointer, -} -#[doc(hidden)] -impl AccountContractSafeLibraryDispatcherSubPointersImpl of starknet::storage::SubPointers< - AccountContractSafeLibraryDispatcher, -> { - type SubPointersType = AccountContractSafeLibraryDispatcherSubPointers; - fn sub_pointers( - self: starknet::storage::StoragePointer, - ) -> AccountContractSafeLibraryDispatcherSubPointers { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __class_hash_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractSafeLibraryDispatcherSubPointers { class_hash: __class_hash_value__ } - } -} -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractSafeLibraryDispatcherSubPointersMut { - pub class_hash: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, -} -#[doc(hidden)] -impl AccountContractSafeLibraryDispatcherSubPointersMutImpl of starknet::storage::SubPointersMut< - AccountContractSafeLibraryDispatcher, -> { - type SubPointersType = AccountContractSafeLibraryDispatcherSubPointersMut; - fn sub_pointers_mut( - self: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, - ) -> AccountContractSafeLibraryDispatcherSubPointersMut { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __class_hash_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractSafeLibraryDispatcherSubPointersMut { class_hash: __class_hash_value__ } - } -} - -impl AccountContractSafeDispatcherStore<> of starknet::Store { - fn read( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { - value: starknet::Store::< - starknet::ContractAddress, - >::read(__store_derive_address_domain__, __store_derive_base__)?, - }; - starknet::SyscallResult::Ok( - AccountContractSafeDispatcher { contract_address: contract_address.value }, - ) - } - fn write( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - value: AccountContractSafeDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let AccountContractSafeDispatcher { contract_address } = value; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { value: contract_address }; - starknet::Store::< - starknet::ContractAddress, - >::write(__store_derive_address_domain__, __store_derive_base__, contract_address.value)?; - starknet::SyscallResult::Ok(()) - } - fn read_at_offset( - address_domain: u32, base: starknet::storage_access::StorageBaseAddress, offset: u8, - ) -> starknet::SyscallResult { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { - value: starknet::Store::< - starknet::ContractAddress, - >::read_at_offset( - __store_derive_address_domain__, __store_derive_base__, __store_derive_offset__, - )?, - }; - starknet::SyscallResult::Ok( - AccountContractSafeDispatcher { contract_address: contract_address.value }, - ) - } - #[inline(always)] - fn write_at_offset( - address_domain: u32, - base: starknet::storage_access::StorageBaseAddress, - offset: u8, - value: AccountContractSafeDispatcher, - ) -> starknet::SyscallResult<()> { - let __store_derive_address_domain__ = address_domain; - let __store_derive_base__ = base; - let __store_derive_offset__ = offset; - let AccountContractSafeDispatcher { contract_address } = value; - let contract_address = core::internal::InferDestruct::< - starknet::ContractAddress, - > { value: contract_address }; - starknet::Store::< - starknet::ContractAddress, - >::write_at_offset( - __store_derive_address_domain__, - __store_derive_base__, - __store_derive_offset__, - contract_address.value, - )?; - starknet::SyscallResult::Ok(()) - } - #[inline(always)] - fn size() -> u8 { - starknet::Store::::size() - } -} - -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractSafeDispatcherSubPointers { - pub contract_address: starknet::storage::StoragePointer, -} -#[doc(hidden)] -impl AccountContractSafeDispatcherSubPointersImpl of starknet::storage::SubPointers< - AccountContractSafeDispatcher, -> { - type SubPointersType = AccountContractSafeDispatcherSubPointers; - fn sub_pointers( - self: starknet::storage::StoragePointer, - ) -> AccountContractSafeDispatcherSubPointers { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __contract_address_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractSafeDispatcherSubPointers { contract_address: __contract_address_value__ } - } -} -#[derive(Drop, Copy)] -#[doc(hidden)] -pub struct AccountContractSafeDispatcherSubPointersMut { - pub contract_address: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, -} -#[doc(hidden)] -impl AccountContractSafeDispatcherSubPointersMutImpl of starknet::storage::SubPointersMut< - AccountContractSafeDispatcher, -> { - type SubPointersType = AccountContractSafeDispatcherSubPointersMut; - fn sub_pointers_mut( - self: starknet::storage::StoragePointer< - starknet::storage::Mutable, - >, - ) -> AccountContractSafeDispatcherSubPointersMut { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let __contract_address_value__ = starknet::storage::StoragePointer { - __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset, - }; - AccountContractSafeDispatcherSubPointersMut { contract_address: __contract_address_value__ } - } -} - -pub trait AccountContractDispatcherTrait { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__(self: T, class_hash: felt252) -> felt252; - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__(self: T, calls: Array) -> felt252; - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__(self: T, calls: Array) -> Array>; -} - -#[derive(Copy, Drop, Serde)] -pub struct AccountContractDispatcher { - pub contract_address: starknet::ContractAddress, -} - -impl AccountContractDispatcherImpl of AccountContractDispatcherTrait { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__(self: AccountContractDispatcher, class_hash: felt252) -> felt252 { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::::serialize(@class_hash, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__(self: AccountContractDispatcher, calls: Array) -> felt252 { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__(self: AccountContractDispatcher, calls: Array) -> Array> { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::>>::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } -} - -#[derive(Copy, Drop, Serde)] -pub struct AccountContractLibraryDispatcher { - pub class_hash: starknet::ClassHash, -} - -impl AccountContractLibraryDispatcherImpl of AccountContractDispatcherTrait< - AccountContractLibraryDispatcher, -> { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__( - self: AccountContractLibraryDispatcher, class_hash: felt252, - ) -> felt252 { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::::serialize(@class_hash, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__(self: AccountContractLibraryDispatcher, calls: Array) -> felt252 { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__( - self: AccountContractLibraryDispatcher, calls: Array, - ) -> Array> { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = starknet::SyscallResultTrait::unwrap_syscall( - __dispatcher_return_data__, - ); - core::option::OptionTrait::expect( - core::serde::Serde::>>::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ) - } -} - -pub trait AccountContractSafeDispatcherTrait { - #[unstable(feature: "safe_dispatcher")] - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__(self: T, class_hash: felt252) -> starknet::SyscallResult; - #[unstable(feature: "safe_dispatcher")] - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__(self: T, calls: Array) -> starknet::SyscallResult; - #[unstable(feature: "safe_dispatcher")] - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__(self: T, calls: Array) -> starknet::SyscallResult>>; -} - -#[derive(Copy, Drop, Serde)] -pub struct AccountContractSafeLibraryDispatcher { - pub class_hash: starknet::ClassHash, -} - -impl AccountContractSafeLibraryDispatcherImpl of AccountContractSafeDispatcherTrait< - AccountContractSafeLibraryDispatcher, -> { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__( - self: AccountContractSafeLibraryDispatcher, class_hash: felt252, - ) -> starknet::SyscallResult { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::::serialize(@class_hash, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__( - self: AccountContractSafeLibraryDispatcher, calls: Array, - ) -> starknet::SyscallResult { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__( - self: AccountContractSafeLibraryDispatcher, calls: Array, - ) -> starknet::SyscallResult>> { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::library_call_syscall( - self.class_hash, - 0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::< - Array>, - >::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } -} - - -#[derive(Copy, Drop, Serde)] -pub struct AccountContractSafeDispatcher { - pub contract_address: starknet::ContractAddress, -} - -impl AccountContractSafeDispatcherImpl of AccountContractSafeDispatcherTrait< - AccountContractSafeDispatcher, -> { - /// An entry point that is called to check if the account is willing to pay for the declaration - /// of the class with the given hash. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the declaration. - fn __validate_declare__( - self: AccountContractSafeDispatcher, class_hash: felt252, - ) -> starknet::SyscallResult { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::::serialize(@class_hash, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } - - /// An entry point that is called to check if the account is willing to pay for - /// executing a given set of calls. - /// The entry point should return `starknet::VALIDATED` if the account is willing to pay - /// for the execution, in which case `__execute__` will be called on the same set of calls. - fn __validate__( - self: AccountContractSafeDispatcher, calls: Array, - ) -> starknet::SyscallResult { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } - - /// An entry point that is called to execute a given set of calls. - /// This entry point should block the deprecated v0 invoke transactions as they do not go - /// through the `__validate__` entry point. - fn __execute__( - self: AccountContractSafeDispatcher, calls: Array, - ) -> starknet::SyscallResult>> { - let mut __calldata__ = core::traits::Default::default(); - core::serde::Serde::>::serialize(@calls, ref __calldata__); - - let mut __dispatcher_return_data__ = starknet::syscalls::call_contract_syscall( - self.contract_address, - 0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad, - core::array::ArrayTrait::span(@__calldata__), - ); - let mut __dispatcher_return_data__ = __dispatcher_return_data__?; - Result::Ok( - core::option::OptionTrait::expect( - core::serde::Serde::< - Array>, - >::deserialize(ref __dispatcher_return_data__), - 'Returned data too short', - ), - ) - } -} diff --git a/corelib/src/starknet/class_hash.cairo b/corelib/src/starknet/class_hash.cairo deleted file mode 100644 index 44b10b803b..0000000000 --- a/corelib/src/starknet/class_hash.cairo +++ /dev/null @@ -1,103 +0,0 @@ -//! The `ClassHash` type represents a Starknet contract class hash, with a value range of -//! `[0, 2**251)`. -//! -//! -//! A variable of type `ClassHash` can be created from a `felt252` value using the -//! `class_hash_const` function, or using the `TryInto` trait. -//! -//! # Examples -//! -//! ``` -//! use starknet::class_hash::class_hash_const; -//! -//! let hash = class_hash_const::<0x123>(); -//! let hash = 0x123.try_into().unwrap(); -//! ``` - -use core::RangeCheck; -#[allow(unused_imports)] -use core::hash::{Hash, HashStateTrait}; -use core::serde::Serde; - -/// Represents a Starknet contract class hash. -/// The value range of this type is `[0, 2**251)`. -pub extern type ClassHash; - -impl ClassHashCopy of Copy; -impl ClassHashDrop of Drop; - -/// Returns a `ClassHash` given a `felt252` value. -/// -/// # Examples -/// -/// ``` -/// use starknet::class_hash::class_hash_const; -/// -/// let class_hash = class_hash_const::<0x123>(); -/// ``` -#[deprecated( - feature: "deprecated-starknet-consts", - note: "Use `TryInto::try_into` in const context instead.", -)] -pub extern fn class_hash_const() -> ClassHash nopanic; - -pub(crate) extern const fn class_hash_to_felt252(address: ClassHash) -> felt252 nopanic; - -pub(crate) extern const fn class_hash_try_from_felt252( - address: felt252, -) -> Option implicits(RangeCheck) nopanic; - -pub(crate) impl Felt252TryIntoClassHash of TryInto { - const fn try_into(self: felt252) -> Option { - class_hash_try_from_felt252(self) - } -} - -pub(crate) impl ClassHashIntoFelt252 of Into { - const fn into(self: ClassHash) -> felt252 { - class_hash_to_felt252(self) - } -} - -impl ClassHashZero of core::num::traits::Zero { - #[feature("deprecated-starknet-consts")] - fn zero() -> ClassHash { - class_hash_const::<0>() - } - - #[inline] - fn is_zero(self: @ClassHash) -> bool { - core::num::traits::Zero::::is_zero(@class_hash_to_felt252(*self)) - } - - #[inline] - fn is_non_zero(self: @ClassHash) -> bool { - !self.is_zero() - } -} - -pub(crate) impl ClassHashZeroable = - core::zeroable::zero_based::ZeroableImpl; - -impl ClassHashSerde of Serde { - fn serialize(self: @ClassHash, ref output: Array) { - class_hash_to_felt252(*self).serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Some(class_hash_try_from_felt252(Serde::::deserialize(ref serialized)?)?) - } -} - -impl ClassHashPartialEq of PartialEq { - #[inline] - fn eq(lhs: @ClassHash, rhs: @ClassHash) -> bool { - class_hash_to_felt252(*lhs) == class_hash_to_felt252(*rhs) - } -} - -impl HashClassHash, +Drop> = - core::hash::into_felt252_based::HashImpl; - -impl DebugClassHash = core::fmt::into_felt252_based::DebugImpl; -impl LowerHexClassHash = core::fmt::into_felt252_based::LowerHexImpl; diff --git a/corelib/src/starknet/contract_address.cairo b/corelib/src/starknet/contract_address.cairo deleted file mode 100644 index 20cf70632d..0000000000 --- a/corelib/src/starknet/contract_address.cairo +++ /dev/null @@ -1,112 +0,0 @@ -//! The `ContractAddress` type represents a Starknet contract address, with a value range of -//! `[0, 2**251)`. -//! -//! -//! A variable of type `ContractAddress` can be created from a `felt252` value using the -//! `contract_address_const` function, or using the `TryInto` trait. -//! -//! # Examples -//! -//! ``` -//! use starknet::contract_address::contract_address_const; -//! -//! let contract_address = contract_address_const::<0x0>(); -//! ``` - -use core::RangeCheck; -#[allow(unused_imports)] -use core::hash::{Hash, HashStateTrait}; -use core::serde::Serde; -#[allow(unused_imports)] -use core::zeroable::Zeroable; - -/// Represents a Starknet contract address. -/// The value range of this type is `[0, 2**251)`. -pub extern type ContractAddress; - -impl ContractAddressCopy of Copy; -impl ContractAddressDrop of Drop; - -/// Returns a `ContractAddress` given a `felt252` value. -/// -/// # Examples -/// -/// ``` -/// use starknet::contract_address::contract_address_const; -/// -/// let contract_address = contract_address_const::<0x0>(); -/// ``` -#[deprecated( - feature: "deprecated-starknet-consts", - note: "Use `TryInto::try_into` in const context instead.", -)] -pub extern fn contract_address_const() -> ContractAddress nopanic; - -pub(crate) extern const fn contract_address_to_felt252(address: ContractAddress) -> felt252 nopanic; - -pub(crate) extern const fn contract_address_try_from_felt252( - address: felt252, -) -> Option implicits(RangeCheck) nopanic; - -pub(crate) impl Felt252TryIntoContractAddress of TryInto { - const fn try_into(self: felt252) -> Option { - contract_address_try_from_felt252(self) - } -} - -pub(crate) impl ContractAddressIntoFelt252 of Into { - const fn into(self: ContractAddress) -> felt252 { - contract_address_to_felt252(self) - } -} - -impl ContractAddressZero of core::num::traits::Zero { - #[feature("deprecated-starknet-consts")] - fn zero() -> ContractAddress { - contract_address_const::<0>() - } - - #[inline] - fn is_zero(self: @ContractAddress) -> bool { - core::num::traits::Zero::::is_zero(@contract_address_to_felt252(*self)) - } - - #[inline] - fn is_non_zero(self: @ContractAddress) -> bool { - !self.is_zero() - } -} - -pub(crate) impl ContractAddressZeroable = - core::zeroable::zero_based::ZeroableImpl; - -impl ContractAddressSerde of Serde { - fn serialize(self: @ContractAddress, ref output: Array) { - contract_address_to_felt252(*self).serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Some(contract_address_try_from_felt252(Serde::::deserialize(ref serialized)?)?) - } -} - -impl ContractAddressPartialEq of PartialEq { - #[inline] - fn eq(lhs: @ContractAddress, rhs: @ContractAddress) -> bool { - contract_address_to_felt252(*lhs) == contract_address_to_felt252(*rhs) - } -} - -impl ContractAddressPartialOrd of PartialOrd { - fn lt(lhs: ContractAddress, rhs: ContractAddress) -> bool { - // TODO(orizi): Check if implementing a libfunc for `felt252` ordering is more efficient. - let lhs: u256 = contract_address_to_felt252(lhs).into(); - lhs < contract_address_to_felt252(rhs).into() - } -} - -impl HashContractAddress, +Drop> = - core::hash::into_felt252_based::HashImpl; - -impl DebugContractAddress = core::fmt::into_felt252_based::DebugImpl; -impl LowerHexContractAddress = core::fmt::into_felt252_based::LowerHexImpl; diff --git a/corelib/src/starknet/deployment.cairo b/corelib/src/starknet/deployment.cairo deleted file mode 100644 index f1c7b993a4..0000000000 --- a/corelib/src/starknet/deployment.cairo +++ /dev/null @@ -1,13 +0,0 @@ -/// Configuration for contract deployment -/// -/// This structure contains parameters needed to deploy a new contract instance -/// Used by the typed deployment function generated by the Starknet Cairo plugin. -#[cfg(target: 'test')] -#[derive(Drop, Copy, Debug, PartialEq, Serde, Default)] -pub struct DeploymentParams { - /// The salt, an arbitrary value provided by the deployer, used in the computation of the - /// contract's address. - pub salt: felt252, - /// Deploy the contract from the zero address. - pub deploy_from_zero: bool, -} diff --git a/corelib/src/starknet/eth_address.cairo b/corelib/src/starknet/eth_address.cairo deleted file mode 100644 index 9bc5114b1f..0000000000 --- a/corelib/src/starknet/eth_address.cairo +++ /dev/null @@ -1,94 +0,0 @@ -//! Ethereum address type for working with Ethereum primitives. -//! -//! This module provides the [`EthAddress`] type, which is used when interacting with Ethereum -//! primitives, such as signatures and L1 <-> L2 messages. - -use core::debug::PrintTrait; -#[allow(unused_imports)] -use core::integer::{U128TryIntoNonZero, U256TryIntoFelt252, u128_safe_divmod}; -use core::serde::Serde; -use core::traits::{Into, TryInto}; - -/// An Ethereum address, 20 bytes in length. -#[derive(Copy, Drop, Hash, PartialEq)] -pub struct EthAddress { - address: felt252, -} - -impl EthAddressStorePacking of starknet::StorePacking { - fn pack(value: EthAddress) -> felt252 { - value.address - } - - fn unpack(value: felt252) -> EthAddress { - value.try_into().expect('StoreEthAddress - non u160') - } -} - -pub(crate) impl Felt252TryIntoEthAddress of TryInto { - fn try_into(self: felt252) -> Option { - let ETH_ADDRESS_BOUND = 0x10000000000000000000000000000000000000000_u256; // 2 ** 160 - - if self.into() < ETH_ADDRESS_BOUND { - Some(EthAddress { address: self }) - } else { - None - } - } -} - -pub(crate) impl EthAddressIntoFelt252 of Into { - fn into(self: EthAddress) -> felt252 { - self.address - } -} - -/// Creates an `EthAddress` from the 20 least significant bytes of a `u256`. -pub(crate) impl U256IntoEthAddress of Into { - fn into(self: u256) -> EthAddress { - // The Ethereum address is the 20 least significant bytes (=160=128+32 bits) of the value. - let high_32_bits = self.high % 0x100000000_u128; - EthAddress { - address: high_32_bits.into() * 0x100000000000000000000000000000000_felt252 - + self.low.into(), - } - } -} - -pub(crate) impl EthAddressSerde of Serde { - fn serialize(self: @EthAddress, ref output: Array) { - self.address.serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Serde::::deserialize(ref serialized)?.try_into() - } -} - -impl EthAddressZero of core::num::traits::Zero { - fn zero() -> EthAddress { - EthAddress { address: 0 } - } - - #[inline] - fn is_zero(self: @EthAddress) -> bool { - core::num::traits::Zero::::is_zero(@self.address) - } - - #[inline] - fn is_non_zero(self: @EthAddress) -> bool { - !self.is_zero() - } -} - -pub(crate) impl EthAddressZeroable = - core::zeroable::zero_based::ZeroableImpl; - -pub(crate) impl EthAddressPrintImpl of PrintTrait { - fn print(self: EthAddress) { - self.address.print(); - } -} - -impl DebugEthAddress = core::fmt::into_felt252_based::DebugImpl; -impl LowerHexEthAddress = core::fmt::into_felt252_based::LowerHexImpl; diff --git a/corelib/src/starknet/eth_signature.cairo b/corelib/src/starknet/eth_signature.cairo deleted file mode 100644 index eaa1b8b034..0000000000 --- a/corelib/src/starknet/eth_signature.cairo +++ /dev/null @@ -1,156 +0,0 @@ -//! Utilities for Ethereum signature verification and address recovery. -//! -//! This module provides functionality for working with Ethereum signatures. -//! It implements verification of Ethereum signatures against addresses and conversion of public -//! keys to Ethereum addresses. - -use core::keccak::keccak_u256s_be_inputs; -#[allow(unused_imports)] -use starknet::secp256_trait::{ - Secp256PointTrait, Secp256Trait, Signature, is_signature_entry_valid, is_signature_s_valid, - recover_public_key, -}; -#[allow(unused_imports)] -use starknet::secp256k1::Secp256k1Point; -#[allow(unused_imports)] -use starknet::{EthAddress, SyscallResult, SyscallResultTrait}; - -/// Asserts that an Ethereum signature is valid for a given message hash and Ethereum address. -/// Also verifies that the `r` component of the signature is in the range `[1, N)`, -/// and the `s` component is in the range `[1, N/2]`, where N is the size of the curve. -/// -/// # Arguments -/// -/// * `msg_hash` - The 32-byte hash of the message that was signed -/// * `signature` - The Ethereum signature containing `r`, `s` components and `y_parity` -/// * `eth_address` - The expected Ethereum address of the signer -/// -/// # Panics -/// -/// Panics if: -/// * The `r` component is out of range (not in [1, N) where N is the curve order) -/// * The `s` component is out of range (not in [1, N/2] where N is the curve order) -/// * The recovered address doesn't match the provided address -/// -/// # Examples -/// -/// ``` -/// use starknet::eth_address::EthAddress; -/// use starknet::eth_signature::verify_eth_signature; -/// use starknet::secp256_trait::Signature; -/// -/// let msg_hash = 0xe888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3e934f78d7a71dd85; -/// let r = 0x4c8e4fbc1fbb1dece52185e532812c4f7a5f81cf3ee10044320a0d03b62d3e9a; -/// let s = 0x4ac5e5c0c0e8a4871583cc131f35fb49c2b7f60e6a8b84965830658f08f7410c; -/// let y_parity = true; -/// let eth_address: EthAddress = 0x767410c1bb448978bd42b984d7de5970bcaf5c43_u256 -/// .try_into() -/// .unwrap(); -/// verify_eth_signature(msg_hash, Signature { r, s, y_parity }, eth_address); -/// ``` -pub fn verify_eth_signature(msg_hash: u256, signature: Signature, eth_address: EthAddress) { - match is_eth_signature_valid(:msg_hash, :signature, :eth_address) { - Ok(()) => {}, - Err(err) => core::panic_with_felt252(err), - } -} - -/// Validates an Ethereum signature against a message hash and Ethereum address. -/// Similar to `verify_eth_signature` but returns a `Result` instead of panicking. -/// Also verifies that the `r` component of the signature is in the range `[1, N)`, -/// and the `s` component is in the range `[1, N/2]`, where N is the size of the curve. -/// -/// # Arguments -/// -/// * `msg_hash` - The 32-byte hash of the message that was signed -/// * `signature` - The Ethereum signature containing `r`, `s` components and `y_parity` -/// * `eth_address` - The expected Ethereum address of the signer -/// -/// # Returns -/// -/// Returns `Ok(())` if the signature is valid, or `Err(felt252)` containing an error message if -/// invalid. -/// -/// # Examples -/// -/// ``` -/// use starknet::eth_address::EthAddress; -/// use starknet::eth_signature::is_eth_signature_valid; -/// use starknet::secp256_trait::Signature; -/// -/// let msg_hash = 0xe888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3e934f78d7a71dd85; -/// let r = 0x4c8e4fbc1fbb1dece52185e532812c4f7a5f81cf3ee10044320a0d03b62d3e9a; -/// let s = 0x4ac5e5c0c0e8a4871583cc131f35fb49c2b7f60e6a8b84965830658f08f7410c; -/// let y_parity = true; -/// let eth_address: EthAddress = 0x767410c1bb448978bd42b984d7de5970bcaf5c43_u256 -/// .try_into() -/// .unwrap(); -/// assert!(is_eth_signature_valid(msg_hash, Signature { r, s, y_parity }, eth_address).is_ok()); -/// ``` -pub fn is_eth_signature_valid( - msg_hash: u256, signature: Signature, eth_address: EthAddress, -) -> Result<(), felt252> { - if !is_signature_entry_valid::(signature.r) { - return Err('Signature out of range'); - } - if !is_signature_s_valid::(signature.s) { - return Err('Signature out of range'); - } - - let Some(public_key_point) = recover_public_key::(:msg_hash, :signature) else { - return Err('Public key recovery failed'); - }; - let calculated_eth_address = public_key_point_to_eth_address(:public_key_point); - if eth_address != calculated_eth_address { - return Err('Invalid signature'); - } - Ok(()) -} - -/// Converts a public key point to its corresponding Ethereum address. -/// -/// The Ethereum address is calculated by taking the Keccak-256 hash of the public key coordinates -/// and taking the last 20 big-endian bytes. -/// -/// # Arguments -/// -/// * `public_key_point` - A point on a secp256 curve representing a public key -/// -/// # Returns -/// -/// The 20-byte Ethereum address derived from the public key -/// -/// # Examples -/// -/// ``` -/// use starknet::eth_signature::public_key_point_to_eth_address; -/// use starknet::secp256k1::Secp256k1Point; -/// use starknet::secp256_trait::Secp256Trait; -/// -/// let public_key: Secp256k1Point = Secp256Trait::secp256_ec_get_point_from_x_syscall( -/// 0xa9a02d48081294b9bb0d8740d70d3607feb20876964d432846d9b9100b91eefd, false, -/// ) -/// .unwrap() -/// .unwrap(); -/// let eth_address = public_key_point_to_eth_address(public_key); -/// assert!(eth_address == 0x767410c1bb448978bd42b984d7de5970bcaf5c43.try_into().unwrap()); -/// ``` -pub fn public_key_point_to_eth_address< - Secp256Point, - +Drop, - +Secp256Trait, - +Secp256PointTrait, ->( - public_key_point: Secp256Point, -) -> EthAddress { - let (x, y) = public_key_point.get_coordinates().unwrap_syscall(); - - // Keccak output is little endian. - let point_hash_le = keccak_u256s_be_inputs([x, y].span()); - let point_hash = u256 { - low: core::integer::u128_byte_reverse(point_hash_le.high), - high: core::integer::u128_byte_reverse(point_hash_le.low), - }; - - point_hash.into() -} diff --git a/corelib/src/starknet/event.cairo b/corelib/src/starknet/event.cairo deleted file mode 100644 index 214a06eb0b..0000000000 --- a/corelib/src/starknet/event.cairo +++ /dev/null @@ -1,95 +0,0 @@ -//! Event handling traits for Starknet smart contracts. -//! -//! This module provides traits for serializing, deserializing and emitting events on Starknet. -//! The [`Event`] trait handles the serialization of event types, while the [`EventEmitter`] trait -//! provides the capability to emit events from Starknet contracts. - -/// A trait for handling serialization and deserialization of events. -/// -/// Events in Starknet are stored in transaction receipts as a combination of keys and data fields. -/// This trait provides the methods needed to serialize event data into these fields and deserialize -/// them back into their original form. -/// -/// This trait can easily be derived using the `#[derive(starknet::Event)]` attribute. -/// Fields can be marked as keys using the `#[key]` attribute to serialize them as event keys. -/// -/// # Performance -/// -/// Serialization and deserialization have O(n) complexity for structs, where n is the number of -/// fields. -/// For enums, deserialization has O(m) complexity, where m is the number of variants, as it may -/// need to check multiple variants before finding a match. -/// -/// # Examples -/// -/// ``` -/// #[derive(Drop, starknet::Event)] -/// pub struct Transfer { -/// #[key] -/// pub from: ContractAddress, -/// #[key] -/// pub to: ContractAddress, -/// pub amount: u256, -/// } -/// ``` -pub trait Event { - /// Serializes the keys and data for event emission. - /// - /// The keys array will contain: - /// - The event name selector as the first key - /// - Any fields marked with #[key] as subsequent keys - /// - /// The data array will contain all non-key fields. - fn append_keys_and_data(self: @T, ref keys: Array, ref data: Array); - - /// Deserializes events keys and data back into the original event structure. - /// - /// Returns `None` if deserialization fails. This can happen when: - /// - The keys or data arrays don't contain enough elements - /// - The event selector (first key) doesn't match the expected event type (for enums) - /// - Any field deserialization fails (e.g., invalid type conversion) - /// - /// # Examples - /// - /// ``` - /// let (mut keys, mut data) = starknet::testing::pop_log_raw(contract_address)?; - /// match starknet::Event::deserialize(ref keys, ref data) { - /// Option::Some(event) => { /* handle event */ }, - /// Option::None => { /* deserialization failed */ }, - /// } - /// ``` - fn deserialize(ref keys: Span, ref data: Span) -> Option; -} - -/// A trait for emitting Starknet events. -/// -/// The generic parameter `T` represents the contract state type (typically `ContractState`), -/// and `TEvent` represents the event type (typically an enum named `Event`). -/// -/// # Examples -/// -/// ``` -/// #[derive(Drop, starknet::Event)] -/// pub struct NewOwner { -/// pub new_owner: ContractAddress, -/// } -/// -/// fn emit_event(ref self: ContractState, new_owner: ContractAddress) { -/// self.emit(NewOwner { new_owner }); -/// } -/// ``` -/// -/// The generic parameter `S` with bound `+Into` allows passing either -/// the event type directly or any type that can be converted into it (e.g., enum variants). -pub trait EventEmitter { - /// Emits an event. - /// - /// The `S` parameter allows passing the event directly or any type convertible to `TEvent` - /// via the `Into` trait. This enables flexible usage patterns like emitting enum variants - /// directly. - /// - /// # Panics - /// - /// This method will panic if the underlying system call fails. - fn emit>(ref self: T, event: S); -} diff --git a/corelib/src/starknet/info.cairo b/corelib/src/starknet/info.cairo deleted file mode 100644 index 985814b88d..0000000000 --- a/corelib/src/starknet/info.cairo +++ /dev/null @@ -1,325 +0,0 @@ -//! Information about the Starknet execution environment. -//! -//! This module provides access to runtime information about the current transaction, -//! block, and execution context in a Starknet smart contract. It enables contracts -//! to access execution context data. -//! -//! # Examples -//! -//! ``` -//! use starknet::{get_block_info, get_caller_address, get_contract_address}; -//! -//! // Get block information -//! let block_info = get_block_info().unbox(); -//! let timestamp = block_info.block_timestamp; -//! -//! // Get caller and contract addresses -//! let caller = get_caller_address(); -//! let contract = get_contract_address(); -//! ``` - -#[allow(unused_imports)] -use core::box::BoxTrait; -#[allow(unused_imports)] -use starknet::contract_address::ContractAddress; -#[allow(unused_imports)] -use starknet::syscalls::get_execution_info_syscall; -#[allow(unused_imports)] -use starknet::{SyscallResult, SyscallResultTrait}; - -/// The execution information for the current entry point. -#[derive(Copy, Drop, Debug)] -pub struct ExecutionInfo { - /// Information about the current block. - pub block_info: Box, - /// Information about the current transaction. - pub tx_info: Box, - /// The address of the caller contract. - /// Returns 0 if the current execution was externally triggered, this happens when the - /// transaction begins its execution in an account contract. - pub caller_address: ContractAddress, - /// The address of the contract being executed. - /// Storage writes and emitted events are associated with this address. - pub contract_address: ContractAddress, - /// The selector of the current entry point. - pub entry_point_selector: felt252, -} - -/// Information about the current block. -#[derive(Copy, Drop, Debug, Serde)] -pub struct BlockInfo { - /// The number, that is, the height, of this block. - pub block_number: u64, - /// The time at which the sequencer began building the block, in seconds since the Unix epoch. - pub block_timestamp: u64, - /// The Starknet address of the sequencer that created the block. - pub sequencer_address: ContractAddress, -} - -/// Information about the current transaction. -#[derive(Copy, Drop, Debug, Serde)] -pub struct TxInfo { - /// The version of the transaction. - /// This field allows invalidating old transactions, whenever the meaning of the other - /// transaction fields is changed (in the OS). - pub version: felt252, - /// The account contract from which this transaction originates. - pub account_contract_address: ContractAddress, - /// The `max_fee` field of the transaction. - pub max_fee: u128, - /// The signature of the transaction. - pub signature: Span, - /// The hash of the transaction. - pub transaction_hash: felt252, - /// The identifier of the chain. - /// This field can be used to prevent replay of testnet transactions on mainnet. - pub chain_id: felt252, - /// The transaction's nonce. - pub nonce: felt252, -} - -/// Returns the execution info for the current execution. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_execution_info; -/// -/// let execution_info = get_execution_info().unbox(); -/// -/// // Access various execution context information -/// let caller = execution_info.caller_address; -/// let contract = execution_info.contract_address; -/// let selector = execution_info.entry_point_selector; -/// ``` -pub fn get_execution_info() -> Box { - starknet::syscalls::get_execution_info_v2_syscall().unwrap_syscall() -} - -/// Returns the address of the caller contract. -/// -/// Returns `0` if there is no caller—for example, when a transaction begins execution inside an -/// account contract. -/// -/// Note: This function returns the *direct* caller. If you're interested in the account that -/// initiated the transaction, use `get_execution_info().tx_info.unbox().account_contract_address` -/// instead. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_caller_address; -/// -/// let caller = get_caller_address(); -/// ``` -pub fn get_caller_address() -> ContractAddress { - get_execution_info().caller_address -} - -/// Returns the address of the contract being executed. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_contract_address; -/// -/// let contract_address = get_contract_address(); -/// ``` -pub fn get_contract_address() -> ContractAddress { - get_execution_info().contract_address -} - -/// Returns the block information for the current block. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_block_info; -/// -/// let block_info = get_block_info().unbox(); -/// -/// let block_number = block_info.block_number; -/// let block_timestamp = block_info.block_timestamp; -/// let sequencer = block_info.sequencer_address; -/// ``` -pub fn get_block_info() -> Box { - get_execution_info().block_info -} - -/// Returns the transaction information for the current transaction. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_tx_info; -/// -/// let tx_info = get_tx_info().unbox(); -/// -/// let account_contract_address = tx_info.account_contract_address; -/// let chain_id = tx_info.chain_id; -/// let nonce = tx_info.nonce; -/// let max_fee = tx_info.max_fee; -/// let tx_hash = tx_info.transaction_hash; -/// let signature = tx_info.signature; -/// let version = tx_info.version; -/// ``` -pub fn get_tx_info() -> Box { - get_execution_info().tx_info -} - -/// Returns the timestamp of the current block. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_block_timestamp; -/// -/// let block_timestamp = get_block_timestamp(); -/// ``` -pub fn get_block_timestamp() -> u64 { - get_block_info().block_timestamp -} - -/// Returns the number of the current block. -/// -/// # Examples -/// -/// ``` -/// use starknet::get_block_number; -/// -/// let block_number = get_block_number(); -/// ``` -pub fn get_block_number() -> u64 { - get_block_info().block_number -} - -/// The extended version of the `get_execution_info` syscall result. -pub mod v2 { - use starknet::contract_address::ContractAddress; - use super::BlockInfo; - - /// The same as `ExecutionInfo`, but with the `TxInfo` field replaced with `v2::TxInfo`. - #[derive(Copy, Drop, Debug)] - pub struct ExecutionInfo { - pub block_info: Box, - pub tx_info: Box, - pub caller_address: ContractAddress, - pub contract_address: ContractAddress, - pub entry_point_selector: felt252, - } - - /// Extended information about the current transaction. - #[derive(Copy, Drop, Debug, Serde)] - pub struct TxInfo { - /// The version of the transaction. It is fixed (currently, 1) in the OS, and should be - /// signed by the account contract. - /// This field allows invalidating old transactions, whenever the meaning of the other - /// transaction fields is changed (in the OS). - pub version: felt252, - /// The account contract from which this transaction originates. - pub account_contract_address: ContractAddress, - /// The `max_fee` field of the transaction. - pub max_fee: u128, - /// The signature of the transaction. - pub signature: Span, - /// The hash of the transaction. - pub transaction_hash: felt252, - /// The identifier of the chain. - /// This field can be used to prevent replay of testnet transactions on mainnet. - pub chain_id: felt252, - /// The transaction's nonce. - pub nonce: felt252, - /// A span of `ResourceBounds` structs used for V3 transactions. - pub resource_bounds: Span, - /// The tip of the transaction. - pub tip: u128, - /// If specified, the paymaster should pay for the execution of the transaction. - /// The data includes the address of the paymaster sponsoring the transaction, followed by - /// extra data to send to the paymaster. - /// Used for V3 transactions. - pub paymaster_data: Span, - /// The data availability mode for the nonce. - /// Used for V3 transactions. - pub nonce_data_availability_mode: u32, - /// The data availability mode for the account balance from which fee will be taken. - /// Used for V3 transactions. - pub fee_data_availability_mode: u32, - /// If nonempty, will contain the required data for deploying and initializing an account - /// contract: its class hash, address salt and constructor calldata. - /// Used for V3 transactions. - pub account_deployment_data: Span, - } - - /// V3 transactions resources used for enabling the fee market. - #[derive(Copy, Drop, Debug, Serde)] - pub struct ResourceBounds { - /// The name of the resource. - pub resource: felt252, - /// The maximum amount of the resource allowed for usage during the execution. - pub max_amount: u64, - /// The maximum price the user is willing to pay for the resource unit. - pub max_price_per_unit: u128, - } -} - - -/// The extended version of the `get_execution_info` syscall result. -pub mod v3 { - use starknet::contract_address::ContractAddress; - use super::BlockInfo; - pub use super::v2::ResourceBounds; - - /// The same as `ExecutionInfo`, but with the `TxInfo` field replaced with `v3::TxInfo`. - #[derive(Copy, Drop, Debug)] - pub struct ExecutionInfo { - pub block_info: Box, - pub tx_info: Box, - pub caller_address: ContractAddress, - pub contract_address: ContractAddress, - pub entry_point_selector: felt252, - } - - /// Extended information about the current transaction. - #[derive(Copy, Drop, Debug, Serde)] - pub struct TxInfo { - /// The version of the transaction. It is fixed (currently, 1) in the OS, and should be - /// signed by the account contract. - /// This field allows invalidating old transactions, whenever the meaning of the other - /// transaction fields is changed (in the OS). - pub version: felt252, - /// The account contract from which this transaction originates. - pub account_contract_address: ContractAddress, - /// The `max_fee` field of the transaction. - pub max_fee: u128, - /// The signature of the transaction. - pub signature: Span, - /// The hash of the transaction. - pub transaction_hash: felt252, - /// The identifier of the chain. - /// This field can be used to prevent replay of testnet transactions on mainnet. - pub chain_id: felt252, - /// The transaction's nonce. - pub nonce: felt252, - /// A span of `ResourceBounds` structs used for V3 transactions. - pub resource_bounds: Span, - /// The tip of the transaction. - pub tip: u128, - /// If specified, the paymaster should pay for the execution of the transaction. - /// The data includes the address of the paymaster sponsoring the transaction, followed by - /// extra data to send to the paymaster. - /// Used for V3 transactions. - pub paymaster_data: Span, - /// The data availability mode for the nonce. - /// Used for V3 transactions. - pub nonce_data_availability_mode: u32, - /// The data availability mode for the account balance from which fee will be taken. - /// Used for V3 transactions. - pub fee_data_availability_mode: u32, - /// If nonempty, will contain the required data for deploying and initializing an account - /// contract: its class hash, address salt and constructor calldata. - /// Used for V3 transactions. - pub account_deployment_data: Span, - /// The proof facts of the transaction. Used for client-side proving. - pub proof_facts: Span, - } -} diff --git a/corelib/src/starknet/secp256_trait.cairo b/corelib/src/starknet/secp256_trait.cairo deleted file mode 100644 index 37b3c03312..0000000000 --- a/corelib/src/starknet/secp256_trait.cairo +++ /dev/null @@ -1,373 +0,0 @@ -//! Elliptic Curve Digital Signature Algorithm (ECDSA) for Secp256k1 and Secp256r1 curves. -//! -//! This module provides traits and functions for working with ECDSA signatures -//! on the Secp256k1 and the Secp256r1 curves. It includes utilities for creating -//! and validating signatures, as well as recovering public keys from signatures. -//! -//! # Examples -//! -//! ``` -//! use starknet::SyscallResultTrait; -/// use starknet::secp256r1::Secp256r1Point; -/// use starknet::secp256_trait::{Secp256Trait, Signature, is_signature_entry_valid, -/// is_valid_signature, recover_public_key}; -/// -/// assert!( -/// is_signature_entry_valid::< -/// Secp256r1Point, -/// >(0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac), -/// ); -/// -/// let msg_hash = 0x4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4d; -/// let r = 0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac; -/// let s = 0x36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d60; -/// let public_key = Secp256Trait::secp256_ec_new_syscall( -/// 0x4aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff3, -/// 0x7618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e, -/// ) -/// .unwrap_syscall() -/// .unwrap(); -/// -/// assert!(is_valid_signature::(msg_hash, r, s, public_key)); -/// -/// let signature = Signature { -/// r: 0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac, -/// s: 0x36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d60, -/// y_parity: true, -/// }; -/// -/// let public_key = recover_public_key::(msg_hash, signature); -/// ``` - -#[allow(unused_imports)] -use core::array::ArrayTrait; -#[allow(unused_imports)] -use core::integer::U256TryIntoNonZero; -use core::math::{u256_inv_mod, u256_mul_mod_n}; -use core::traits::{Into, TryInto}; -#[allow(unused_imports)] -use starknet::eth_address::U256IntoEthAddress; -#[allow(unused_imports)] -use starknet::{EthAddress, SyscallResult, SyscallResultTrait}; - -/// Represents a Secp256{k/r}1 ECDSA signature. -/// -/// This struct holds the components of an ECDSA signature: `r`, `s`, and `y_parity`. -#[derive(Copy, Drop, Debug, PartialEq, Serde, Hash)] -pub struct Signature { - pub r: u256, - pub s: u256, - /// The parity of the y coordinate of the elliptic curve point whose x coordinate is `r`. - /// `y_parity == true` means that the y coordinate is odd. - /// Some places use non boolean `v` instead of `y_parity`. - /// In that case, `signature_from_vrs` should be used. - pub y_parity: bool, -} - -impl SignatureStorePacking of starknet::StorePacking { - fn pack(value: Signature) -> (u256, u256, bool) { - (value.r, value.s, value.y_parity) - } - - fn unpack(value: (u256, u256, bool)) -> Signature { - let (r, s, y_parity) = value; - Signature { r, s, y_parity } - } -} - -/// Creates an ECDSA signature from the `v`, `r`, and `s` values. -/// -/// `v` is the sum of an odd number and the parity of the y coordinate of the ec point whose x -/// coordinate is `r`. -/// -/// See https://eips.ethereum.org/EIPS/eip-155 for more details. -/// -/// # Examples -/// -/// ``` -/// use starknet::secp256_trait::signature_from_vrs; -/// -/// let signature = signature_from_vrs(0, -/// 0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac, -/// 0x36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d60); -/// ``` -pub fn signature_from_vrs(v: u32, r: u256, s: u256) -> Signature { - Signature { r, s, y_parity: v % 2 == 0 } -} - -/// A trait for interacting with Secp256{k/r}1 curves. -/// -/// Provides operations needed to work with Secp256k1 and Secp256r1 elliptic curves. -/// It includes methods for accessing curve parameters and creating curve points. -/// -/// # Examples -/// -/// ``` -/// use starknet::secp256k1::Secp256k1Point; -/// use starknet::secp256_trait::Secp256Trait; -/// use starknet::SyscallResultTrait; -/// -/// assert!( -/// Secp256Trait::< -/// Secp256k1Point, -/// >::get_curve_size() == 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141, -/// ); -/// -/// let generator = Secp256Trait::::get_generator_point(); -/// -/// let generator = Secp256Trait::< -/// Secp256k1Point, -/// >::secp256_ec_new_syscall( -/// 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, -/// 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, -/// ) -/// .unwrap_syscall(); -/// -/// let random_point = Secp256Trait::< -/// Secp256k1Point, -/// >::secp256_ec_get_point_from_x_syscall( -/// 0x4aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff3, true, -/// ); -/// ``` -pub trait Secp256Trait { - /// Returns the order (size) of the curve's underlying field. - /// - /// This is the number of points on the curve, also known as the curve order. - fn get_curve_size() -> u256; - - /// Returns the generator point (G) for the curve. - /// - /// The generator point is a standard base point on the curve from which other points - /// can be generated through scalar multiplication. - fn get_generator_point() -> Secp256Point; - - /// Creates a new curve point from its x and y coordinates. - /// - /// Returns `None` if the provided coordinates don't represent a valid point on the curve. - fn secp256_ec_new_syscall(x: u256, y: u256) -> SyscallResult>; - - /// Creates a curve point on the curve given its x-coordinate and y-parity. - /// - /// # Arguments - /// - /// * `x` - The x coordinate of the point - /// * `y_parity` - If true, choose the odd y value; if false, choose the even y value - /// - /// # Returns - /// - /// Returns `Some(point)` if a point exists with the given x coordinate, - /// `None` otherwise. - fn secp256_ec_get_point_from_x_syscall( - x: u256, y_parity: bool, - ) -> SyscallResult>; -} - -/// A trait for performing operations on Secp256{k/r}1 curve points. -/// -/// Provides operations needed for elliptic curve cryptography, including point addition -/// and scalar multiplication. -/// -/// # Examples -/// -/// ``` -/// use starknet::SyscallResultTrait; -/// use starknet::secp256k1::Secp256k1Point; -/// use starknet::secp256_trait::Secp256PointTrait; -/// use starknet::secp256_trait::Secp256Trait; -/// -/// let generator = Secp256Trait::::get_generator_point(); -/// -/// assert!( -/// Secp256PointTrait::get_coordinates(generator) -/// .unwrap_syscall() == ( -/// 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, -/// 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, -/// ), -/// ); -/// -/// let point = Secp256PointTrait::add(generator, generator); -/// let other_point = Secp256PointTrait::mul(generator, 2); -/// ``` -pub trait Secp256PointTrait { - /// Returns the x and y coordinates of the curve point. - fn get_coordinates(self: Secp256Point) -> SyscallResult<(u256, u256)>; - - /// Performs elliptic curve point addition. - /// - /// Adds `self` and `other` following the curve's addition law and returns - /// the resulting point. - fn add(self: Secp256Point, other: Secp256Point) -> SyscallResult; - - /// Performs scalar multiplication of a curve point. - /// - /// Multiplies `self` by the given scalar value. - fn mul(self: Secp256Point, scalar: u256) -> SyscallResult; -} - -/// Checks whether the given `value` is in the range [1, N), where N is the size of the curve. -/// -/// For ECDSA signatures to be secure, both `r` and `s` components must be in the range [1, N), -/// where N is the order of the curve. -/// This function validates that a given value meets this requirement. -/// -/// # Returns -/// -/// Returns `true` if the value is in the valid range [1, N), `false` otherwise. -/// -/// # Examples -/// -/// ``` -/// use starknet::secp256r1::Secp256r1Point; -/// use starknet::secp256_trait::is_signature_entry_valid; -/// -/// assert!(!is_signature_entry_valid::(0)); -/// ``` -pub fn is_signature_entry_valid< - Secp256Point, +Drop, impl Secp256Impl: Secp256Trait, ->( - value: u256, -) -> bool { - value != 0_u256 && value < Secp256Impl::get_curve_size() -} - -/// Checks whether the given `s` is in the range [1, N / 2], where N is the size of the curve. -/// -/// For ECDSA signatures to be secure, the `s` component must be in the range [1, N / 2], -/// where N is the order of the curve. -/// This function validates that a given value meets this requirement. -/// -/// # Returns -/// -/// Returns `true` if the value is in the valid range [1, N / 2], `false` otherwise. -/// -/// # Examples -/// -/// ``` -/// use starknet::secp256r1::Secp256r1Point; -/// use starknet::secp256_trait::is_signature_s_valid; -/// -/// assert!(!is_signature_s_valid::(0)); -/// ``` -pub(crate) fn is_signature_s_valid< - Secp256Point, +Drop, impl Secp256Impl: Secp256Trait, ->( - s: u256, -) -> bool { - s != 0_u256 && s <= Secp256Impl::get_curve_size() / 2 -} - -/// Checks whether a signature is valid given a public key point and a message hash. -/// -/// # Examples -/// -/// ``` -/// use starknet::SyscallResultTrait; -/// use starknet::secp256r1::Secp256r1Point; -/// use starknet::secp256_trait::{Secp256Trait, is_valid_signature}; -/// -/// let msg_hash = 0x4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4d; -/// let r = 0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac; -/// let s = 0x36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d60; -/// let public_key = Secp256Trait::secp256_ec_new_syscall( -/// 0x4aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff3, -/// 0x7618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e, -/// ) -/// .unwrap_syscall() -/// .unwrap(); -/// -/// assert!(is_valid_signature::(msg_hash, r, s, public_key)); -/// ``` -pub fn is_valid_signature< - Secp256Point, - +Drop, - impl Secp256Impl: Secp256Trait, - +Secp256PointTrait, ->( - msg_hash: u256, r: u256, s: u256, public_key: Secp256Point, -) -> bool { - if !is_signature_entry_valid::(r) || !is_signature_s_valid::(s) { - return false; - } - - let Some(order) = Secp256Impl::get_curve_size().try_into() else { - return false; - }; - let Some(s_inv) = u256_inv_mod(s, order) else { - return false; - }; - let s_inv = s_inv.into(); - let u1 = u256_mul_mod_n(msg_hash, s_inv, order); - let u2 = u256_mul_mod_n(r, s_inv, order); - - let generator_point = Secp256Impl::get_generator_point(); - let point1 = generator_point.mul(u1).unwrap_syscall(); - let point2 = public_key.mul(u2).unwrap_syscall(); - let sum = point1.add(point2).unwrap_syscall(); - - let (x, _y) = sum.get_coordinates().unwrap_syscall(); - x == r -} - -/// Recovers the public key associated with a given signature and message hash. -/// -/// Returns the public key as a point on the curve. -/// -/// # Examples -/// -/// ``` -/// use starknet::secp256r1::Secp256r1Point; -/// use starknet::secp256_trait::{Signature, recover_public_key}; -/// -/// let msg_hash = 0x4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4d; -/// -/// let signature = Signature { -/// r: 0xa73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac, -/// s: 0x36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d60, -/// y_parity: true, -/// }; -/// -/// let public_key = recover_public_key::(msg_hash, signature); -/// ``` -pub fn recover_public_key< - Secp256Point, - +Drop, - impl Secp256Impl: Secp256Trait, - +Secp256PointTrait, ->( - msg_hash: u256, signature: Signature, -) -> Option { - let Signature { r, s, y_parity } = signature; - if !is_signature_entry_valid::(r) || !is_signature_s_valid::(s) { - return None; - } - // Note this additionally checks that `r` is valid. - let r_point = Secp256Impl::secp256_ec_get_point_from_x_syscall(x: r, :y_parity) - .unwrap_syscall()?; - let generator_point = Secp256Impl::get_generator_point(); - - // The result is given by - // -(msg_hash / r) * gen + (s / r) * r_point - // where the divisions by `r` are modulo `N` (the size of the curve). - - let n_nz = Secp256Impl::get_curve_size().try_into()?; - let r_inv = u256_inv_mod(r.try_into()?, n_nz)?.into(); - - let u1 = u256_mul_mod_n(msg_hash, r_inv, n_nz); - let minus_u1 = secp256_ec_negate_scalar::(u1); - let u2 = u256_mul_mod_n(s, r_inv, n_nz); - - let minus_point1 = generator_point.mul(minus_u1).unwrap_syscall(); - - let point2 = r_point.mul(u2).unwrap_syscall(); - - Some(minus_point1.add(point2).unwrap_syscall()) -} - -/// Computes the negation of a scalar modulo N (the size of the curve). -fn secp256_ec_negate_scalar< - Secp256Point, +Drop, impl Secp256Impl: Secp256Trait, ->( - c: u256, -) -> u256 { - Secp256Impl::get_curve_size() - c -} diff --git a/corelib/src/starknet/secp256k1.cairo b/corelib/src/starknet/secp256k1.cairo deleted file mode 100644 index 62667864ca..0000000000 --- a/corelib/src/starknet/secp256k1.cairo +++ /dev/null @@ -1,123 +0,0 @@ -//! Functions and constructs related to elliptic curve operations on the secp256k1 curve. -//! -//! This module provides functionality for performing operations on the secp256k1 elliptic curve, -//! commonly used in cryptographic applications such as Bitcoin and Ethereum. -//! It implements the traits defined in the `secp256_trait` module to ensure consistent behavior -//! across different secp256 curve implementations. -//! -//! Curve information: -//! * Base field: q = -//! 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f -//! * Scalar field: r = -//! 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 -//! * Curve equation: y^2 = x^3 + 7 - -use core::gas::GasBuiltin; -use core::option::OptionTrait; -#[allow(unused_imports)] -use starknet::secp256_trait::{ - Secp256PointTrait, Secp256Trait, Signature, is_signature_entry_valid, recover_public_key, -}; -#[allow(unused_imports)] -use starknet::{SyscallResult, SyscallResultTrait}; - -/// A point on the secp256k1 curve. -pub extern type Secp256k1Point; - -impl Secp256k1PointCopy of Copy; -impl Secp256k1PointDrop of Drop; - -pub(crate) impl Secp256k1Impl of Secp256Trait { - // TODO(yuval): change to constant once u256 constants are supported. - fn get_curve_size() -> u256 { - 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - } - - fn get_generator_point() -> Secp256k1Point { - secp256k1_new_syscall( - 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, - 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, - ) - .unwrap_syscall() - .unwrap() - } - - fn secp256_ec_new_syscall(x: u256, y: u256) -> SyscallResult> { - secp256k1_new_syscall(x, y) - } - - fn secp256_ec_get_point_from_x_syscall( - x: u256, y_parity: bool, - ) -> SyscallResult> { - secp256k1_get_point_from_x_syscall(x, y_parity) - } -} - -pub(crate) impl Secp256k1PointImpl of Secp256PointTrait { - fn get_coordinates(self: Secp256k1Point) -> SyscallResult<(u256, u256)> { - secp256k1_get_xy_syscall(self) - } - - fn add(self: Secp256k1Point, other: Secp256k1Point) -> SyscallResult { - secp256k1_add_syscall(self, other) - } - - fn mul(self: Secp256k1Point, scalar: u256) -> SyscallResult { - secp256k1_mul_syscall(self, scalar) - } -} - -/// Creates a new point on the secp256k1 curve from its `x` and `y` coordinates. -/// -/// # Returns -/// -/// Returns `Some(point)` if the coordinates represent a valid point on the curve, -/// `None` otherwise. -extern fn secp256k1_new_syscall( - x: u256, y: u256, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -/// Adds two points `p0` and `p1` on the secp256k1 curve. -extern fn secp256k1_add_syscall( - p0: Secp256k1Point, p1: Secp256k1Point, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Multiplies a point `p` on the secp256k1 curve by the given `scalar`. -extern fn secp256k1_mul_syscall( - p: Secp256k1Point, scalar: u256, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Recovers a point on the curve given its x-coordinate and y-parity. -/// -/// Since the curve equation y² = x³ + 7 has two solutions for y given x, -/// the y_parity parameter is used to determine which y value to use. -/// -/// # Arguments -/// -/// * `x` - The x coordinate of the point -/// * `y_parity` - If true, choose the odd y value; if false, choose the even y value -/// -/// # Returns -/// -/// Returns `Some(point)` if a point exists with the given x coordinate, -/// `None` otherwise. -extern fn secp256k1_get_point_from_x_syscall( - x: u256, y_parity: bool, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -/// Returns the coordinates of a point on the Secp256k1 curve. -extern fn secp256k1_get_xy_syscall( - p: Secp256k1Point, -) -> SyscallResult<(u256, u256)> implicits(GasBuiltin, System) nopanic; - -impl Secp256k1PointSerde of Serde { - fn serialize(self: @Secp256k1Point, ref output: Array) { - let point = (*self).get_coordinates().unwrap_syscall(); - point.serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - let (x, y) = Serde::<(u256, u256)>::deserialize(ref serialized)?; - secp256k1_new_syscall(x, y).unwrap_syscall() - } -} diff --git a/corelib/src/starknet/secp256r1.cairo b/corelib/src/starknet/secp256r1.cairo deleted file mode 100644 index 349e5d0368..0000000000 --- a/corelib/src/starknet/secp256r1.cairo +++ /dev/null @@ -1,122 +0,0 @@ -//! Functions and constructs related to elliptic curve operations on the secp256r1 curve. -//! -//! This module provides functionality for performing operations on the NIST P-256 (also known as -//! secp256r1) elliptic curve. It implements the traits defined in the `secp256_trait` module to -//! ensure consistent behavior across different secp256 curve implementations. -//! -//! Curve information: -//! * Base field: q = -//! 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff -//! * Scalar field: r = -//! 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 -//! * a = -3 -//! * b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b -//! * Curve equation: y^2 = x^3 + ax + b - -use core::gas::GasBuiltin; -use core::option::OptionTrait; -#[allow(unused_imports)] -use starknet::secp256_trait::{Secp256PointTrait, Secp256Trait}; -#[allow(unused_imports)] -use starknet::{EthAddress, SyscallResult, SyscallResultTrait}; - -/// Represents a point on the secp256r1 elliptic curve. -pub extern type Secp256r1Point; - -impl Secp256r1PointCopy of Copy; -impl Secp256r1PointDrop of Drop; - -pub(crate) impl Secp256r1Impl of Secp256Trait { - // TODO(yuval): change to constant once u256 constants are supported. - fn get_curve_size() -> u256 { - 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 - } - - fn get_generator_point() -> Secp256r1Point { - secp256r1_new_syscall( - 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, - 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, - ) - .unwrap_syscall() - .unwrap() - } - - fn secp256_ec_new_syscall(x: u256, y: u256) -> SyscallResult> { - secp256r1_new_syscall(x, y) - } - - fn secp256_ec_get_point_from_x_syscall( - x: u256, y_parity: bool, - ) -> SyscallResult> { - secp256r1_get_point_from_x_syscall(x, y_parity) - } -} - -pub(crate) impl Secp256r1PointImpl of Secp256PointTrait { - fn get_coordinates(self: Secp256r1Point) -> SyscallResult<(u256, u256)> { - secp256r1_get_xy_syscall(self) - } - - fn add(self: Secp256r1Point, other: Secp256r1Point) -> SyscallResult { - secp256r1_add_syscall(self, other) - } - - fn mul(self: Secp256r1Point, scalar: u256) -> SyscallResult { - secp256r1_mul_syscall(self, scalar) - } -} - -/// Creates a new point on the secp256r1 curve from its `x` and `y` coordinates. -/// -/// # Returns -/// -/// Returns `Some(point)` if the coordinates represent a valid point on the curve, -/// `None` otherwise. -extern fn secp256r1_new_syscall( - x: u256, y: u256, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -/// Adds two points `p0` and `p1` on the secp256r1 curve. -extern fn secp256r1_add_syscall( - p0: Secp256r1Point, p1: Secp256r1Point, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Multiplies a point `p` on the curve by the given `scalar`. -extern fn secp256r1_mul_syscall( - p: Secp256r1Point, scalar: u256, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Recovers a point on the curve given its x-coordinate and `y-parity`. -/// -/// Since the curve equation y² = x³ + ax + b has two solutions for y given x, -/// the `y_parity` parameter is used to determine which y value to use. -/// -/// # Arguments -/// -/// * `x` - The x coordinate of the point -/// * `y_parity` - If true, choose the odd y value; if false, choose the even y value -/// -/// # Returns -/// -/// Returns `Some(point)` if a point exists with the given x coordinate, -/// `None` otherwise. -extern fn secp256r1_get_point_from_x_syscall( - x: u256, y_parity: bool, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -/// Returns the coordinates of a point on the secp256r1 curve. -extern fn secp256r1_get_xy_syscall( - p: Secp256r1Point, -) -> SyscallResult<(u256, u256)> implicits(GasBuiltin, System) nopanic; - -impl Secp256r1PointSerde of Serde { - fn serialize(self: @Secp256r1Point, ref output: Array) { - let point = (*self).get_coordinates().unwrap_syscall(); - point.serialize(ref output) - } - - fn deserialize(ref serialized: Span) -> Option { - let (x, y) = Serde::<(u256, u256)>::deserialize(ref serialized)?; - secp256r1_new_syscall(x, y).unwrap_syscall() - } -} diff --git a/corelib/src/starknet/storage.cairo b/corelib/src/starknet/storage.cairo deleted file mode 100644 index 09fc6d2514..0000000000 --- a/corelib/src/starknet/storage.cairo +++ /dev/null @@ -1,603 +0,0 @@ -//! Storage-related types and traits for Cairo contracts. -//! -//! This module implements the storage system for Starknet contracts, providing high-level -//! abstractions for persistent data storage. It offers a type-safe interface for reading and -//! writing to Starknet storage through the [`StoragePointerReadAccess`] and -//! [`StoragePointerWriteAccess`] traits, along with useful storage-only collection types like -//! [`Vec`] and [`Map`]. -//! -//! [`Vec`]: starknet::storage::vec::Vec -//! [`Map`]: starknet::storage::map::Map -//! -//! # Overview -//! -//! The storage system in Starknet contracts is built on a key-value store where each storage slot -//! is identified by a 251-bit address. The storage system allows interactions with storage using -//! state variables, which are declared inside a `Storage` struct annotated with the `#[storage]` -//! attribute. This ensures type-safe storage access and simplifies the process of reading and -//! writing to storage. -//! -//! # Using the Storage System -//! -//! Storage is typically declared using the `#[storage]` attribute on a struct: -//! -//! ``` -//! #[storage] -//! struct Storage { -//! balance: u256, -//! users: Map, -//! nested_data: Map>, -//! collection: Vec, -//! } -//! ``` -//! -//! Any type that implements the `Store` trait (or its optimized `StorePacked` variant) can be used -//! in storage. This type can simply be derived using `#[derive(Store)]` - provided that all of the -//! members of the type also implement `Store`. -//! -//! ``` -//! #[derive(Copy, Default, Drop, Store)] -//! struct User { -//! name: felt252, -//! age: u8, -//! } -//! ``` -//! -//! Interaction with storage is made through a set of traits, depending on the type interacted -//! with: -//! -//! - [`StoragePointerReadAccess`] and [`StoragePointerWriteAccess`] allow for reading and writing -//! storable types. -//! - [`StorageMapReadAccess`] and [`StorageMapWriteAccess`] allow for reading and writing to -//! storage [`Map`]s. -//! - [`StoragePathEntry`] allows for accessing a specific entry in a [`Map`], and can be combined -//! with the `StoragePointer` traits to read and write in these entries. -//! - [`VecTrait`] and [`MutableVecTrait`] allow for interacting with storage [`Vec`]s. -//! -//! [`VecTrait`]: starknet::storage::vec::VecTrait -//! [`MutableVecTrait`]: starknet::storage::vec::MutableVecTrait -//! [`StorageMapReadAccess`]: starknet::storage::map::StorageMapReadAccess -//! [`StorageMapWriteAccess`]: starknet::storage::map::StorageMapWriteAccess -//! [`StoragePathEntry`]: starknet::storage::map::StoragePathEntry -//! -//! ## Examples -//! -//! ``` -//! fn use_storage(self: @ContractState) { -//! let address = 'address'.try_into().unwrap(); -//! // Reading values -//! let balance = self.balance.read(); -//! // For a `Map`, use the `entry` method to access values at specific keys: -//! let user = self.users.entry(address).read(); -//! // Accessing nested `Map`s requires chaining `entry` calls: -//! let nested = self.nested_data.entry(address).entry(address).read(); -//! // Accessing a specific index in a `Vec` requires using the `index` method: -//! let element = self.collection[index]; -//! -//! // Writing values -//! self.balance.write(100); -//! self.users.entry(address).write(Default::default()); -//! self.nested_data.entry(address).entry(address).write(10); -//! self.collection[index].write(20); -//! } -//! ``` -//! -//! # Storage Lifecycle -//! -//! When you access a storage variable, it goes through several transformations: -//! -//! 1. **FlattenedStorage**: The starting point is your contract's storage struct. Each member is -//! represented either as a `StorageBase` or another `FlattenedStorage` (for `#[substorage(v0)]` -//! or `#[flat]` members). -//! -//! 2. **StorageBase**: For simple variables, this holds the `sn_keccak` hash of the variable name, -//! which becomes the storage address. For example: -//! ``` -//! #[storage] -//! struct Storage { -//! balance: u128, // Stored at sn_keccak('balance') -//! } -//! ``` -//! 3. **StoragePath**: For complex types, a `StoragePath` represents an un-finalized path to a -//! specific entry in storage. For example, a `StoragePath` for a `Map` can be updated with -//! specific keys to point to a specific entry in the map. -//! -//! 4. **StoragePointer**: The final form, pointing to the actual storage location. For multi-slot -//! values (like structs), values are stored sequentially from this address. -//! -//! # Storage Collections -//! -//! Cairo's memory collection types, like [`Felt252Dict`] and [`Array`], cannot be used in storage. -//! Consequently, any type that contains these types cannot be used in storage either. -//! Instead, Cairo has two storage-only collection types: [`Map`] and [`Vec`]. -//! -//! Instead of storing these _memory_ collections directly, you will need to reflect them into -//! storage using the [`Map`] and [`Vec`] types. -//! -//! # Address Calculation -//! -//! Storage addresses are calculated deterministically: -//! -//! * For a single value variable, the address is the `sn_keccak` hash of the variable name's ASCII -//! encoding. `sn_keccak` is Starknet's version of the Keccak-256 hash function, with its output -//! truncated to 250 bits. -//! -//! * For variables composed of multiple values (tuples, structs, or enums), the base storage -//! address is also the `sn_keccak` hash of the variable name's ASCII encoding. The storage layout -//! then varies depending on the specific type. A struct will store its members as a sequence of -//! primitive types, while an enum will store its variant index, followed by the members of the -//! variant. -//! -//! * For variables within a storage node, the address is calculated using a chain of hashes that -//! represents the node structure. Given a member `m` within a storage variable `variable_name`, -//! the path is computed as `h(sn_keccak(variable_name), sn_keccak(m))`, where `h` is the Pedersen -//! hash. For nested storage nodes, this process repeats, creating a hash chain representing the -//! path to each leaf node. At the leaf node, the storage calculation follows the standard rules for -//! that variable type. -//! -//! * For [`Map`] or [`Vec`] variables, the address is calculated relative to the storage base -//! address (the `sn_keccak` hash of the variable name) combined with the mapping keys or vector -//! indices. -//! See their respective module documentation for more details. -use core::hash::HashStateTrait; -#[allow(unused_imports)] -use core::pedersen::HashState; -use core::traits::Into; -#[allow(unused_imports)] -use starknet::SyscallResult; -use starknet::storage_access::{StorageBaseAddress, storage_base_address_from_felt252}; - -mod map; -pub use map::{Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry}; - -mod storage_base; -pub use storage_base::{FlattenedStorage, StorageBase, StorageTrait, StorageTraitMut}; - -mod storage_node; -pub use storage_node::{StorageNode, StorageNodeMut}; - -mod sub_pointers; -pub use sub_pointers::{SubPointers, SubPointersForward, SubPointersMut, SubPointersMutForward}; - -mod vec; -use vec::{ - MutableVecIndexView, MutableVecIntoIterRange, PathableMutableVecIntoIterRange, - PathableVecIntoIterRange, VecIndexView, VecIntoIterRange, -}; -pub use vec::{MutableVecTrait, Vec, VecIter, VecTrait}; - -/// A pointer to an address in storage, can be used to read and write values, if the generic type -/// supports it (e.g. basic types like `felt252`). -pub struct StoragePointer { - pub __storage_pointer_address__: StorageBaseAddress, - pub __storage_pointer_offset__: u8, -} - -impl StoragePointerCopy of Copy> {} -impl StoragePointerDrop of Drop> {} - -/// This makes the sub-pointers members directly accessible from a pointer to the parent struct. -pub impl SubPointersDeref> of core::ops::Deref> { - type Target = SubPointers::::SubPointersType; - fn deref(self: StoragePointer) -> Self::Target { - self.sub_pointers() - } -} - -/// This makes the sub-pointers members directly accessible from a pointer to the parent struct. -pub impl SubPointersMutDeref< - T, +SubPointersMut, -> of core::ops::Deref>> { - type Target = SubPointersMut::::SubPointersType; - fn deref(self: StoragePointer>) -> Self::Target { - self.sub_pointers_mut() - } -} - - -/// Same as `StoragePointer`, but with `offset` 0, which allows for some optimizations. -pub struct StoragePointer0Offset { - pub __storage_pointer_address__: StorageBaseAddress, -} - -impl StoragePointer0OffsetCopy of Copy> {} -impl StoragePointer0OffsetDrop of Drop> {} - -/// Trait for converting a storage member to a `StoragePointer0Offset`. -// type instead of `T`. -pub trait StorageAsPointer { - type Value; - fn as_ptr(self: @TMemberState) -> StoragePointer0Offset; -} - -/// Trait for accessing the values in storage using a `StoragePointer`. -/// -/// # Examples -/// -//! ``` -//! use starknet::storage::StoragePointerReadAccess; -//! -//! #[storage] -//! struct Storage { -//! element: felt252, -//! } -//! -//! fn read_storage(self: @ContractState) -> felt252 { -//! self.element.read() -//! } -//! ``` -pub trait StoragePointerReadAccess { - type Value; - fn read(self: @T) -> Self::Value; -} - -/// Trait for writing values to storage using a `StoragePointer`. -/// -/// # Examples -/// -//! ``` -//! use starknet::storage::StoragePointerWriteAccess; -//! -//! #[storage] -//! struct Storage { -//! element: felt252, -//! } -//! -//! fn write_storage(self: @ContractState) { -//! self.element.write(1); -//! } -//! ``` -pub trait StoragePointerWriteAccess { - type Value; - fn write(self: T, value: Self::Value); -} - -/// Simple implementation of `StoragePointerReadAccess` for any type that implements `Store` for 0 -/// offset. -impl StorableStoragePointer0OffsetReadAccess< - T, +starknet::Store, -> of StoragePointerReadAccess> { - type Value = T; - fn read(self: @StoragePointer0Offset) -> T { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::::read(0, self.__storage_pointer_address__), - ) - } -} - -/// Simple implementation of `StoragePointerReadAccess` for any mutable type that implements `Store` -/// for 0 offset. -impl MutableStorableStoragePointer0OffsetReadAccess< - T, +MutableTrait, +starknet::Store::InnerType>, -> of StoragePointerReadAccess> { - type Value = MutableTrait::::InnerType; - fn read(self: @StoragePointer0Offset) -> MutableTrait::::InnerType { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - MutableTrait::::InnerType, - >::read(0, self.__storage_pointer_address__), - ) - } -} - -/// Simple implementation of `StoragePointerWriteAccess` for any mutable type that implements -/// `Store` for 0 offset. -impl StorableStoragePointer0OffsetWriteAccess< - T, +MutableTrait, +starknet::Store::InnerType>, -> of StoragePointerWriteAccess> { - type Value = MutableTrait::::InnerType; - fn write(self: StoragePointer0Offset, value: MutableTrait::::InnerType) { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - MutableTrait::::InnerType, - >::write(0, self.__storage_pointer_address__, value), - ) - } -} - -/// Simple implementation of `StoragePointerReadAccess` for any type that implements `Store` for any -/// offset. -pub impl StorableStoragePointerReadAccess< - T, +starknet::Store, -> of StoragePointerReadAccess> { - type Value = T; - fn read(self: @StoragePointer) -> T { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - T, - >::read_at_offset(0, self.__storage_pointer_address__, self.__storage_pointer_offset__), - ) - } -} - -/// Simple implementation of `StoragePointerReadAccess` for any mutable type that implements `Store` -/// for any offset. -impl MutableStorableStoragePointerReadAccess< - T, +MutableTrait, +starknet::Store::InnerType>, -> of StoragePointerReadAccess> { - type Value = MutableTrait::::InnerType; - fn read(self: @StoragePointer) -> MutableTrait::::InnerType { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - MutableTrait::::InnerType, - >::read_at_offset(0, self.__storage_pointer_address__, self.__storage_pointer_offset__), - ) - } -} - -/// Simple implementation of `StoragePointerWriteAccess` for any mutable type that implements -/// `Store` for any offset. -impl MutableStorableStoragePointerWriteAccess< - T, +MutableTrait, +starknet::Store::InnerType>, -> of StoragePointerWriteAccess> { - type Value = MutableTrait::::InnerType; - fn write(self: StoragePointer, value: MutableTrait::::InnerType) { - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - MutableTrait::::InnerType, - >::write_at_offset( - 0, self.__storage_pointer_address__, self.__storage_pointer_offset__, value, - ), - ) - } -} - -/// An intermediate struct to store a hash state, in order to be able to hash multiple values and -/// get the final address. -/// Storage path should have two interfaces, if `T` is storable then it should implement -/// `StorageAsPointer` in order to be able to get the address of the storage path. Otherwise, if -/// `T` is not storable then it should implement some kind of updating trait, e.g. -/// `StoragePathEntry`. -pub struct StoragePath { - __hash_state__: StoragePathHashState, -} - -/// The hash state of a storage path. -type StoragePathHashState = core::pedersen::HashState; - -impl StoragePathCopy of core::traits::Copy> {} -impl StoragePathDrop of core::traits::Drop> {} - -/// This makes the storage node members directly accessible from a path to the parent struct. -pub impl StorageNodeDeref> of core::ops::Deref> { - type Target = StorageNode::::NodeType; - fn deref(self: StoragePath) -> Self::Target { - self.storage_node() - } -} - -/// This makes the storage node members directly accessible from a path to the parent struct. -pub impl StorageNodeMutDeref> of core::ops::Deref>> { - type Target = StorageNodeMut::::NodeType; - fn deref(self: StoragePath>) -> Self::Target { - self.storage_node_mut() - } -} - -/// Trait for StoragePath operations. -trait StoragePathTrait { - fn new(init_value: felt252) -> StoragePath; - fn finalize(self: StoragePath) -> StorageBaseAddress; -} - -impl StoragePathImpl of StoragePathTrait { - fn new(init_value: felt252) -> StoragePath { - StoragePath { __hash_state__: core::pedersen::PedersenTrait::new(init_value) } - } - - fn finalize(self: StoragePath) -> StorageBaseAddress { - storage_base_address_from_felt252(self.__hash_state__.finalize()) - } -} - -/// Trait for updating the hash state of a storage path with a given value. Also changes the generic -/// type of the storage path from `SourceType` to `TargetType`. -trait StoragePathUpdateTrait { - fn update(self: StoragePath, value: Value) -> StoragePath; -} - -impl StoragePathUpdateImpl< - SourceType, TargetType, Value, impl HashImpl: core::hash::Hash, -> of StoragePathUpdateTrait { - fn update(self: StoragePath, value: Value) -> StoragePath { - StoragePath { __hash_state__: HashImpl::update_state(self.__hash_state__, value) } - } -} - -impl StoragePathSIntoStoragePathTImpl< - SourceType, TargetType, -> of Into, StoragePath> { - fn into(self: StoragePath) -> StoragePath { - StoragePath { __hash_state__: self.__hash_state__ } - } -} - -/// Trait for creating a new `StoragePath` from a storage member. -pub trait StorageAsPath { - type Value; - fn as_path(self: @TMemberState) -> StoragePath; -} - -/// An implementation of `StorageAsPointer` for any `StoragePath` with inner type that implements -/// `Store`. -impl StorableStoragePathAsPointer> of StorageAsPointer> { - type Value = T; - fn as_ptr(self: @StoragePath) -> StoragePointer0Offset { - StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() } - } -} - -/// An implementation of `StorageAsPointer` for any `StoragePath` with inner type that implements -/// `Store`. -impl MutableStorableStoragePathAsPointer< - T, +MutableTrait, +starknet::Store::InnerType>, -> of StorageAsPointer> { - type Value = T; - fn as_ptr(self: @StoragePath) -> StoragePointer0Offset { - StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() } - } -} - -/// Implement `Deref` for storage paths that implements `StorageAsPointer`. -impl StoragePathDeref< - T, impl PointerImpl: StorageAsPointer>, -> of core::ops::Deref> { - type Target = StoragePointer0Offset; - fn deref(self: StoragePath) -> StoragePointer0Offset { - self.as_ptr() - } -} - -/// Implement `Deref` for `StoragePointer0Offset` into a `StoragePointer`. -impl StoragePointer0OffsetDeref of core::ops::Deref> { - type Target = StoragePointer; - fn deref(self: StoragePointer0Offset) -> StoragePointer { - StoragePointer::< - T, - > { - __storage_pointer_address__: self.__storage_pointer_address__, - __storage_pointer_offset__: 0, - } - } -} - -/// A struct for delaying the creation of a storage path, used for lazy evaluation in storage nodes. -pub struct PendingStoragePath { - __hash_state__: StoragePathHashState, - __pending_key__: felt252, -} - -/// A trait for creating a `PendingStoragePath` from a `StoragePath` hash state and a key. -pub trait PendingStoragePathTrait { - fn new(storage_path: @StoragePath, pending_key: felt252) -> PendingStoragePath; -} - -impl PendingStoragePathImpl of PendingStoragePathTrait { - fn new(storage_path: @StoragePath, pending_key: felt252) -> PendingStoragePath { - PendingStoragePath { - __hash_state__: storage_path.__hash_state__, __pending_key__: pending_key, - } - } -} - -impl PendingStoragePathDrop of Drop> {} -impl PendingStoragePathCopy of Copy> {} - -/// An implementation of 'StorageAsPath' for `PendingStoragePath`. -impl PendingStoragePathAsPath of StorageAsPath> { - type Value = T; - fn as_path(self: @PendingStoragePath) -> StoragePath { - StoragePath::< - T, - > { - __hash_state__: core::hash::HashStateTrait::update( - self.__hash_state__, self.__pending_key__, - ), - } - } -} - -/// Deref pending storage path into a storage path. -impl PendingStoragePathDeref of core::ops::Deref> { - type Target = StoragePath; - fn deref(self: PendingStoragePath) -> Self::Target { - self.as_path() - } -} - -/// Implement as_ptr for any type that implements StorageAsPath and Store. -impl StorablePathableStorageAsPointer< - T, - impl PathImpl: StorageAsPath, - impl PtrImpl: StorageAsPointer>, -> of StorageAsPointer { - type Value = PtrImpl::Value; - fn as_ptr(self: @T) -> StoragePointer0Offset { - let path = self.as_path(); - path.as_ptr() - } -} - -/// Implement StoragePointerReadAccess for any type that implements StorageAsPointer and -/// StoragePointerReadAccess. -impl StorablePointerReadAccessImpl< - T, - impl PointerImpl: StorageAsPointer, - impl AccessImpl: StoragePointerReadAccess>, -> of StoragePointerReadAccess { - type Value = AccessImpl::Value; - fn read(self: @T) -> Self::Value { - self.as_ptr().read() - } -} - -/// Implement StoragePointerWriteAccess for any type that implements StorageAsPointer. -impl StorablePointerWriteAccessImpl< - T, - impl PointerImpl: StorageAsPointer, - impl AccessImpl: StoragePointerWriteAccess>, - +Drop, - +Drop, -> of StoragePointerWriteAccess { - type Value = AccessImpl::Value; - fn write(self: T, value: Self::Value) { - let ptr: StoragePointer0Offset = self.as_ptr(); - ptr.write(value) - } -} - -/// A wrapper around different storage related types, indicating that the instance is mutable, -/// i.e. originally created from a `ref` contract state. -#[phantom] -pub struct Mutable {} - -impl MutableDrop of Drop> {} -impl MutableCopy of Copy> {} - - -/// A trait for exposing the inner type of a `Mutable` type. -trait MutableTrait { - type InnerType; -} - -impl MutableImpl of MutableTrait> { - type InnerType = T; -} - -pub trait StoragePathMutableConversion { - /// Converts a `StoragePath>` to a `StoragePath`. This is useful to expose - /// functions implemented for `StoragePath` on a `StoragePath>`. - fn as_non_mut(self: StoragePath>) -> StoragePath; -} - - -impl StoragePathAsNonMutImpl of StoragePathMutableConversion { - fn as_non_mut(self: StoragePath>) -> StoragePath { - StoragePath { __hash_state__: self.__hash_state__ } - } -} - - -/// Trait for turning collection of values into an iterator over a specific range. -pub trait IntoIterRange { - type IntoIter; - impl Iterator: Iterator; - /// Creates an iterator over a range from a collection. - fn into_iter_range(self: T, range: core::ops::Range) -> Self::IntoIter; - /// Creates an iterator over the full range of a collection. - fn into_iter_full_range(self: T) -> Self::IntoIter; -} - -/// Trait that ensures a type is valid for storage in Starknet contracts. -/// This trait is used to enforce that only specific types, such as those implementing -/// `Store` or acting as a `StorageNode`, can be a part of a storage hierarchy. Any type -/// that does not implement this trait cannot be used in a storage struct. -pub trait ValidStorageTypeTrait; - -/// Implementation of `ValidStorageTypeTrait` for types that implement `starknet::Store`. -impl ValidStorageTypeTraitStoreImpl> of ValidStorageTypeTrait; - -/// `StorageTrait` is typically used for storage nodes, which help organize contract storage -/// hierarchies. By implementing `ValidStorageTypeTrait`, this ensures that storage nodes (and -/// substorages within components) are valid storage types. -impl ValidStorageTypeTraitStorageNodeImpl> of ValidStorageTypeTrait; diff --git a/corelib/src/starknet/storage/map.cairo b/corelib/src/starknet/storage/map.cairo deleted file mode 100644 index 361a72a261..0000000000 --- a/corelib/src/starknet/storage/map.cairo +++ /dev/null @@ -1,338 +0,0 @@ -//! Key-value storage mapping implementation for Starknet contracts. -//! -//! This module provides the core mapping functionality used in Starknet smart contracts, -//! enabling persistent key-value storage. Unlike traditional hash tables, storage mappings -//! do not store the key data itself. Instead, they use the hash of the key to compute -//! a storage slot address where the corresponding value is stored. -//! -//! # Interacting with [`Map`] -//! -//! Storage maps can be accessed through two sets of traits, each serving different use cases: -//! -//! 1. Direct access using `StorageMapReadAccess`/`StorageMapWriteAccess`: -//! These traits allow you to read from or write to a map directly by providing the key(s) -//! and value: -//! ``` -//! // Read directly with key -//! let value = self.my_map.read(key); -//! -//! // Write directly with key and value -//! self.my_map.write(key, value); -//! ``` -//! -//! 2. Path-based access combining `StoragePathEntry` with -//! `StoragePointerReadAccess`/`StoragePointerWriteAccess`: -//! This approach first computes a `StoragePath` for the entry, which can then be used with -//! the `StoragePointer` access traits from `starknet::storage`: -//! ``` -//! // Get storage path for the entry -//! let path = self.my_map.entry(key); -//! -//! // Read/write using the storage pointer traits -//! let value = path.read(); -//! path.write(new_value); -//! ``` -//! -//! The path-based approach is particularly useful for: -//! - Nested mappings where you need to chain multiple keys -//! - Cases where you need to reuse the same storage path multiple times -//! -//! # Storage Address Computation -//! -//! Storage addresses for mapping entries are deterministically computed using hash functions: -//! -//! * For a single key mapping: -//! ```text -//! address = h(sn_keccak(variable_name), k) mod N -//! ``` -//! where: -//! - `h` is the Pedersen hash function -//! - `k` is the key value -//! - `N` is 2^251 - 256 -//! -//! * For nested mappings with multiple keys: -//! ```text -//! address = h(h(...h(h(sn_keccak(variable_name), k₁), k₂)...), kₙ) mod N -//! ``` -//! where each key `kᵢ` is hashed sequentially with the result of the previous hash. -//! -//! # Examples -//! -//! Basic usage with a single mapping: -//! -//! ``` -//! use starknet::ContractAddress; -//! use starknet::storage::{Map, StorageMapReadAccess, StoragePathEntry, -//! StoragePointerReadAccess}; -//! -//! #[storage] -//! struct Storage { -//! balances: Map, -//! } -//! -//! fn read_storage(self: @ContractState, address: ContractAddress) { -//! let balance = self.balances.read(address); -//! let balance = self.balances.entry(address).read(); -//! } -//! ``` -//! -//! Nested mappings: -//! -//! ``` -//! #[storage] -//! struct Storage { -//! allowances: Map>, -//! } -//! -//! fn read_storage(self: @ContractState, owner: ContractAddress, spender: ContractAddress) { -//! let allowance = self.allowances.entry(owner).entry(spender).read(); -//! let allowance = self.allowances.entry(owner).read(spender); -//! } -//! ``` - -#[allow(unused_imports)] -use super::{ - Mutable, MutableTrait, StorageAsPath, StorageAsPointer, StoragePath, StoragePathHashState, - StoragePathTrait, StoragePathUpdateTrait, StoragePointerReadAccess, StoragePointerWriteAccess, -}; - -/// Provides direct read access to values in a storage [`Map`]. -/// -/// # Examples -/// -/// ``` -/// use starknet::ContractAddress; -/// use starknet::storage::{Map, StorageMapReadAccess, StoragePathEntry}; -/// -/// #[storage] -/// struct Storage { -/// balances: Map, -/// allowances: Map>, -/// } -/// -/// fn read_storage(self: @ContractState, address: ContractAddress) { -/// // Read from single mapping -/// let balance = self.balances.read(address); -/// // Read from nested mapping -/// let allowance = self.allowances.entry(owner).read(spender); -/// } -/// ``` -pub trait StorageMapReadAccess { - type Key; - type Value; - fn read(self: TMemberState, key: Self::Key) -> Self::Value; -} - -/// Provides direct write access to values in a storage [`Map`]. -/// -/// Enables directly storing values in the contract's storage at the address of the given key. -/// -/// # Examples -/// -/// ``` -/// use starknet::ContractAddress; -/// use starknet::storage::{Map, StorageMapWriteAccess, StoragePathEntry}; -/// -/// #[storage] -/// struct Storage { -/// balances: Map, -/// allowances: Map>, -/// } -/// -/// fn write_storage(ref self: ContractState, address: ContractAddress) { -/// // Write to single mapping -/// self.balances.write(address, 100); -/// // Write to nested mapping -/// self.allowances.entry(owner).write(spender, 50); -/// } -/// ``` -pub trait StorageMapWriteAccess { - type Key; - type Value; - fn write(self: TMemberState, key: Self::Key, value: Self::Value); -} - -/// Computes storage paths for accessing [`Map`] entries. -/// -/// The storage path combines the variable's base path with the key's hash to create a unique -/// identifier for the storage slot. This path can then be used for subsequent read or write -/// operations, or advanced further by chaining the `entry` method. -/// -/// # Examples -/// -/// ``` -/// use starknet::ContractAddress; -/// use starknet::storage::{Map, StoragePathEntry}; -/// -/// #[storage] -/// struct Storage { -/// balances: Map, -/// } -/// -/// // Get the storage path for the balance of a specific address -/// let balance_path = self.balances.entry(address); -/// ``` -pub trait StoragePathEntry { - type Key; - type Value; - fn entry(self: C, key: Self::Key) -> StoragePath; -} - -/// A persistent key-value store in contract storage. -/// -/// This type cannot be instantiated as it is marked with `#[phantom]`. This is by design: -/// `Map` is a compile-time type that only exists to provide type information for the compiler. -/// It represents a mapping in storage, but the actual storage operations are handled by the -/// [`StorageMapReadAccess`], [`StorageMapWriteAccess`], and [`StoragePathEntry`] traits. -#[phantom] -pub struct Map {} - -/// A trait for making a map like type support implement the `StoragePathEntry` trait. -trait EntryInfo { - type Key; - type Value; -} - -impl EntryInfoImpl of EntryInfo> { - type Key = K; - type Value = V; -} - -/// Implement `StoragePathEntry` for any `EntryInfo` type if their key implements `Hash`. -impl EntryInfoStoragePathEntry< - T, +EntryInfo, +core::hash::Hash::Key, StoragePathHashState>, -> of StoragePathEntry> { - type Key = EntryInfo::::Key; - type Value = EntryInfo::::Value; - fn entry(self: StoragePath, key: EntryInfo::::Key) -> StoragePath::Value> { - self.update(key) - } -} - -/// Same as `StoragePathEntryMap`, but for `Mutable`, forwards the Mutable wrapper onto the value -/// type. -impl MutableEntryStoragePathEntry< - T, - +MutableTrait, - impl EntryImpl: EntryInfo::InnerType>, - +core::hash::Hash, -> of StoragePathEntry> { - type Key = EntryImpl::Key; - type Value = Mutable; - fn entry(self: StoragePath, key: EntryImpl::Key) -> StoragePath> { - self.update(key) - } -} - -/// Implement `StorageMapReadAccess` trait for any type that implements `StoragePathEntry` and -/// `Store`. -impl StorableEntryReadAccess< - T, - +EntryInfo, - +core::hash::Hash::Key, StoragePathHashState>, - +starknet::Store::Value>, -> of StorageMapReadAccess> { - type Key = EntryInfo::::Key; - type Value = EntryInfo::::Value; - fn read(self: StoragePath, key: EntryInfo::::Key) -> EntryInfo::::Value { - self.entry(key).as_ptr().read() - } -} - -impl StorageAsPathReadForward< - T, - impl PathImpl: StorageAsPath, - impl AccessImpl: StorageMapReadAccess>, - +Drop, - +Drop, -> of StorageMapReadAccess { - type Key = AccessImpl::Key; - type Value = AccessImpl::Value; - #[inline] - fn read(self: T, key: AccessImpl::Key) -> AccessImpl::Value { - self.as_path().read(key) - } -} - -/// Implement `StorageMapReadAccess` trait for any mutable type that implements `StoragePathEntry` -/// and `Store`. -impl MutableStorableEntryReadAccess< - T, - +MutableTrait, - +EntryInfo::InnerType>, - +core::hash::Hash::InnerType>::Key, StoragePathHashState>, - +starknet::Store::InnerType>::Value>, -> of StorageMapReadAccess> { - type Key = EntryInfo::::InnerType>::Key; - type Value = EntryInfo::::InnerType>::Value; - #[inline] - fn read( - self: StoragePath, key: EntryInfo::::InnerType>::Key, - ) -> EntryInfo::::InnerType>::Value { - self.entry(key).as_ptr().read() - } -} - - -/// Implement `StorageMapWriteAccess` trait for any mutable type that implements `StoragePathEntry` -/// and `Store`. -impl MutableStorableEntryWriteAccess< - T, - +MutableTrait, - +EntryInfo::InnerType>, - +core::hash::Hash::InnerType>::Key, StoragePathHashState>, - +starknet::Store::InnerType>::Value>, - +Drop::InnerType>::Value>, -> of StorageMapWriteAccess> { - type Key = EntryInfo::::InnerType>::Key; - type Value = EntryInfo::::InnerType>::Value; - fn write( - self: StoragePath, - key: EntryInfo::::InnerType>::Key, - value: EntryInfo::::InnerType>::Value, - ) { - self.entry(key).as_ptr().write(value) - } -} - -impl StorageAsPathWriteForward< - T, - impl PathImpl: StorageAsPath, - impl AccessImpl: StorageMapWriteAccess>, - +Drop, - +Drop, - +Drop, -> of StorageMapWriteAccess { - type Key = AccessImpl::Key; - type Value = AccessImpl::Value; - fn write(self: T, key: AccessImpl::Key, value: AccessImpl::Value) { - self.as_path().write(key, value) - } -} - -/// Implement `StoragePathEntry` for any type that implements `StoragePath` and `StoragePathEntry`. -impl PathableStorageEntryImpl< - T, - impl PathImpl: StorageAsPath, - impl EntryImpl: StoragePathEntry>, - +Drop, - +Drop, -> of StoragePathEntry { - type Key = EntryImpl::Key; - type Value = EntryImpl::Value; - fn entry(self: T, key: Self::Key) -> StoragePath { - let path = PathImpl::as_path(@self); - EntryImpl::entry(path, key) - } -} - -/// Implementation of `ValidStorageTypeTrait` for `Map`. -/// This ensures that Starknet storage maps (`Map`) are valid storage types, -/// as long as: -/// - The `key` type implements `core::hash::Hash`, which allows it to be used in storage mappings. -/// - The `value` type implements `ValidStorageTypeTrait`, meaning it is itself a valid storage -/// type. -use starknet::storage::ValidStorageTypeTrait; -impl ValidStorageTypeTraitMapImpl< - Key, Value, +core::hash::Hash, +ValidStorageTypeTrait, -> of ValidStorageTypeTrait>; diff --git a/corelib/src/starknet/storage/storage_base.cairo b/corelib/src/starknet/storage/storage_base.cairo deleted file mode 100644 index 63b435114e..0000000000 --- a/corelib/src/starknet/storage/storage_base.cairo +++ /dev/null @@ -1,85 +0,0 @@ -//! Core abstractions for contract storage management. -//! -//! This module provides the types and traits for handling contract storage internally -//! within the Cairo core library. Most developers should not need to implement these traits -//! directly, as they are primarily used by the storage system implementation. -//! -//! If you're writing a regular Starknet contract, you should use the high-level storage -//! traits and types, interacting with the members of the storage struct directly. - -use super::{Mutable, StorageAsPath, StoragePath, StoragePathTrait}; - -/// A struct for holding an address to initialize a storage path with. The members (not direct -/// members, but accessible using `deref`) of a contract state are either `StorageBase` or -/// `FlattenedStorage` instances, with the generic type representing the type of the stored member. -pub struct StorageBase { - pub __base_address__: felt252, -} - -impl StorageBaseDrop of Drop> {} -impl StorageBaseCopy of Copy> {} - -impl StorageBaseAsPath of StorageAsPath> { - type Value = T; - fn as_path(self: @StorageBase) -> StoragePath { - StoragePathTrait::new(self.__base_address__) - } -} - -impl StorageBaseDeref of core::ops::Deref> { - type Target = StoragePath; - fn deref(self: StorageBase) -> Self::Target { - self.as_path() - } -} - -/// A type that represents a flattened storage, i.e. a storage object which does not have any effect -/// on the path taken into consideration when computing the address of the storage object. -pub struct FlattenedStorage {} - -impl FlattenedStorageDrop of Drop> {} -impl FlattenedStorageCopy of Copy> {} - -/// Dereference a flattened storage into the storage object containing the members of the object. -impl FlattenedStorageDeref< - T, impl StorageImpl: StorageTrait, -> of core::ops::Deref> { - type Target = StorageImpl::BaseType; - fn deref(self: FlattenedStorage) -> Self::Target { - self.storage() - } -} - -/// Dereference a mutable flattened storage into the storage object containing a mutable version -/// of the members of the object. -impl MutableFlattenedStorageDeref< - T, impl StorageImpl: StorageTraitMut, -> of core::ops::Deref>> { - type Target = StorageImpl::BaseType; - fn deref(self: FlattenedStorage>) -> Self::Target { - self.storage_mut() - } -} - -/// A trait for creating the struct containing the `StorageBase` or `FlattenedStorage` of all the -/// members of a contract state. -pub trait StorageTrait { - /// The type of the struct containing the `StorageBase` or `FlattenedStorage` of all the members - /// of the type `T`. - type BaseType; - /// Creates a struct containing the `StorageBase` or `FlattenedStorage` of all the members of a - /// contract state. Should be called from the `deref` method of the contract state. - fn storage(self: FlattenedStorage) -> Self::BaseType; -} - -/// A trait for creating the struct containing the mutable `StorageBase` or `FlattenedStorage` of -/// all the members of a contract state. -pub trait StorageTraitMut { - /// The type of the struct containing the mutable `StorageBase` or `FlattenedStorage` of all the - /// members of the type `T`. - type BaseType; - /// Creates a struct containing a mutable version of the `StorageBase` or `FlattenedStorage` of - /// all the members of a contract state. Should be called from the `deref` method of the - /// contract state. - fn storage_mut(self: FlattenedStorage>) -> Self::BaseType; -} diff --git a/corelib/src/starknet/storage/storage_node.cairo b/corelib/src/starknet/storage/storage_node.cairo deleted file mode 100644 index a1a1d1eb58..0000000000 --- a/corelib/src/starknet/storage/storage_node.cairo +++ /dev/null @@ -1,117 +0,0 @@ -//! Storage nodes provide a way to structure contract storage data, reflecting their structure in -//! the storage address computation of their members. They are special structs that can contain any -//! storable type and are marked with the `#[starknet::storage_node]` attribute. -//! -//! # Purpose and Benefits -//! -//! Storage nodes provide a flexible way to structure storage data by allowing non-sequential -//! storage layouts. They allow the creation of storage-only types, that can contain both -//! storage-specific types (like `Map` and `Vec`) and regular types - so long as these types are -//! storable. -//! -//! Storage nodes are particularly valuable when defining structs containing phantom types like -//! `Map` and `Vec`. When a struct is marked with `#[starknet::storage_node]`, it automatically -//! becomes a phantom type. -//! -//! While you can declare any struct as a storage node (even those without phantom types), doing so -//! will make that struct a phantom type. For structs that don't contain phantom types, it's often -//! more appropriate to make them storable using `#[derive(Store)]`. This alternative approach -//! still enables access to individual struct members through `SubPointers` without imposing the -//! phantom type behavior. -//! -//! The storage layout differs significantly between these two approaches: -//! * `#[derive(Store)]`: Members are stored continuously in the same variable space, with a limit -//! of 256 field elements. -//! * Storage node: Each member is stored at a different location. For a storage node member `m` -//! within a storage variable `variable_name`, the path to that member is computed as -//! `h(sn_keccak(variable_name), sn_keccak(m))`, where `h` is the Pedersen hash. -//! -//! # Examples -//! -//! Here's how to define a storage node: -//! -//! ``` -//! #[starknet::storage_node] -//! struct MyStruct { -//! a: felt252, -//! b: Map, -//! } -//! ``` -//! -//! For the struct above, the following storage node struct and impl will be generated: -//! -//! ``` -//! struct MyStructStorageNode { -//! a: PendingStoragePath, -//! b: PendingStoragePath>, -//! } -//! -//! impl MyStructStorageNodeImpl of StorageNode { -//! fn storage_node(self: StoragePath) -> MyStructStorageNode { -//! MyStructStorageNode { -//! a: PendingStoragePathTrait::new(@self, selector!("a")), -//! b: PendingStoragePathTrait::new(@self, selector!("b")), -//! } -//! } -//! } -//! ``` -//! -//! For a type `T` that implements `StorageNode` (e.g. `MyStruct` in the example above), -//! `Deref>` is implemented as simply calling `storage_node`, and thus exposing the -//! members of the storage node (`a` and `b` in the example above). -//! For example, given the following storage: -//! -//! ``` -//! #[storage] -//! struct Storage { -//! my_struct: MyStruct, -//! a: felt252, -//! } -//! -//! We can access the members of the storage node as follows: -//! -//! ``` -//! fn use_storage(self: @ContractState) { -//! let a_value = self.a.read(); -//! let inner_a_value = self.my_struct.a.read(); -//! let b_value = self.my_struct.b.entry(42).read(); -//! } -//! ``` -//! -//! # Flattening Storage Nodes -//! -//! Storage Nodes members can be annotated with `#[flat]` to flatten the storage hierarchy and not -//! use the member name in the computation of the storage address for its fields. -//! -//! ``` -//! #[storage] -//! struct Storage { -//! #[flat] -//! my_struct: MyStruct, -//! a: felt252, -//! } -//! ``` -//! -//! When flattened, the storage node's field name (e.g., `my_struct`) doesn't affect storage address -//! computation. In the example above, both `self.a` and `self.my_struct.a` will point to the same -//! address. Use `#[flat]` with caution as this behavior is rarely intended. -//! -//! # Performance Considerations -//! -//! Storage node members are implemented as `PendingStoragePath` instances, enabling lazy evaluation -//! of storage paths. This means storage addresses are only computed for members that are actually -//! accessed. - -use super::{Mutable, StoragePath}; - -/// A trait that given a storage path of a struct, generates the storage node of this struct. -pub trait StorageNode { - type NodeType; - fn storage_node(self: StoragePath) -> Self::NodeType; -} - -/// A mutable version of `StorageNode`, works the same way, but on `Mutable`. -pub trait StorageNodeMut { - type NodeType; - fn storage_node_mut(self: StoragePath>) -> Self::NodeType; -} diff --git a/corelib/src/starknet/storage/sub_pointers.cairo b/corelib/src/starknet/storage/sub_pointers.cairo deleted file mode 100644 index e75468dd56..0000000000 --- a/corelib/src/starknet/storage/sub_pointers.cairo +++ /dev/null @@ -1,182 +0,0 @@ -use super::{Mutable, StorageAsPointer, StoragePointer, StoragePointer0Offset}; - -/// Similar to storage node, but for structs which are stored sequentially in the storage. In -/// contrast to storage node, the fields of the struct are just at an offset from the base address -/// of the struct. -pub trait SubPointers { - /// The type of the storage pointers, generated for the struct T. - type SubPointersType; - /// Creates a sub pointers struct for the given storage pointer to a struct T. - fn sub_pointers(self: StoragePointer) -> Self::SubPointersType; -} - -/// A mutable version of `SubPointers`, works the same way, but on `Mutable`. -pub trait SubPointersMut { - /// The type of the storage pointers, generated for the struct T. - type SubPointersType; - /// Creates a sub pointers struct for the given storage pointer to a struct T. - fn sub_pointers_mut(self: StoragePointer>) -> Self::SubPointersType; -} - -impl OptionSubPointers of SubPointers> { - type SubPointersType = Option>; - fn sub_pointers(self: StoragePointer>) -> Option> { - let selector_storage_pointer = starknet::storage::StoragePointer::< - felt252, - > { - __storage_pointer_address__: self.__storage_pointer_address__, - __storage_pointer_offset__: self.__storage_pointer_offset__, - }; - let selector = starknet::storage::StoragePointerReadAccess::read(@selector_storage_pointer); - match selector { - 0 => None, - 1 => Some( - starknet::storage::StoragePointer { - __storage_pointer_address__: self.__storage_pointer_address__, - __storage_pointer_offset__: self.__storage_pointer_offset__ + 1, - }, - ), - _ => panic!("Invalid selector value"), - } - } -} - -impl OptionSubPointersMut of SubPointersMut> { - type SubPointersType = Option>>; - fn sub_pointers_mut( - self: StoragePointer>>, - ) -> Option>> { - let selector_storage_pointer = starknet::storage::StoragePointer::< - felt252, - > { - __storage_pointer_address__: self.__storage_pointer_address__, - __storage_pointer_offset__: self.__storage_pointer_offset__, - }; - let selector = starknet::storage::StoragePointerReadAccess::read(@selector_storage_pointer); - match selector { - 0 => None, - 1 => Some( - starknet::storage::StoragePointer { - __storage_pointer_address__: self.__storage_pointer_address__, - __storage_pointer_offset__: self.__storage_pointer_offset__ + 1, - }, - ), - _ => panic!("Invalid selector value"), - } - } -} - -/// A trait for implementing `SubPointers` for types which are not a `StoragePointer`, such as -/// `StorageBase` and `StoragePath`. -pub trait SubPointersForward { - type SubPointersType; - fn sub_pointers(self: T) -> Self::SubPointersType; -} - -/// Implementation of SubPointersForward for `StoragePointer0Offset`. -impl Pointer0OffsetSubPointersForward< - T, impl SubPointersImpl: SubPointers, -> of SubPointersForward> { - type SubPointersType = SubPointersImpl::SubPointersType; - fn sub_pointers(self: StoragePointer0Offset) -> SubPointersImpl::SubPointersType { - self.deref().sub_pointers() - } -} - -/// Implementation of SubPointersForward for types which supports `StorageAsPointer`, i.e. being -/// able to convert to a `StoragePointer0Offset`, and the resulting type should implement -/// `SubPointersForward` (see `Pointer0OffsetSubPointersForward`). -impl SubPointersForwardImpl< - T, - +Drop, - impl AsPointerImpl: StorageAsPointer, - impl PointerForwardImpl: SubPointersForward>, -> of SubPointersForward { - type SubPointersType = PointerForwardImpl::SubPointersType; - fn sub_pointers(self: T) -> Self::SubPointersType { - self.as_ptr().sub_pointers() - } -} - -/// A trait for implementing `SubPointersMut` for types which are not a `StoragePointer`, such as -/// `StorageBase` and `StoragePath`. -pub trait SubPointersMutForward { - type SubPointersType; - fn sub_pointers_mut(self: T) -> Self::SubPointersType; -} - -/// Implementation of SubPointersMutForward for `StoragePointer0Offset`. -impl Pointer0OffsetSubPointersMutForward< - T, impl SubPointersImpl: SubPointersMut, -> of SubPointersMutForward>> { - type SubPointersType = SubPointersImpl::SubPointersType; - fn sub_pointers_mut( - self: StoragePointer0Offset>, - ) -> SubPointersImpl::SubPointersType { - self.deref().sub_pointers_mut() - } -} - -/// Implementation of SubPointersMutForward for types which supports `StorageAsPointer`, i.e. being -/// able to convert to a `StoragePointer0Offset`, and the resulting type should implement -/// `SubPointersMutForward` (see `Pointer0OffsetSubPointersMutForward`). -impl SubPointersMutForwardImpl< - T, - +Drop, - impl AsPointerImpl: StorageAsPointer, - impl PointerForwardImpl: SubPointersMutForward>, -> of SubPointersMutForward { - type SubPointersType = PointerForwardImpl::SubPointersType; - fn sub_pointers_mut(self: T) -> Self::SubPointersType { - self.as_ptr().sub_pointers_mut() - } -} - -/// Implementation of SubPointers for core types. -#[derive(Drop, Copy)] -struct u256SubPointers { - pub low: starknet::storage::StoragePointer, - pub high: starknet::storage::StoragePointer, -} - -pub impl u256SubPointersImpl of starknet::storage::SubPointers { - type SubPointersType = u256SubPointers; - fn sub_pointers(self: starknet::storage::StoragePointer) -> u256SubPointers { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let low_value = starknet::storage::StoragePointer::< - u128, - > { __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset }; - current_offset = current_offset + starknet::Store::::size(); - let high_value = starknet::storage::StoragePointer::< - u128, - > { __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset }; - - u256SubPointers { low: low_value, high: high_value } - } -} - -#[derive(Drop, Copy)] -struct U256SubPointersMut { - pub low: starknet::storage::StoragePointer>, - pub high: starknet::storage::StoragePointer>, -} - -pub impl U256SubPointersImplMut of starknet::storage::SubPointersMut { - type SubPointersType = U256SubPointersMut; - fn sub_pointers_mut( - self: starknet::storage::StoragePointer>, - ) -> U256SubPointersMut { - let base_address = self.__storage_pointer_address__; - let mut current_offset = self.__storage_pointer_offset__; - let low_value = starknet::storage::StoragePointer::< - Mutable, - > { __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset }; - current_offset = current_offset + starknet::Store::::size(); - let high_value = starknet::storage::StoragePointer::< - Mutable, - > { __storage_pointer_address__: base_address, __storage_pointer_offset__: current_offset }; - - U256SubPointersMut { low: low_value, high: high_value } - } -} diff --git a/corelib/src/starknet/storage/vec.cairo b/corelib/src/starknet/storage/vec.cairo deleted file mode 100644 index 317912b467..0000000000 --- a/corelib/src/starknet/storage/vec.cairo +++ /dev/null @@ -1,653 +0,0 @@ -//! Vector-like storage collection for persisting data in contract storage. -//! -//! This module provides a vector-like collection that stores elements in contract storage. -//! Unlike memory arrays, storage vectors persist data onchain, meaning that values can be retrieved -//! even after the end of the current context. -//! -//! # Storage Layout -//! -//! A storage vector consists of two parts: -//! - The vector length stored at the base storage address (`sn_keccak(variable_name)`) -//! - The elements stored at addresses computed as `h(base_address, index)` where: -//! - `h` is the Pedersen hash function -//! - `index` is the element's position in the vector -//! -//! # Interacting with [`Vec`] -//! -//! Storage vectors can be accessed through two sets of traits: -//! -//! 1. Read-only access using `VecTrait`: -//! ``` -//! // Get length -//! let len = self.my_vec.len(); -//! -//! // Read element (panics if out of bounds) -//! let value = self.my_vec.at(0).read(); -//! -//! // Read element (returns Option) -//! let maybe_value: Option = self.my_vec.get(0).map(|ptr| ptr.read()); -//! ``` -//! -//! 2. Mutable access using `MutableVecTrait`: -//! ``` -//! // Append new element using push -//! self.my_vec.push(value); -//! -//! // Allocate space for a new element (useful for nested vectors) -//! let new_slot = self.my_vec.allocate(); -//! -//! // Modify existing element -//! self.my_vec.at(0).write(new_value); -//! ``` -//! -//! # Examples -//! -//! Basic usage: -//! -//! ``` -//! use starknet::storage::{Vec, VecTrait, MutableVecTrait, StoragePointerReadAccess, -//! StoragePointerWriteAccess}; -//! -//! #[storage] -//! struct Storage { -//! numbers: Vec, -//! } -//! -//! fn store_number(ref self: ContractState, number: u256) { -//! // Append new number -//! self.numbers.push(number); -//! -//! // Read first number -//! let first = self.numbers[0].read(); -//! -//! // Get current length -//! let size = self.numbers.len(); -//! } -//! ``` -//! -//! Loading the numbers into a memory array: -//! -//! ``` -//! use starknet::storage::{Vec, VecTrait, StoragePointerReadAccess}; -//! -//! fn to_array(self: @ContractState) -> Array { -//! let mut arr = array![]; -//! -//! let len = self.numbers.len(); -//! for i in 0..len { -//! arr.append(self.numbers[i].read()); -//! } -//! arr -//! } -//! ``` -use core::ops::Range; -use super::{ - IntoIterRange, Mutable, StorageAsPath, StorageAsPointer, StoragePath, - StoragePathMutableConversion, StoragePathTrait, StoragePathUpdateTrait, StoragePointer0Offset, - StoragePointerReadAccess, StoragePointerWriteAccess, -}; - -/// Represents a dynamic array in contract storage. -/// -/// This type is zero-sized and cannot be instantiated. -/// Vectors can only be used in storage contexts and manipulated using the associated `VecTrait` -/// and `MutableVecTrait` traits. -#[phantom] -pub struct Vec {} - -impl VecDrop of Drop> {} -impl VecCopy of Copy> {} - -/// Implement `as_ptr` for `Vec`. -impl VecAsPointer of StorageAsPointer>> { - type Value = u64; - fn as_ptr(self: @StoragePath>) -> StoragePointer0Offset { - StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() } - } -} - -/// Implement `as_ptr` for `Mutable`. -impl MutableVecAsPointer of StorageAsPointer>>> { - type Value = Mutable; - fn as_ptr(self: @StoragePath>>) -> StoragePointer0Offset> { - StoragePointer0Offset { __storage_pointer_address__: (*self).finalize() } - } -} - -/// Provides read-only access to elements in a storage [`Vec`]. -/// -/// This trait enables retrieving elements and checking the vector's length without -/// modifying the underlying storage. -pub trait VecTrait { - type ElementType; - - /// Returns a storage path to the element at the specified index, or `None` if out of bounds. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, VecTrait, StoragePointerReadAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn maybe_number(self: @ContractState, index: u64) -> Option { - /// self.numbers.get(index).map(|ptr| ptr.read()) - /// } - /// ``` - fn get(self: T, index: u64) -> Option>; - - /// Returns a storage path to access the element at the specified index. - /// - /// # Panics - /// - /// Panics if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, VecTrait, StoragePointerReadAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn get_number(self: @ContractState, index: u64) -> u256 { - /// self.numbers.at(index).read() - /// } - /// ``` - fn at(self: T, index: u64) -> StoragePath; - - /// Returns the number of elements in the vector. - /// - /// The length is stored at the vector's base storage address and is automatically - /// updated when elements are appended. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, VecTrait}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn is_empty(self: @ContractState) -> bool { - /// self.numbers.len() == 0 - /// } - /// ``` - fn len(self: T) -> u64; -} - -/// Implement `VecTrait` for `StoragePath>`. -impl VecImpl of VecTrait>> { - type ElementType = T; - - fn get(self: StoragePath>, index: u64) -> Option> { - let vec_len = self.len(); - if index < vec_len { - Some(self.update(index)) - } else { - None - } - } - - fn at(self: StoragePath>, index: u64) -> StoragePath { - assert!(index < self.len(), "Index out of bounds"); - self.update(index) - } - - fn len(self: StoragePath>) -> u64 { - self.as_ptr().read() - } -} - -/// Implement `VecTrait` for any type that implements `StorageAsPath` into a storage path -/// that implements `VecTrait`. -impl PathableVecImpl< - T, - +Drop, - impl PathImpl: StorageAsPath, - impl VecTraitImpl: VecTrait>, -> of VecTrait { - type ElementType = VecTraitImpl::ElementType; - - fn get(self: T, index: u64) -> Option> { - self.as_path().get(index) - } - - fn at(self: T, index: u64) -> StoragePath { - self.as_path().at(index) - } - - fn len(self: T) -> u64 { - self.as_path().len() - } -} - -/// Provides mutable access to elements in a storage [`Vec`]. -/// -/// This trait extends the read functionality with methods to append new elements -/// and modify existing ones. -pub trait MutableVecTrait { - type ElementType; - - /// Returns a mutable storage path to the element at the specified index, or `None` if out of - /// bounds. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait, StoragePointerWriteAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn set_number(ref self: ContractState, index: u64, number: u256) -> bool { - /// if let Some(ptr) = self.numbers.get(index) { - /// ptr.write(number); - /// true - /// } else { - /// false - /// } - /// } - /// ``` - fn get(self: T, index: u64) -> Option>>; - - /// Returns a mutable storage path to the element at the specified index. - /// - /// # Panics - /// - /// Panics if the index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait, StoragePointerWriteAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn set_number(ref self: ContractState, index: u64, number: u256) { - /// self.numbers.at(index).write(number); - /// } - /// ``` - fn at(self: T, index: u64) -> StoragePath>; - - /// Returns the number of elements in the vector. - /// - /// The length is stored at the vector's base storage address and is automatically - /// updated when elements are appended. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn is_empty(self: @ContractState) -> bool { - /// self.numbers.len() == 0 - /// } - /// ``` - fn len(self: T) -> u64; - - /// Returns a mutable storage path to write a new element at the end of the vector. - /// - /// This operation: - /// 1. Increments the vector's length - /// 2. Returns a storage path to write the new element - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait, StoragePointerWriteAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn push_number(ref self: ContractState, number: u256) { - /// self.numbers.append().write(number); - /// } - /// ``` - #[deprecated( - feature: "starknet-storage-deprecation", - note: "Use `starknet::storage::MutableVecTrait::push` or `starknet::storage::MutableVecTrait::allocate` instead.", - )] - fn append(self: T) -> StoragePath> { - Self::allocate(self) - } - - /// Allocates space for a new element at the end of the vector, returning a mutable storage path - /// to write the element. - /// - /// This function is a replacement for the deprecated `append` function, which allowed - /// appending new elements to a vector. - /// Unlike `push`, which gets an object to write to the vector, `allocate` is specifically - /// useful when you need to prepare space for elements of unknown or dynamic size (e.g., - /// appending another vector). - /// - /// # Use Case - /// - /// `allocate` is essential when pushing a vector into another vector, as the size of the - /// nested vector is unknown at compile time. It allows the caller to allocate the required - /// space first, then write the nested vector into the allocated space using `.write()`. - /// - /// This is necessary because pushing directly (e.g., `vec.push(nested_vec)`) is not supported - /// due to `Vec` being only a storage abstraction. - /// - /// # Deprecation Note - /// - /// The `append` function is now deprecated. Use `allocate` to achieve the same functionality - /// with improved clarity and flexibility. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait, StoragePointerWriteAccess}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec>, - /// } - /// - /// fn append_nested_vector(ref self: ContractState, elements: Array) { - /// // Allocate space for the nested vector in the outer vector. - /// let new_vec_storage_path = self.numbers.allocate(); - /// for element in elements { - /// new_vec_storage_path.push(element) - /// } - /// } - /// ``` - fn allocate(self: T) -> StoragePath>; - - /// Pushes a new value onto the vector. - /// - /// This operation: - /// 1. Increments the vector's length. - /// 2. Writes the provided value to the new storage location at the end of the vector. - /// - /// # Note - /// - /// If you need to allocate storage without writing a value (e.g., when appending another - /// vector), consider using [`allocate`] instead. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn push_number(ref self: ContractState, number: u256) { - /// self.numbers.push(number); - /// } - /// ``` - fn push<+Drop, +starknet::Store>( - self: T, value: Self::ElementType, - ); - - /// Pops the last value off the vector. - /// - /// This operation: - /// 1. Retrieves the value stored at the last position in the vector. - /// 2. Decrements the vector's length. - /// 3. Returns the retrieved value or `None` if the vector is empty. - /// - /// # Examples - /// - /// ``` - /// use starknet::storage::{Vec, MutableVecTrait}; - /// - /// #[storage] - /// struct Storage { - /// numbers: Vec, - /// } - /// - /// fn pop_number(ref self: ContractState) -> Option { - /// self.numbers.pop() - /// } - /// ``` - fn pop<+Drop, +starknet::Store>( - self: T, - ) -> Option; -} - -/// Implement `MutableVecTrait` for `StoragePath>>`. -impl MutableVecImpl of MutableVecTrait>>> { - type ElementType = T; - - fn get(self: StoragePath>>, index: u64) -> Option>> { - let vec_len = self.len(); - if index < vec_len { - Some(self.update(index)) - } else { - None - } - } - - fn at(self: StoragePath>>, index: u64) -> StoragePath> { - assert!(index < self.len(), "Index out of bounds"); - self.update(index) - } - - fn len(self: StoragePath>>) -> u64 { - self.as_non_mut().len() - } - - fn allocate(self: StoragePath>>) -> StoragePath> { - let vec_len = self.len(); - self.as_ptr().write(vec_len + 1); - self.update(vec_len) - } - - fn push<+Drop, +starknet::Store>( - self: StoragePath>>, value: Self::ElementType, - ) { - self.allocate().write(value); - } - - fn pop<+Drop, +starknet::Store>( - self: StoragePath>>, - ) -> Option { - let len_ptr = self.as_ptr(); - let vec_len: u64 = len_ptr.read(); - if vec_len == 0 { - return None; - } - let entry: StoragePath> = self.update(vec_len - 1); - let last_element = entry.read(); - // Remove the element's data from the storage. - let entry_ptr = entry.as_ptr(); - starknet::SyscallResultTrait::unwrap_syscall( - starknet::Store::< - Self::ElementType, - >::scrub(0, entry_ptr.__storage_pointer_address__, 0), - ); - len_ptr.write(vec_len - 1); - Some(last_element) - } -} - -/// Implement `MutableVecTrait` for any type that implements StorageAsPath into a storage -/// path that implements MutableVecTrait. -impl PathableMutableVecImpl< - T, - +Drop, - impl PathImpl: StorageAsPath, - impl VecTraitImpl: MutableVecTrait>, -> of MutableVecTrait { - type ElementType = VecTraitImpl::ElementType; - - fn get(self: T, index: u64) -> Option>> { - self.as_path().get(index) - } - - fn at(self: T, index: u64) -> StoragePath> { - self.as_path().at(index) - } - - fn len(self: T) -> u64 { - self.as_path().len() - } - - fn allocate(self: T) -> StoragePath> { - self.as_path().allocate() - } - - fn push<+Drop, +starknet::Store>( - self: T, value: Self::ElementType, - ) { - self.as_path().push(value) - } - - fn pop<+Drop, +starknet::Store>( - self: T, - ) -> Option { - self.as_path().pop() - } -} - -pub impl VecIndexView< - VecT, impl VecImpl: VecTrait, +Copy, -> of core::ops::IndexView { - type Target = StoragePath; - fn index(self: @VecT, index: u64) -> Self::Target { - (*self).at(index) - } -} - -pub impl MutableVecIndexView< - VecT, impl VecImpl: MutableVecTrait, +Copy, -> of core::ops::IndexView { - type Target = StoragePath>; - fn index(self: @VecT, index: u64) -> Self::Target { - (*self).at(index) - } -} - -/// An iterator struct over a `Vec` in storage. -#[derive(Drop)] -pub struct VecIter> { - vec: T, - current_index: IntoIterator::>::IntoIter, -} - -impl VecIterator, +Drop, +Copy> of Iterator> { - type Item = StoragePath; - fn next(ref self: VecIter) -> Option { - self.vec.get(self.current_index.next()?) - } -} - -// Implement `IntoIterRange` for `StoragePath>` -pub impl VecIntoIterRange< - T, impl VecTraitImpl: VecTrait>>, -> of IntoIterRange>> { - type IntoIter = VecIter>, VecTraitImpl>; - #[inline] - fn into_iter_range(self: StoragePath>, range: Range) -> Self::IntoIter { - VecIter { current_index: range.into_iter(), vec: self } - } - #[inline] - fn into_iter_full_range(self: StoragePath>) -> Self::IntoIter { - VecIter { current_index: (0..core::num::traits::Bounded::MAX).into_iter(), vec: self } - } -} - -/// Implement `IntoIterRange` for any type that implements StorageAsPath into a storage path -/// that implements VecTrait. -pub impl PathableVecIntoIterRange< - T, - +Destruct, - impl PathImpl: StorageAsPath, - impl VecTraitImpl: VecTrait>, -> of IntoIterRange { - type IntoIter = VecIter, VecTraitImpl>; - #[inline] - fn into_iter_range(self: T, range: Range) -> Self::IntoIter { - VecIter { current_index: range.into_iter(), vec: self.as_path() } - } - #[inline] - fn into_iter_full_range(self: T) -> Self::IntoIter { - let vec = self.as_path(); - VecIter { current_index: (0..core::num::traits::Bounded::MAX).into_iter(), vec } - } -} - -/// An iterator struct over a `Mutable` in storage. -#[derive(Drop)] -struct MutableVecIter> { - vec: T, - current_index: IntoIterator::>::IntoIter, -} - -impl MutableVecIterator< - T, +Drop, +Copy, impl MutVecTraitImpl: MutableVecTrait, -> of Iterator> { - type Item = StoragePath>; - fn next(ref self: MutableVecIter) -> Option { - self.vec.get(self.current_index.next()?) - } -} - -// Implement `IntoIterRange` for `StoragePath>>` -pub impl MutableVecIntoIterRange< - T, impl MutVecTraitImpl: MutableVecTrait>>>, -> of IntoIterRange>>> { - type IntoIter = MutableVecIter>>, MutVecTraitImpl>; - #[inline] - fn into_iter_range(self: StoragePath>>, range: Range) -> Self::IntoIter { - MutableVecIter { current_index: range.into_iter(), vec: self } - } - #[inline] - fn into_iter_full_range(self: StoragePath>>) -> Self::IntoIter { - MutableVecIter { - current_index: (0..core::num::traits::Bounded::MAX).into_iter(), vec: self, - } - } -} - -/// Implement `IntoIterRange` for any type that implements StorageAsPath into a storage path -/// that implements MutableVecTrait. -pub impl PathableMutableVecIntoIterRange< - T, - +Destruct, - impl PathImpl: StorageAsPath, - impl MutVecTraitImpl: MutableVecTrait>, -> of IntoIterRange { - type IntoIter = MutableVecIter, MutVecTraitImpl>; - #[inline] - fn into_iter_range(self: T, range: Range) -> Self::IntoIter { - MutableVecIter { current_index: range.into_iter(), vec: self.as_path() } - } - #[inline] - fn into_iter_full_range(self: T) -> Self::IntoIter { - let vec = self.as_path(); - MutableVecIter { current_index: (0..core::num::traits::Bounded::MAX).into_iter(), vec } - } -} - -/// Implementation of `ValidStorageTypeTrait` for `Vec`. -/// This ensures that Starknet storage vectors (`Vec`) are valid storage types, -/// as long as the contained type `T` is itself a valid storage type (`ValidStorageTypeTrait`). -/// This allows vectors to be stored in contract storage, provided that their elements -/// conform to the required storage constraints. -use starknet::storage::ValidStorageTypeTrait; -impl ValidStorageTypeVecTrait> of ValidStorageTypeTrait>; diff --git a/corelib/src/starknet/storage_access.cairo b/corelib/src/starknet/storage_access.cairo deleted file mode 100644 index e17f733f5e..0000000000 --- a/corelib/src/starknet/storage_access.cairo +++ /dev/null @@ -1,976 +0,0 @@ -//! Storage access primitives for Starknet contract storage. -//! -//! This module provides abstractions over the system calls for reading from and writing to Starknet -//! contract storage. It includes traits and implementations for storing various data types -//! efficiently. -//! -//! # Storage Architecture -//! -//! * Storage addresses range from `[0, 2^251)` -//! * Base addresses can be combined with offsets, allowing storage of up to 255 values sequentially -//! * Multiple storage domains can be supported, each with its own set of storage space. -//! Currently, only the domain `0` is supported. Values stored in domain `0` are committed to -//! Ethereum as part of the state diffs. -//! -//! # Core Components -//! -//! * [`StorageAddress`]: Represents a specific storage location -//! * [`StorageBaseAddress`]: Base address that can be combined with offsets -//! * [`Store`]: Core trait for types that can be stored in contract storage -//! * [`StorePacking`]: Trait for efficient packing/unpacking of values -//! -//! Generally, you don't need to implement the [`Store`] trait yourself. Most types of the core -//! library, at the exception of collection types, implement the [`Store`] trait - and thus, you can -//! derive the [`Store`] trait for your own types, as long as they don't contain any collections. - -use core::RangeCheck; -use core::array::ArrayTrait; -use core::byte_array::ByteArrayTrait; -use core::option::OptionTrait; -use core::serde::Serde; -use core::traits::{Into, TryInto}; -#[allow(unused_imports)] -use starknet::SyscallResult; -#[allow(unused_imports)] -use starknet::class_hash::{ClassHash, ClassHashIntoFelt252, Felt252TryIntoClassHash}; -#[allow(unused_imports)] -use starknet::contract_address::{ - ContractAddress, ContractAddressIntoFelt252, Felt252TryIntoContractAddress, -}; -#[allow(unused_imports)] -use starknet::syscalls::{storage_read_syscall, storage_write_syscall}; - -/// Represents the address of a storage value in a Starknet contract. -/// The value range of this type is `[0, 2**251)`. -pub extern type StorageAddress; - -impl StorageAddressCopy of Copy; -impl StorageAddressDrop of Drop; - -/// Represents a base storage address that can be combined with offsets. -/// The value range of this type is `[0, 2**251 - 256)`. -pub extern type StorageBaseAddress; - -impl StorageBaseAddressCopy of Copy; -impl StorageBaseAddressDrop of Drop; - -/// Returns a `StorageBaseAddress` given a constant `felt252` value. -/// -/// The value is validated to be in the range `[0, 2**251 - 256)` at compile time. -/// -/// # Examples -/// -/// ``` -/// use starknet::storage_access::storage_base_address_const; -/// -/// let base_address = storage_base_address_const::<0>(); -/// ``` -pub extern fn storage_base_address_const() -> StorageBaseAddress nopanic; - -/// Returns a `StorageBaseAddress` given a `felt252` value. -/// -/// Wraps around the value if it is not in the range `[0, 2**251 - 256)`. -pub extern fn storage_base_address_from_felt252( - addr: felt252, -) -> StorageBaseAddress implicits(RangeCheck) nopanic; - -pub(crate) extern fn storage_address_to_felt252(address: StorageAddress) -> felt252 nopanic; - -/// Sums the base address and the offset to return a storage address. -pub extern fn storage_address_from_base_and_offset( - base: StorageBaseAddress, offset: u8, -) -> StorageAddress nopanic; - -/// Converts a `StorageBaseAddress` into a `StorageAddress`. -/// -/// This should be used through the high-level `Into` trait. -pub extern fn storage_address_from_base(base: StorageBaseAddress) -> StorageAddress nopanic; - -pub(crate) extern fn storage_address_try_from_felt252( - address: felt252, -) -> Option implicits(RangeCheck) nopanic; - -impl Felt252TryIntoStorageAddress of TryInto { - fn try_into(self: felt252) -> Option { - storage_address_try_from_felt252(self) - } -} - -impl StorageAddressIntoFelt252 of Into { - fn into(self: StorageAddress) -> felt252 { - storage_address_to_felt252(self) - } -} - -impl StorageAddressSerde of Serde { - fn serialize(self: @StorageAddress, ref output: Array) { - storage_address_to_felt252(*self).serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Some(storage_address_try_from_felt252(Serde::::deserialize(ref serialized)?)?) - } -} - -impl StorageBaseAddressIntoFelt252 of Into { - fn into(self: StorageBaseAddress) -> felt252 { - storage_address_to_felt252(storage_address_from_base(self)) - } -} - -impl DebugStorageAddress = core::fmt::into_felt252_based::DebugImpl; -impl DebugStorageBaseAddress of core::fmt::Debug { - fn fmt(self: @StorageBaseAddress, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> { - DebugStorageAddress::fmt(@storage_address_from_base(*self), ref f) - } -} - -impl LowerHexStorageAddress = core::fmt::into_felt252_based::LowerHexImpl; -impl LowerHexStorageBaseAddress of core::fmt::LowerHex { - fn fmt(self: @StorageBaseAddress, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> { - LowerHexStorageAddress::fmt(@storage_address_from_base(*self), ref f) - } -} - -/// Trait for types that can be stored in Starknet contract storage. -/// -/// The `Store` trait enables types to be stored in and retrieved from Starknet's contract storage. -/// Cairo implements `Store` for most primitive types. However, collection types (arrays, dicts, -/// etc.) do not implement `Store` directly. Instead, use specialized storage types, such as [`Vec`] -/// or [`Map`]. -/// -/// [`Map`]: starknet::storage::Map -/// [`Vec`]: starknet::storage::Vec -/// -/// # Derivation -/// -/// To make a type storable in contract storage, simply derive the `Store` trait: -/// -/// ``` -/// #[derive(Drop, starknet::Store)] -/// struct Sizes { -/// tiny: u8, // 8 bits -/// small: u32, // 32 bits -/// medium: u64, // 64 bits -/// } -/// ``` -/// -/// This allows the `Size` struct to be stored in a contract's storage. -/// -/// There's no real reason to implement this trait yourself, as it can be trivially derived. -/// For efficiency purposes, consider manually implementing [`StorePacking`] to optimize storage -/// usage. -pub trait Store { - /// Reads a value from storage at the given domain and base address. - /// - /// # Arguments - /// - /// * `address_domain` - The storage domain (currently only 0 is supported) - /// * `base` - The base storage address to read from - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult; - - /// Writes a value to storage at the given domain and base address. - /// - /// # Arguments - /// - /// * `address_domain` - The storage domain (currently only 0 is supported) - /// * `base` - The base storage address to write to - /// * `value` - The value to store - fn write(address_domain: u32, base: StorageBaseAddress, value: T) -> SyscallResult<()>; - - /// Reads a value from storage at a base address plus an offset. - /// - /// # Arguments - /// - /// * `address_domain` - The storage domain (currently only 0 is supported) - /// * `base` - The base storage address - /// * `offset` - The offset from the base address where the value should be read - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult; - - /// Writes a value to storage at a base address plus an offset. - /// - /// # Arguments - /// - /// * `address_domain` - The storage domain (currently only 0 is supported) - /// * `base` - The base storage address - /// * `offset` - The offset from the base address where the value should be written - /// * `value` - The value to store - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: T, - ) -> SyscallResult<()>; - - /// Returns the size in storage for this type. - /// - /// This is bounded to 255, as the offset is a u8. As such, a single type can only take up to - /// 255 slots in storage. - fn size() -> u8; - - /// Clears the storage area by writing zeroes to it. - /// - /// # Arguments - /// - /// * `address_domain` - The storage domain - /// * `base` - The base storage address to start clearing - /// * `offset` - The offset from the base address where clearing should start - /// - /// The operation writes zeroes to storage starting from the specified base address and offset, - /// and continues for the size of the type as determined by the `size()` function. - /// - /// Note: This is a flat operation. It only zeros the storage slots that belong to this value as - /// determined by `size()`. It does not traverse or delete storage that is pointed to by - /// pointers within the value (e.g., ByteArray data stored via pointers). To fully clear such - /// nested data, users should handle clearing on the nested storage components as well. - #[inline] - fn scrub( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult< - (), - > { - let mut result = Result::Ok(()); - let mut offset = offset; - for _ in 0..Self::size() { - if let Result::Err(err) = - storage_write_syscall( - address_domain, storage_address_from_base_and_offset(base, offset), 0, - ) { - result = Result::Err(err); - break; - } - offset += 1; - } - result - } -} - -/// Trait for efficient packing of values into optimized storage representations. -/// -/// This trait enables bit-packing of complex types into simpler storage types to reduce gas costs -/// by minimizing the number of storage slots used. When a type implements `StorePacking`, the -/// compiler automatically uses [`StoreUsingPacking`] to handle storage operations. As such, a type -/// cannot implement both `Store` and `StorePacking`. -/// -/// # Storage Optimization -/// -/// Each storage slot in Starknet is a `felt252`, and storage operations are expensive. By packing -/// multiple values into fewer slots, you can significantly reduce gas costs. For example: -/// - Multiple small integers can be packed into a single `felt252` -/// - Structs with several fields can be compressed into a single storage slot -/// -/// # Implementation Requirements -/// -/// To implement `StorePacking`, ensure that the `PackedT` type implements [`Store`]. The packed -/// representation must preserve all necessary information to allow unpacking back to the original -/// type. Additionally, the `pack` and `unpack` operations must be reversible, meaning that packing -/// followed by unpacking should return the original value. -/// -/// # Example -/// -/// Packing multiple integer fields into a single storage slot: -/// -/// ``` -/// use starknet::storage_access::StorePacking; -/// -/// #[derive(Drop)] -/// struct Sizes { -/// tiny: u8, // 8 bits -/// small: u32, // 32 bits -/// medium: u64, // 64 bits -/// } -/// -/// const TWO_POW_8: u128 = 0x100; -/// const TWO_POW_40: u128 = 0x10000000000; -/// -/// impl SizesStorePacking of StorePacking { -/// fn pack(value: Sizes) -> u128 { -/// value.tiny.into() + -/// (value.small.into() * TWO_POW_8) + -/// (value.medium.into() * TWO_POW_40) -/// } -/// -/// fn unpack(value: u128) -> Sizes { -/// let tiny = value & 0xff; -/// let small = (value / TWO_POW_8) & 0xffffffff; -/// let medium = (value / TWO_POW_40); -/// -/// Sizes { -/// tiny: tiny.try_into().unwrap(), -/// small: small.try_into().unwrap(), -/// medium: medium.try_into().unwrap(), -/// } -/// } -/// } -/// ``` -/// -/// By implementing `StorePacking` for `Sizes`, the `Sizes` will be stored in its packed form, -/// using a single storage slot instead of 3. When retrieved, it will automatically be unpacked back -/// into the original type. -pub trait StorePacking { - /// Packs a value into its optimized storage representation. - fn pack(value: T) -> PackedT; - - /// Unpacks a storage representation back into the original type. - fn unpack(value: PackedT) -> T; -} - -impl StoreUsingPacking< - T, PackedT, impl TPacking: StorePacking, impl PackedTStore: Store, -> of Store { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { - Ok(TPacking::unpack(PackedTStore::read(address_domain, base)?)) - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: T) -> SyscallResult<()> { - PackedTStore::write(address_domain, base, TPacking::pack(value)) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult { - Ok(TPacking::unpack(PackedTStore::read_at_offset(address_domain, base, offset)?)) - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: T, - ) -> SyscallResult<()> { - PackedTStore::write_at_offset(address_domain, base, offset, TPacking::pack(value)) - } - - #[inline] - fn size() -> u8 { - PackedTStore::size() - } -} - -impl StoreFelt252 of Store { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { - storage_read_syscall(address_domain, storage_address_from_base(base)) - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: felt252) -> SyscallResult<()> { - storage_write_syscall(address_domain, storage_address_from_base(base), value) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult { - storage_read_syscall(address_domain, storage_address_from_base_and_offset(base, offset)) - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: felt252, - ) -> SyscallResult<()> { - storage_write_syscall( - address_domain, storage_address_from_base_and_offset(base, offset), value, - ) - } - - #[inline] - fn size() -> u8 { - 1_u8 - } -} - -impl StorePackingBool of StorePacking { - fn pack(value: bool) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> bool { - value != 0 - } -} - -impl StorePackingU8 of StorePacking { - fn pack(value: u8) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> u8 { - value.try_into().expect('StoreU8 - non u8') - } -} - -impl StorePackingI8 of StorePacking { - fn pack(value: i8) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> i8 { - value.try_into().expect('StoreI8 - non i8') - } -} - -impl StorePackingU16 of StorePacking { - fn pack(value: u16) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> u16 { - value.try_into().expect('StoreU16 - non u16') - } -} - -impl StorePackingI16 of StorePacking { - fn pack(value: i16) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> i16 { - value.try_into().expect('StoreI16 - non i16') - } -} - -impl StorePackingU32 of StorePacking { - fn pack(value: u32) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> u32 { - value.try_into().expect('StoreU32 - non u32') - } -} - -impl StorePackingI32 of StorePacking { - fn pack(value: i32) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> i32 { - value.try_into().expect('StoreI32 - non i32') - } -} - -impl StorePackingU64 of StorePacking { - fn pack(value: u64) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> u64 { - value.try_into().expect('StoreU64 - non u64') - } -} - -impl StorePackingI64 of StorePacking { - fn pack(value: i64) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> i64 { - value.try_into().expect('StoreI64 - non i64') - } -} - -impl StorePackingU128 of StorePacking { - fn pack(value: u128) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> u128 { - value.try_into().expect('StoreU128 - non u128') - } -} - -impl StorePackingI128 of StorePacking { - fn pack(value: i128) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> i128 { - value.try_into().expect('StoreI128 - non i128') - } -} - -impl StorePackingU256 of StorePacking { - fn pack(value: u256) -> (u128, u128) { - (value.low, value.high) - } - - #[inline] - fn unpack(value: (u128, u128)) -> u256 { - let (low, high) = value; - u256 { low, high } - } -} - -impl StorePackingBytes31 of StorePacking { - fn pack(value: bytes31) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> bytes31 { - value.try_into().expect('StoreBytes31 - non bytes31') - } -} - -impl StorePackingNonZero>> of StorePacking, T> { - fn pack(value: NonZero) -> T { - value.into() - } - - #[inline] - fn unpack(value: T) -> NonZero { - value.try_into().expect('StoreNonZero - zero value') - } -} - -impl StorePackingStorageAddress of StorePacking { - fn pack(value: StorageAddress) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> StorageAddress { - value.try_into().expect('Non StorageAddress') - } -} - -impl StorePackingContractAddress of StorePacking { - fn pack(value: ContractAddress) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> ContractAddress { - value.try_into().expect('Non ContractAddress') - } -} - -impl StorePackingClassHash of StorePacking { - fn pack(value: ClassHash) -> felt252 { - value.into() - } - - #[inline] - fn unpack(value: felt252) -> ClassHash { - value.try_into().expect('Non ClassHash') - } -} - -/// Store implementation for a tuple of size 0. -impl TupleSize0Store of Store<()> { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult<()> { - Ok(()) - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: ()) -> SyscallResult<()> { - Ok(()) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult<()> { - Ok(()) - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: (), - ) -> SyscallResult<()> { - Ok(()) - } - - #[inline] - fn size() -> u8 { - 0 - } -} - -/// Store packing for tuples of size 1. -impl StorePackingTuple1 of StorePacking<(T,), T> { - fn pack(value: (T,)) -> T { - let (value,) = value; - value - } - - fn unpack(value: T) -> (T,) { - (value,) - } -} - -/// Store packing for small fixed sized arrays. -impl StorePackingFixedSizedArray0 of StorePacking<[T; 0], ()> { - fn pack(value: [T; 0]) -> () { - let [] = value; - () - } - - #[inline] - fn unpack(value: ()) -> [T; 0] { - [] - } -} - -/// Store packing for fixed sized arrays of size 1. -impl StorePackingFixedSizedArray1 of StorePacking<[T; 1], T> { - fn pack(value: [T; 1]) -> T { - let [value] = value; - value - } - - fn unpack(value: T) -> [T; 1] { - [value] - } -} - -/// Store implementation for a tuple of size 2 and more. -impl TupleNextStore< - T, - impl TH: core::metaprogramming::TupleSplit, - impl HeadStore: Store, - impl RestStore: Store, - +Drop, - +Drop, - // The following bound is to allow the recursion to be more efficient at size 1. - +core::metaprogramming::TupleSplit, -> of Store { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { - let head = HeadStore::read(address_domain, base)?; - let rest = RestStore::read_at_offset(address_domain, base, HeadStore::size())?; - Ok(TH::reconstruct(head, rest)) - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: T) -> SyscallResult<()> { - let (head, rest) = TH::split_head(value); - HeadStore::write(address_domain, base, head)?; - RestStore::write_at_offset(address_domain, base, HeadStore::size(), rest) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult { - let head = HeadStore::read_at_offset(address_domain, base, offset)?; - let rest = RestStore::read_at_offset(address_domain, base, offset + HeadStore::size())?; - Ok(TH::reconstruct(head, rest)) - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: T, - ) -> SyscallResult<()> { - let (head, rest) = TH::split_head(value); - HeadStore::write_at_offset(address_domain, base, offset, head)?; - RestStore::write_at_offset(address_domain, base, offset + HeadStore::size(), rest) - } - - #[inline] - fn size() -> u8 { - HeadStore::size() + RestStore::size() - } -} - -const RESULT_OK_INDICATOR: felt252 = 0; -const RESULT_ERR_INDICATOR: felt252 = 1; - -impl ResultStore, +Store, +Drop, +Drop> of Store> { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult> { - let idx = Store::::read(address_domain, base)?; - if idx == RESULT_OK_INDICATOR { - starknet::SyscallResult::Ok(Ok(Store::read_at_offset(address_domain, base, 1_u8)?)) - } else if idx == RESULT_ERR_INDICATOR { - starknet::SyscallResult::Ok(Err(Store::read_at_offset(address_domain, base, 1_u8)?)) - } else { - starknet::SyscallResult::Err(array!['Incorrect index:']) - } - } - - #[inline] - fn write( - address_domain: u32, base: StorageBaseAddress, value: Result, - ) -> SyscallResult<()> { - match value { - Ok(x) => { - Store::write(address_domain, base, RESULT_OK_INDICATOR)?; - Store::write_at_offset(address_domain, base, 1_u8, x)?; - }, - Err(x) => { - Store::write(address_domain, base, RESULT_ERR_INDICATOR)?; - Store::write_at_offset(address_domain, base, 1_u8, x)?; - }, - } - starknet::SyscallResult::Ok(()) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult> { - let idx = Store::::read_at_offset(address_domain, base, offset)?; - if idx == RESULT_OK_INDICATOR { - starknet::SyscallResult::Ok( - Ok(Store::read_at_offset(address_domain, base, offset + 1_u8)?), - ) - } else if idx == RESULT_ERR_INDICATOR { - starknet::SyscallResult::Ok( - Err(Store::read_at_offset(address_domain, base, offset + 1_u8)?), - ) - } else { - starknet::SyscallResult::Err(array!['Incorrect index:']) - } - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: Result, - ) -> SyscallResult<()> { - match value { - Ok(x) => { - Store::write_at_offset(address_domain, base, offset, RESULT_OK_INDICATOR)?; - Store::write_at_offset(address_domain, base, offset + 1_u8, x)?; - }, - Err(x) => { - Store::write_at_offset(address_domain, base, offset, RESULT_ERR_INDICATOR)?; - Store::write_at_offset(address_domain, base, offset + 1_u8, x)?; - }, - } - starknet::SyscallResult::Ok(()) - } - - #[inline] - fn size() -> u8 { - 1 + core::cmp::max(Store::::size(), Store::::size()) - } -} - -const OPTION_NONE_INDICATOR: felt252 = 0; -const OPTION_SOME_INDICATOR: felt252 = 1; - -impl OptionStore, +Drop> of Store> { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult> { - let idx = Store::::read(address_domain, base)?; - if idx == OPTION_SOME_INDICATOR { - starknet::SyscallResult::Ok(Some(Store::read_at_offset(address_domain, base, 1_u8)?)) - } else if idx == OPTION_NONE_INDICATOR { - starknet::SyscallResult::Ok(None) - } else { - starknet::SyscallResult::Err(array!['Incorrect index:']) - } - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: Option) -> SyscallResult<()> { - match value { - Some(x) => { - Store::write(address_domain, base, OPTION_SOME_INDICATOR)?; - Store::write_at_offset(address_domain, base, 1_u8, x)?; - }, - None(_) => { Store::write(address_domain, base, OPTION_NONE_INDICATOR)?; }, - } - starknet::SyscallResult::Ok(()) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult> { - let idx = Store::::read_at_offset(address_domain, base, offset)?; - if idx == OPTION_SOME_INDICATOR { - starknet::SyscallResult::Ok( - Some(Store::read_at_offset(address_domain, base, offset + 1_u8)?), - ) - } else if idx == OPTION_NONE_INDICATOR { - starknet::SyscallResult::Ok(None) - } else { - starknet::SyscallResult::Err(array!['Incorrect index:']) - } - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: Option, - ) -> SyscallResult<()> { - match value { - Some(x) => { - Store::write_at_offset(address_domain, base, offset, OPTION_SOME_INDICATOR)?; - Store::write_at_offset(address_domain, base, offset + 1_u8, x)?; - }, - None(_x) => { - Store::write_at_offset(address_domain, base, offset, OPTION_NONE_INDICATOR)?; - }, - } - starknet::SyscallResult::Ok(()) - } - - #[inline] - fn size() -> u8 { - 1 + Store::::size() - } -} - -/// Store for a `ByteArray`. -/// -/// The layout of a `ByteArray` in storage is as follows: -/// * Only the length in bytes is stored in the original address where the byte array is logically -/// stored. -/// * The actual data is stored in chunks of 256 `bytes31`s in another place in storage -/// determined by the hash of: -/// - The address storing the length of the array. -/// - The chunk index. -/// - The short string `ByteArray`. -impl ByteArrayStore of Store { - #[inline] - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { - inner_read_byte_array(address_domain, storage_address_from_base(base)) - } - - #[inline] - fn write(address_domain: u32, base: StorageBaseAddress, value: ByteArray) -> SyscallResult<()> { - inner_write_byte_array(address_domain, storage_address_from_base(base), value) - } - - #[inline] - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult { - inner_read_byte_array(address_domain, storage_address_from_base_and_offset(base, offset)) - } - - #[inline] - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: ByteArray, - ) -> SyscallResult<()> { - inner_write_byte_array( - address_domain, storage_address_from_base_and_offset(base, offset), value, - ) - } - - #[inline] - fn size() -> u8 { - 1 - } -} - -/// Returns a pointer to the `chunk`'th chunk of the byte array at `address`. -/// The pointer is the `Poseidon` hash of: -/// * `address` - The address of the ByteArray (where the length is stored). -/// * `chunk` - The index of the chunk. -/// * The short string `ByteArray` is used as the capacity argument of the sponge construction -/// (domain separation). -fn inner_byte_array_pointer(address: StorageAddress, chunk: felt252) -> StorageBaseAddress { - let (r, _, _) = core::poseidon::hades_permutation(address.into(), chunk, 'ByteArray'_felt252); - storage_base_address_from_felt252(r) -} - -/// Reads a byte array from storage from domain `address_domain` and address `address`. -/// The length of the byte array is read from `address` at domain `address_domain`. -/// For more info read the documentation of `ByteArrayStore`. -fn inner_read_byte_array(address_domain: u32, address: StorageAddress) -> SyscallResult { - let Some::(len) = starknet::syscalls::storage_read_syscall(address_domain, address)? - .try_into() else { - return Err(array!['Invalid ByteArray length']); - }; - let (mut remaining_full_words, pending_word_len) = crate::byte_array::len_parts(len); - let mut chunk = 0; - let mut chunk_base = inner_byte_array_pointer(address, chunk); - let mut index_in_chunk = 0_u8; - let mut result: ByteArray = Default::default(); - loop { - if remaining_full_words == 0 { - break; - } - let value = starknet::syscalls::storage_read_syscall( - address_domain, storage_address_from_base_and_offset(chunk_base, index_in_chunk), - )?; - let Some::(value) = value.try_into() else { - return Err(array!['Invalid value']); - }; - result.data.append(value); - remaining_full_words -= 1; - index_in_chunk = match core::integer::u8_overflowing_add(index_in_chunk, 1) { - Ok(x) => x, - Err(_) => { - // After reading 256 `bytes31`s `index_in_chunk` will overflow and we move to the - // next chunk. - chunk += 1; - chunk_base = inner_byte_array_pointer(address, chunk); - 0 - }, - }; - } - if pending_word_len != 0 { - let pending_word = starknet::syscalls::storage_read_syscall( - address_domain, storage_address_from_base_and_offset(chunk_base, index_in_chunk), - )?; - if !core::byte_array::is_valid_pending_word(pending_word, pending_word_len) { - return Err(array!['Invalid pending word']); - } - result.pending_word = pending_word; - result.pending_word_len = pending_word_len; - } - Ok(result) -} - -/// Writes a byte array to storage to domain `address_domain` and address `address`. -/// The length of the byte array is written to `address` at domain `address_domain`. -/// For more info read the documentation of `ByteArrayStore`. -fn inner_write_byte_array( - address_domain: u32, address: StorageAddress, value: ByteArray, -) -> SyscallResult<()> { - let len = value.len(); - starknet::syscalls::storage_write_syscall(address_domain, address, len.into())?; - let mut full_words = value.data.span(); - let mut chunk = 0; - let mut chunk_base = inner_byte_array_pointer(address, chunk); - let mut index_in_chunk = 0_u8; - loop { - let curr_value = match full_words.pop_front() { - Some(x) => x, - None => { break Ok(()); }, - }; - match starknet::syscalls::storage_write_syscall( - address_domain, - storage_address_from_base_and_offset(chunk_base, index_in_chunk), - (*curr_value).into(), - ) { - Ok(_) => {}, - Err(err) => { break Err(err); }, - } - index_in_chunk = match core::integer::u8_overflowing_add(index_in_chunk, 1) { - Ok(x) => x, - Err(_) => { - // After writing 256 `byte31`s `index_in_chunk` will overflow and we move to the - // next chunk. - chunk += 1; - chunk_base = inner_byte_array_pointer(address, chunk); - 0 - }, - }; - }?; - if value.pending_word_len != 0 { - starknet::syscalls::storage_write_syscall( - address_domain, - storage_address_from_base_and_offset(chunk_base, index_in_chunk), - value.pending_word, - )?; - } - Ok(()) -} diff --git a/corelib/src/starknet/syscalls.cairo b/corelib/src/starknet/syscalls.cairo deleted file mode 100644 index e686a1730e..0000000000 --- a/corelib/src/starknet/syscalls.cairo +++ /dev/null @@ -1,242 +0,0 @@ -//! Utilities for interacting with the Starknet OS. -//! -//! Writing smart contracts requires various associated operations, such as calling another contract -//! or accessing the contract’s storage, that standalone programs do not require. Cairo supports -//! these operations by using system calls. -//! -//! System calls enable a contract to require services from the Starknet OS. You can use system -//! calls in a function to get information that depends on the broader state of Starknet, such as -//! the current timestamp or the address of the caller, but also to modify the state of Starknet by, -//! for example, storing values in a contract's storage or deploying new contracts. - -use core::gas::GasBuiltin; -use starknet::SyscallResult; -use starknet::class_hash::ClassHash; -use starknet::contract_address::ContractAddress; -use starknet::storage_access::StorageAddress; - -/// Calls a given contract. -/// -/// # Arguments -/// -/// * `address` - The address of the called contract. -/// * `entry_point_selector` - A selector for a function within that contract. -/// * `calldata` - Call arguments. -pub extern fn call_contract_syscall( - address: ContractAddress, entry_point_selector: felt252, calldata: Span, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -/// Deploys a new instance of a previously declared class. -/// -/// # Arguments -/// -/// * `class_hash` - The class hash of the contract to be deployed. -/// * `contract_address_salt` - The salt, an arbitrary value provided by the deployer, used in the -/// computation of the contract's address. -/// * `calldata` - Call arguments for the constructor. -/// * `deploy_from_zero` - Deploy the contract from the zero address. -/// -/// # Returns -/// -/// * The address of the deployed contract. -/// * The serialized return value of the constructor. -pub extern fn deploy_syscall( - class_hash: ClassHash, - contract_address_salt: felt252, - calldata: Span, - deploy_from_zero: bool, -) -> SyscallResult<(ContractAddress, Span)> implicits(GasBuiltin, System) nopanic; - -/// Emits an event. -/// -/// # Arguments -/// -/// * `keys` - The keys of the event. -/// * `data` - The data of the event. -pub extern fn emit_event_syscall( - keys: Span, data: Span, -) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic; - -/// Returns the hash of the block with the given number. -/// -/// # Arguments -/// -/// * `block_number` - The number of the queried block. -/// -/// # Returns -/// -/// * The hash of the block with the given number. -pub extern fn get_block_hash_syscall( - block_number: u64, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Gets information about the currently executing block and the transactions within it. -/// For a complete description of this information, see [`Execution information`]. -/// When an account’s `__validate__`, `__validate_deploy__`, or `__validate_declare__` function -/// -/// calls `get_execution_info`, the return values for `block_timestamp` and `block_number` are -/// modified as follows: -/// * `block_timestamp` returns the hour, rounded down to the nearest hour. -/// * `block_number` returns the block number, rounded down to the nearest multiple of 100. -/// -/// [`Execution information`]: starknet::info::ExecutionInfo -/// -/// # Returns -/// -/// * A struct that contains information about the currently executing function, transaction, and -/// block. -pub extern fn get_execution_info_syscall() -> SyscallResult< - Box, -> implicits(GasBuiltin, System) nopanic; - -/// Gets information about the current execution, version 2. -/// This syscall should not be called directly. Instead, use -/// `starknet::info::get_execution_info`. -/// -/// # Returns -/// -/// * A box containing the current V2 execution information. -pub extern fn get_execution_info_v2_syscall() -> SyscallResult< - Box, -> implicits(GasBuiltin, System) nopanic; - -/// Gets information about the current execution, version 3. -/// This syscall should not be called directly. Instead, use -/// `starknet::info::get_execution_info`. -/// -/// # Returns -/// -/// * A box containing the current V3 execution information. -pub extern fn get_execution_info_v3_syscall() -> SyscallResult< - Box, -> implicits(GasBuiltin, System) nopanic; - -/// Calls the requested function in any previously declared class. -/// -/// # Arguments -/// -/// * `class_hash` - The hash of the class to be used. -/// * `function_selector` - A selector for a function within that class. -/// * `calldata` - Call arguments. -pub extern fn library_call_syscall( - class_hash: ClassHash, function_selector: felt252, calldata: Span, -) -> SyscallResult> implicits(GasBuiltin, System) nopanic; - -// TODO(Ilya): Decide if we limit the type of `to_address`. -/// Sends a message to L1. -/// -/// # Arguments -/// -/// * `to_address` - The recipient's L1 address. -/// * `payload` - The content of the message. -pub extern fn send_message_to_l1_syscall( - to_address: felt252, payload: Span, -) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic; - -/// Gets the value of a key in the storage of the calling contract. -/// -/// # Arguments -/// -/// * `address_domain` - The domain of the address. Only `address_domain` 0 is currently supported, -/// in the future it will enable access to address spaces with different data availability -/// guarantees. -/// * `address` - The address of the storage key to read. -pub extern fn storage_read_syscall( - address_domain: u32, address: StorageAddress, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Sets the value of a key in the storage of the calling contract. -/// -/// # Arguments -/// -/// * `address_domain` - The domain of the address. Only `address_domain` 0 is currently supported, -/// in the future it will enable access to address spaces with different data availability -/// guarantees. -/// * `address` - The address of the storage key to write. -/// * `value` - The value to write to the key. -pub extern fn storage_write_syscall( - address_domain: u32, address: StorageAddress, value: felt252, -) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic; - -/// Replaces the class hash of the current contract, instantly modifying its entrypoints. -/// -/// The new class becomes effective only after the current function call completes. -/// The remaining code in the current function will continue executing from the old class. -/// The new class will be used: -/// * In subsequent transactions -/// * If the contract is called via `call_contract` syscall later in the same transaction -/// -/// # Arguments -/// -/// * `class_hash` - The class hash that should replace the current one. -pub extern fn replace_class_syscall( - class_hash: ClassHash, -) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic; - -/// Gets the class hash of the contract at the given address. -/// -/// # Arguments -/// -/// * `contract_address` - The address of the deployed contract. -/// -/// # Returns -/// -/// * The class hash of the contract's originating code. -pub extern fn get_class_hash_at_syscall( - contract_address: ContractAddress, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Computes the keccak of the input. -/// -/// * The input must be a multiple of 1088 bits (== 17 u64 words) -/// * The input must be pre-padded following the Keccak padding rule (pad10*1): -/// 1. Add a '1' bit -/// 2. Add zero or more '0' bits -/// 3. Add a final '1' bit -/// The total length after padding must be a multiple of 1088 bits -/// -/// # Arguments -/// -/// * `input` - Array of 64-bit words (little endian) to be hashed. -/// -/// # Returns -/// -/// * The keccak hash as a little-endian u256 -pub extern fn keccak_syscall( - input: Span, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Computes the next SHA-256 state of the input with the given state. -/// -/// # Arguments -/// -/// * `state` - The current SHA-256 state. -/// * `input` - The input provided to compute the next SHA-256 state. -/// -/// # Returns -/// -/// * The next SHA-256 state of the input with the given state. -/// -/// The system call does not add any padding and the input needs to be a multiple of 512 bits -/// (== 16 u32 word). -pub extern fn sha256_process_block_syscall( - state: core::sha256::Sha256StateHandle, input: Box<[u32; 16]>, -) -> SyscallResult implicits(GasBuiltin, System) nopanic; - -/// Invokes the given entry point as a v0 meta transaction. -/// -/// * The signature is replaced with the given signature. -/// * The caller is the OS (address 0). -/// * The transaction version is replaced by 0. -/// * The transaction hash is replaced by the corresponding version-0 transaction hash. -/// -/// The changes apply to the called contract and the inner contracts it calls. -/// -/// NOTE: This syscall should only be used to allow support for old version-0 bound accounts, -/// and should not be used for other purposes. -pub extern fn meta_tx_v0_syscall( - address: ContractAddress, - entry_point_selector: felt252, - calldata: Span, - signature: Span, -) -> starknet::SyscallResult> implicits(GasBuiltin, System) nopanic; diff --git a/corelib/src/starknet/testing.cairo b/corelib/src/starknet/testing.cairo deleted file mode 100644 index 86815ddf02..0000000000 --- a/corelib/src/starknet/testing.cairo +++ /dev/null @@ -1,268 +0,0 @@ -//! Testing utilities for Starknet contracts. -//! -//! This module provides functions for testing Starknet contracts. The functions -//! allow manipulation of blockchain state and storage variables during tests, as well as -//! inspection of emitted events and messages. -//! -//! Note: The functions in this module can only be used with the `cairo-test` testing framework. -//! If you are using Starknet Foundry, refer to its -//! [documentation](https://foundry-rs.github.io/starknet-foundry/appendix/cheatcodes.html). - -#[allow(unused_imports)] -use core::array::{ArrayTrait, SpanTrait}; -use core::traits::Into; -use starknet::ContractAddress; - -/// A general cheatcode function used to simplify implementation of Starknet testing functions. -/// -/// This is the base function used by testing utilities to interact with the test -/// environment. External users can implement custom cheatcodes by injecting a custom -/// `CairoHintProcessor` in the runner. -/// -/// # Arguments -/// -/// `selector` - The cheatcode identifier. -/// `input` - Input parameters for the cheatcode. -/// -/// # Returns -/// -/// * A span containing the cheatcode's output -pub extern fn cheatcode( - input: Span, -) -> Span implicits() nopanic; - -/// Sets the block number to the provided value. -/// -/// # Arguments -/// -/// `block_number` - The block number to set. -/// -/// After a call to `set_block_number`, `starknet::get_execution_info().block_info.block_number` -/// will return the set value. -pub fn set_block_number(block_number: u64) { - cheatcode::<'set_block_number'>([block_number.into()].span()); -} - -/// Sets the caller address to the provided value. -/// -/// # Arguments -/// -/// `address` - The caller address to set. -/// -/// After a call to `set_caller_address`, `starknet::get_execution_info().caller_address` will -/// return the set value. -pub fn set_caller_address(address: ContractAddress) { - cheatcode::<'set_caller_address'>([address.into()].span()); -} - -/// Sets the contract address to the provided value. -/// -/// # Arguments -/// -/// `address` - The contract address to set. -/// -/// After a call to `set_contract_address`, `starknet::get_execution_info().contract_address` will -/// return the set value. -pub fn set_contract_address(address: ContractAddress) { - cheatcode::<'set_contract_address'>([address.into()].span()); -} - -/// Sets the sequencer address to the provided value. -/// -/// # Arguments -/// -/// `address` - The sequencer address to set. -/// -/// After a call to `set_sequencer_address`, -/// `starknet::get_execution_info().block_info.sequencer_address` will return the set value. -pub fn set_sequencer_address(address: ContractAddress) { - cheatcode::<'set_sequencer_address'>([address.into()].span()); -} - -/// Sets the block timestamp to the provided value. -/// -/// # Arguments -/// -/// `block_timestamp` - The block timestamp to set. -/// -/// After a call to `set_block_timestamp`, -/// `starknet::get_execution_info().block_info.block_timestamp` will return the set value. -pub fn set_block_timestamp(block_timestamp: u64) { - cheatcode::<'set_block_timestamp'>([block_timestamp.into()].span()); -} - -/// Sets the version to the provided value. -/// -/// # Arguments -/// -/// `version` - The version to set. -/// -/// After a call to `set_version`, `starknet::get_execution_info().tx_info.version` will return the -/// set value. -pub fn set_version(version: felt252) { - cheatcode::<'set_version'>([version].span()); -} - -/// Sets the account contract address. -/// -/// # Arguments -/// -/// `address` - The account contract to set. -/// -/// After a call to `set_account_contract_address`, -/// `starknet::get_execution_info().tx_info.account_contract_address` will return the set value. -pub fn set_account_contract_address(address: ContractAddress) { - cheatcode::<'set_account_contract_address'>([address.into()].span()); -} - -/// Sets the transaction max fee. -/// -/// # Arguments -/// -/// `fee` - The max fee to set. -/// -/// After a call to `set_max_fee`, `starknet::get_execution_info().tx_info.max_fee` will return the -/// set value. -pub fn set_max_fee(fee: u128) { - cheatcode::<'set_max_fee'>([fee.into()].span()); -} - -/// Sets the transaction hash. -/// -/// # Arguments -/// -/// `hash` - The transaction hash to set. -/// -/// After a call to `set_transaction_hash`, -/// `starknet::get_execution_info().tx_info.transaction_hash` will return the set value. -pub fn set_transaction_hash(hash: felt252) { - cheatcode::<'set_transaction_hash'>([hash].span()); -} - -/// Set the transaction chain id. -/// -/// # Arguments -/// -/// `chain_id` - The chain id to set. -/// -/// After a call to `set_chain_id`, `starknet::get_execution_info().tx_info.chain_id` will return -/// the set value. -pub fn set_chain_id(chain_id: felt252) { - cheatcode::<'set_chain_id'>([chain_id].span()); -} - -/// Set the transaction nonce. -/// -/// # Arguments -/// -/// `nonce` - The nonce to set. -/// -/// After a call to `set_nonce`, `starknet::get_execution_info().tx_info.nonce` will return the set -/// value. -pub fn set_nonce(nonce: felt252) { - cheatcode::<'set_nonce'>([nonce].span()); -} - -/// Set the transaction signature. -/// -/// # Arguments -/// -/// `signature` - The signature to set. -/// -/// After a call to `set_signature`, `starknet::get_execution_info().tx_info.signature` will return -/// the set value. -pub fn set_signature(signature: Span) { - cheatcode::<'set_signature'>(signature); -} - -/// Set the hash for a block. -/// -/// # Arguments -/// -/// `block_number` - The targeted block number. -/// `value` - The block hash to set. -/// -/// After a call to `set_block_hash`, `starknet::syscalls::get_block_hash_syscall` for the -/// block_number will return the set value. -/// Unset blocks values call would fail. -pub fn set_block_hash(block_number: u64, value: felt252) { - cheatcode::<'set_block_hash'>([block_number.into(), value].span()); -} - -/// Pop the earliest unpopped logged event for the contract. -/// -/// # Arguments -/// -/// `address` - The contract address from which to pop an event. -/// -/// The value is returned as a tuple of two spans, the first for the keys and the second for the -/// data. -/// May be called multiple times to pop multiple events. -/// If called until `None` is returned, all events have been popped. -pub fn pop_log_raw(address: ContractAddress) -> Option<(Span, Span)> { - let mut log = cheatcode::<'pop_log'>([address.into()].span()); - Some((Serde::deserialize(ref log)?, Serde::deserialize(ref log)?)) -} - -/// Pop the earliest unpopped logged event for the contract as the requested type. -/// -/// # Arguments -/// -/// `address` - The contract address from which to pop an event. -/// -/// Should be used when the type of the event is known. Type of the event should be the event -/// defined within the contract. -/// Useful for testing the contract's event emission. -/// May be called multiple times to pop multiple events. -/// If called until `None` is returned, all events have been popped. -/// -/// # Examples -/// -/// ``` -/// #[starknet::contract] -/// mod contract { -/// #[event] -/// #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] -/// pub enum Event { -/// Event1: felt252, -/// Event2: u128, -/// } -/// ... -/// } -/// -/// #[test] -/// fn test_event() { -/// let contract_address = somehow_get_contract_address(); -/// call_code_causing_events(contract_address); -/// assert_eq!( -/// starknet::testing::pop_log(contract_address), Some(contract::Event::Event1(42)) -/// ); -/// assert_eq!( -/// starknet::testing::pop_log(contract_address), Some(contract::Event::Event2(41)) -/// ); -/// assert_eq!( -/// starknet::testing::pop_log(contract_address), Some(contract::Event::Event1(40)) -/// ); -/// assert_eq!(starknet::testing::pop_log_raw(contract_address), None); -/// } -/// ``` -pub fn pop_log>(address: ContractAddress) -> Option { - let (mut keys, mut data) = pop_log_raw(address)?; - starknet::Event::deserialize(ref keys, ref data) -} - -// TODO(Ilya): Decide if we limit the type of `to_address`. -/// Pop the earliest unpopped l2 to l1 message for the contract. -/// -/// # Arguments -/// -/// `address` - The contract address from which to pop a l2-L1 message. -/// -/// The returned value is a tuple of the l1 address the message was sent to as a `felt252`, and the -/// message data as a span. -/// May be called multiple times to pop multiple messages. -/// Useful for testing the contract's l2 to l1 message emission. -pub fn pop_l2_to_l1_message(address: ContractAddress) -> Option<(felt252, Span)> { - let mut l2_to_l1_message = cheatcode::<'pop_l2_to_l1_message'>([address.into()].span()); - Some((Serde::deserialize(ref l2_to_l1_message)?, Serde::deserialize(ref l2_to_l1_message)?)) -} diff --git a/corelib/src/string.cairo b/corelib/src/string.cairo deleted file mode 100644 index 7368771d2b..0000000000 --- a/corelib/src/string.cairo +++ /dev/null @@ -1 +0,0 @@ -pub trait StringLiteral; diff --git a/corelib/src/test.cairo b/corelib/src/test.cairo deleted file mode 100644 index 0389c1e656..0000000000 --- a/corelib/src/test.cairo +++ /dev/null @@ -1,53 +0,0 @@ -mod array_test; -mod bool_test; -mod box_test; -mod byte_array_test; -mod bytes31_test; -mod circuit_test; -mod clone_test; -mod cmp_test; -mod coupon_test; -mod deref_test; -mod dict_test; -mod ec_test; -mod felt_test; -mod fmt_test; -mod gas_reserve_test; -mod hash_test; -mod integer_test; -mod iter_test; -mod keccak_test; -mod let_else_test; -mod math_test; -mod nullable_test; -mod num_test; -mod option_test; -mod plugins_test; -mod print_test; -mod qm31_test; -mod range_test; -mod result_test; -mod secp256k1_test; -mod secp256r1_test; -mod sha256_test; -mod test_utils; -mod testing_test; -mod to_byte_array_test; - -/// Tests for language features, without mixing implementations within the corelib. -mod language_features { - mod block_level_items_test; - mod box_test; - mod closure_test; - mod const_folding_test; - mod const_test; - mod early_return_test; - mod for_test; - mod glob_use_test; - mod macro_test; - mod match_test; - mod panics_test; - mod path_attr_test; - mod trait_test; - mod while_test; -} diff --git a/corelib/src/test/array_test.cairo b/corelib/src/test/array_test.cairo deleted file mode 100644 index 36163b7d35..0000000000 --- a/corelib/src/test/array_test.cairo +++ /dev/null @@ -1,286 +0,0 @@ -use crate::iter::Extend; -use crate::test::test_utils::assert_eq; - -#[test] -fn test_array() { - let arr = array![10, 11, 12]; - assert_eq(arr[0], @10, 'array[0] != 10'); - assert_eq(arr[1], @11, 'array[1] != 11'); - assert_eq(arr[2], @12, 'array[2] != 12'); -} - -#[test] -#[should_panic] -fn test_array_out_of_bound_1() { - let arr = array![10, 11, 12]; - arr[3]; -} - -#[test] -#[should_panic] -fn test_array_out_of_bound_2() { - let arr = array![10, 11, 12]; - arr[11]; -} - -#[test] -fn test_array_clone() { - let felt252_snap_array: @Array = @array![10, 11, 12]; - let felt252_snap_array_clone = felt252_snap_array.clone(); - assert_eq(@felt252_snap_array_clone.len(), @3, 'array len != 3'); - assert_eq(felt252_snap_array_clone[0], @10, 'array[0] != 10'); - assert_eq(felt252_snap_array_clone[1], @11, 'array[1] != 11'); - assert_eq(felt252_snap_array_clone[2], @12, 'array[2] != 12'); -} - -#[test] -fn test_span() { - let mut span = array![10, 11, 12].span(); - assert_eq(@span.len(), @3, 'Unexpected span length.'); - assert_eq(span.get(0).unwrap().unbox(), @10, 'Unexpected element'); - assert_eq(span.pop_front().unwrap(), @10, 'Unexpected element'); - assert_eq(@span.len(), @2, 'Unexpected span length.'); - assert_eq(span[1], @12, 'Unexpected element'); - assert_eq(span.pop_back().unwrap(), @12, 'Unexpected element'); - assert_eq(@span.len(), @1, 'Unexpected span length.'); -} - -#[test] -fn test_slice() { - let span = [10, 11, 12].span(); - assert_eq!(span.slice(0, 3), span); - assert_eq!(span.slice(0, 2), [10, 11].span()); - assert_eq!(span.slice(0, 1), [10].span()); - assert!(span.slice(0, 0).is_empty()); - assert_eq!(span.slice(1, 2), [11, 12].span()); - assert_eq!(span.slice(1, 1), [11].span()); - assert!(span.slice(1, 0).is_empty()); -} - -#[test] -#[should_panic] -fn test_slice_out_of_bound_1() { - [10, 11, 12].span().slice(3, 1); -} - -#[test] -#[should_panic] -fn test_slice_out_of_bound_2() { - [10, 11, 12].span().slice(0, 4); -} - -#[test] -fn test_equality() { - let arr1 = array![]; - let arr2 = array![10, 11, 12]; - let arr3 = array![10, 11, 13]; - let arr4 = array![10, 11]; - let arr5 = array![10, 11, 12, 13]; - - assert(arr1 == arr1, 'arr1 != arr1'); - assert(arr2 == arr2, 'arr2 != arr2'); - assert(arr3 == arr3, 'arr3 != arr3'); - assert(arr4 == arr4, 'arr4 != arr4'); - assert(arr5 == arr5, 'arr5 != arr5'); - - assert(arr1 != arr2, 'arr1 == arr2'); - assert(arr1 != arr3, 'arr1 == arr3'); - assert(arr1 != arr4, 'arr1 == arr4'); - assert(arr1 != arr5, 'arr1 == arr5'); - assert(arr2 != arr3, 'arr2 == arr3'); - assert(arr2 != arr4, 'arr2 == arr4'); - assert(arr2 != arr5, 'arr2 == arr5'); - assert(arr3 != arr4, 'arr3 == arr4'); - assert(arr3 != arr5, 'arr3 == arr5'); - assert(arr4 != arr5, 'arr4 == arr5'); -} - -#[test] -fn test_append() { - let mut arr = array![10, 11, 12]; - arr.append(13); - assert(arr.len() == 4, 'Unexpected length'); - assert_eq(arr[3], @13, 'Unexpected element'); -} - -#[test] -fn test_append_span() { - let mut arr = array![10, 11, 12]; - arr.append_span(arr.span()); - assert(arr.len() == 6, 'Unexpected length'); - assert_eq(arr[3], @10, 'Unexpected element'); - assert_eq(arr[4], @11, 'Unexpected element'); - assert_eq(arr[5], @12, 'Unexpected element'); -} - -#[test] -fn test_felt252_span_from_tuple() { - let span: Span = [10, 20, 30].span(); - assert!(*span[0] == 10); - assert!(*span[1] == 20); - assert!(*span[2] == 30); -} - -#[test] -fn test_tuple_span_from_tuple() { - let span: Span<(felt252, felt252, felt252)> = [(10, 20, 30), (40, 50, 60), (70, 80, 90)].span(); - assert!(*span[0] == (10, 20, 30)); - assert!(*span[1] == (40, 50, 60)); - assert!(*span[2] == (70, 80, 90)); -} - -#[test] -fn test_fixed_size_array() { - let arr = [10, 11, 12]; - let [x, y, z] = arr; - assert_eq!(x, 10); - assert_eq!(y, 11); - assert_eq!(z, 12); -} - -fn consume(_arr: [felt252; N]) {} - -#[test] -fn test_fixed_size_array_copy() { - let arr = [10, 11, 12]; - consume(arr); - consume(arr); -} - -/// Helper for tests removing the box wrapping a fixed sized array wrapped by an option. -fn debox(value: Option<@Box<[T; SIZE]>>) -> Option<@[T; SIZE]> { - Some(value?.as_snapshot().unbox()) -} - -#[test] -fn test_span_into_fixed_size_array() { - assert!(debox::([10, 11, 12].span().try_into()).is_none()); - assert!(debox::([10, 11, 12].span().try_into()) == Some(@[10, 11, 12])); - assert!(debox::([10, 11, 12].span().try_into()).is_none()); - assert!(debox::([10, 11, 12].span().try_into()).is_none()); - assert!(debox::([10, 11, 12].span().try_into()) == Some(@[10, 11, 12])); - assert!(debox::([10, 11, 12].span().try_into()).is_none()); - assert!(debox::([].span().try_into()).is_none()); - assert!(debox::([].span().try_into()) == Some(@[])); -} - -#[test] -fn test_span_multi_pop() { - let mut span = array![10, 11, 12, 13].span(); - assert!(span.multi_pop_front::<5>().is_none()); - assert!(debox(span.multi_pop_front::<4>()) == Some(@[10, 11, 12, 13])); - let mut span = array![10, 11, 12, 13].span(); - assert!(debox(span.multi_pop_front::<3>()) == Some(@[10, 11, 12])); - let mut span = array![10, 11, 12, 13].span(); - assert!(span.multi_pop_back::<5>().is_none()); - assert!(debox(span.multi_pop_back::<4>()) == Some(@[10, 11, 12, 13])); - let mut span = array![10, 11, 12, 13].span(); - assert!(debox(span.multi_pop_back::<3>()) == Some(@[11, 12, 13])); -} - -#[test] -fn test_span_iterator() { - let mut iter = array![10, 11, 12, 13_felt252].span().into_iter(); - let mut i = 10; - while let Some(value) = iter.next() { - assert_eq!(value, @i); - i += 1; - } -} - -#[test] -fn test_array_iterator() { - let mut iter = array![10, 11, 12, 13].into_iter(); - let mut i = 10; - while let Some(value) = iter.next() { - assert_eq!(value, i); - i += 1; - } -} - -#[test] -fn test_snapshot_fixed_size_array_iterator() { - let mut iter = (@[10_usize, 11, 12, 13]).into_iter(); - assert_eq!(iter.next(), Some(@10)); - assert_eq!(iter.next(), Some(@11)); - assert_eq!(iter.next(), Some(@12)); - assert_eq!(iter.next(), Some(@13)); - assert!(iter.next().is_none()); -} - -#[test] -fn test_empty_snapshot_fixed_size_array_iterator() { - let mut input: [usize; 0] = []; - let mut iter = (@input).into_iter(); - assert!(iter.next().is_none()); -} - -#[test] -fn test_snapshot_array_into_iter() { - let mut iter = (@array![1, 2, 3, 4, 5]).into_iter(); - assert_eq!(iter.next(), Some(@1)); - assert_eq!(iter.next(), Some(@2)); - assert_eq!(iter.next(), Some(@3)); - assert_eq!(iter.next(), Some(@4)); - assert_eq!(iter.next(), Some(@5)); - assert!(iter.next().is_none()); -} - -#[test] -fn test_snapshot_span_into_iter() { - let mut iter = (@(array![1, 2, 3, 4, 5].span())).into_iter(); - assert_eq!(iter.next(), Some(@1)); - assert_eq!(iter.next(), Some(@2)); - assert_eq!(iter.next(), Some(@3)); - assert_eq!(iter.next(), Some(@4)); - assert_eq!(iter.next(), Some(@5)); - assert!(iter.next().is_none()); -} - -#[test] -fn test_array_from_iterator() { - assert_eq!(FromIterator::from_iter(0..5_u32), array![0, 1, 2, 3, 4]); -} - -#[test] -fn test_array_from_collect() { - assert_eq!((0..5_u32).into_iter().collect(), array![0, 1, 2, 3, 4]); -} - -#[test] -fn test_array_extend() { - let mut arr = array![1_u32, 2, 3]; - arr.extend(4..6_u32); - assert_eq!(arr, array![1, 2, 3, 4, 5]); -} - -#[test] -fn test_array_into_span() { - assert_eq!(array![1, 2, 3].span(), array![1, 2, 3].into()) -} - -#[test] -fn test_span_into_array() { - assert_eq!(array![1, 2, 3], array![1, 2, 3].span().into()); -} - -#[test] -fn test_array_snap_into_span() { - assert_eq!(array![1, 2, 3].span(), (@array![1, 2, 3]).into()); -} - -#[test] -fn test_span_into_array_snap() { - assert_eq!(@array![1, 2, 3], array![1, 2, 3].span().into()); -} -#[test] -fn nested_for_loop() { - let mat = array![array![1, 2], array![3, 4], array![5, 6]]; - let mut result = 0; - for arr in mat { - for i in arr { - result += i; - } - } - assert_eq!(result, 21); -} diff --git a/corelib/src/test/bool_test.cairo b/corelib/src/test/bool_test.cairo deleted file mode 100644 index 85d08bb92a..0000000000 --- a/corelib/src/test/bool_test.cairo +++ /dev/null @@ -1,29 +0,0 @@ -use crate::test::test_utils::{assert_eq, assert_ne}; - -#[test] -fn test_bool_operators() { - assert_eq(@true, @true, 't != t'); - assert_eq(@false, @false, 'f != f'); - assert_eq(@!true, @false, '!t != f'); - assert_eq(@!false, @true, '!f != t'); - assert_ne(@true, @false, 't == f'); - assert_ne(@false, @true, 'f == t'); - assert(!(false & false), '!(f & f)'); - assert(!(true & false), '!(t & f)'); - assert(!(false & true), '!(f & t)'); - assert(true & true, 't & t'); - assert(!(false | false), '!(f | f)'); - assert(true | false, 't | f'); - assert(false | true, 'f | t'); - assert(true | true, 't | t'); - assert(!(false ^ false), '!(f ^ f)'); - assert(true ^ false, 't ^ f'); - assert(false ^ true, 'f ^ t'); - assert(!(true ^ true), '!(t ^ t)'); -} - -#[test] -fn test_bool_conversion() { - assert_eq(@false.into(), @0, 'f.into() != 0'); - assert_eq(@true.into(), @1, 't.into() != 1'); -} diff --git a/corelib/src/test/box_test.cairo b/corelib/src/test/box_test.cairo deleted file mode 100644 index d496a3f3ad..0000000000 --- a/corelib/src/test/box_test.cairo +++ /dev/null @@ -1,22 +0,0 @@ -use crate::test::test_utils::assert_eq; - -#[test] -fn test_box_unbox_felt252s() { - let x = 10; - let boxed_x = BoxTrait::new(x); - let y = 11; - let boxed_y = BoxTrait::new(y); - assert_eq(@boxed_x.unbox(), @10, 'x != 10'); - assert_eq(@boxed_y.unbox(), @11, 'y != 11'); -} - -// Test objects of size>1. -#[test] -fn test_box_unbox_u256() { - let x = u256 { low: 1, high: 0 }; - let boxed_x = BoxTrait::new(x); - let y = u256 { low: 1, high: 1 }; - let boxed_y = BoxTrait::new(y); - assert_eq(@boxed_x.unbox(), @x, 'unbox u256 x'); - assert_eq(@boxed_y.unbox(), @y, 'unbox u256 y'); -} diff --git a/corelib/src/test/byte_array_test.cairo b/corelib/src/test/byte_array_test.cairo deleted file mode 100644 index 74c0232326..0000000000 --- a/corelib/src/test/byte_array_test.cairo +++ /dev/null @@ -1,913 +0,0 @@ -#[feature("byte-span")] -use crate::byte_array::{ByteSpan, ByteSpanTrait, ToByteSpanTrait}; -use crate::num::traits::Bounded; -use crate::test::test_utils::{assert_eq, assert_ne}; - -#[test] -fn test_append_byte() { - let mut ba = Default::default(); - for c in '0'_u8..='Z'_u8 { - ba.append_byte(c); - } - assert_eq!(ba, "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"); -} - -#[test] -fn test_append_word() { - let mut ba = Default::default(); - - ba.append_word('ABCDEFGHIJKLMNOPQRSTUVWXYZabcd', 30); - assert_eq!(ba, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd", "appending word in single bytes31"); - - ba.append_word('efg', 3); - assert_eq!(ba, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg", "append word overflowing pending word"); - - ba.append_word('hi', 2); - assert_eq!(ba, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi", "append word extending new pending word"); - - // Length is 0, so nothing is actually appended. - ba.append_word('jk', 0); - assert_eq!(ba, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi", "append 0 length error"); - - ba.append_word('ABCDEFGHIJKLMNOPQRSTUVWXYZa', 27); - assert_eq!( - ba, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiABCDEFGHIJKLMNOPQRSTUVWXYZa", - "append word filling pending to capacity", - ); - - ba.append_word('b', 1); - assert_eq!( - ba, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiABCDEFGHIJKLMNOPQRSTUVWXYZab", - "append word starting new pending word", - ); -} - -#[test] -fn test_append() { - let mut ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - - ba_32.append(@ba_32); - - assert_eq!( - ba_32, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$", - "append bytearray across new pending word", - ); -} - -// Same as test_append, but with `+=` instead of `append`. -#[test] -fn test_add_eq() { - let mut ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - - ba_32 += ba_32.clone(); - - assert_eq!( - ba_32, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$", - "add-eq bytearray across new pending word", - ); -} - -// Same as test_append and test add_eq, but with `concat`. -#[test] -fn test_concat() { - let mut ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - - let ba = ByteArrayTrait::concat(@ba_32, @ba_32); - - assert_eq!( - ba, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$", - "add-eq bytearray across new pending word", - ); -} - -// Same as test_concat, but with `+` instead of `concat`. -#[test] -fn test_add() { - let mut ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - - let ba_32 = ba_32.clone() + ba_32; - - assert_eq!( - ba_32, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$", - "add-eq bytearray across new pending word", - ); -} - -// Test concat/append, first byte array empty. -#[test] -fn test_concat_first_empty() { - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - let ba_concat = ByteArrayTrait::concat(@Default::default(), @ba_32); - assert_eq!(ba_concat, ba_32, "Error concat empty ba"); -} - -// Test concat/append, second byte array empty. -#[test] -fn test_concat_second_empty() { - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - let ba_concat = ByteArrayTrait::concat(@ba_32, @Default::default()); - assert_eq!(ba_concat, ba_32, "Error concat empty ba"); -} - -// Test concat/append, first byte array pending word is empty. -#[test] -fn test_concat_first_pending_0() { - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - - let ba_concat = ByteArrayTrait::concat(@ba_31, @ba_32); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdeABCDEFGHIJKLMNOPQRSTUVWXYZabcde$", - "Error concat with overflow into pending word", - ); -} - -// Test concat/append, second byte array pending word is empty. -#[test] -fn test_concat_second_pending_0() { - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - - let ba_concat = ByteArrayTrait::concat(@ba_32, @ba_31); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcde", - "Error concat with overflow into pending word", - ); -} - -// Test concat/append, split index of the words of the second byte array is 16. -#[test] -fn test_concat_split_index_16() { - let ba_16: ByteArray = "ABCDEFGHIJKLMNO$"; - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - - let ba_concat = ByteArrayTrait::concat(@ba_16, @ba_32); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNO$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef", - "Error concat with split index 16", - ); -} - -// Test concat/append, split index of the words of the second byte array is < 16, specifically 1. -#[test] -fn test_concat_split_index_lt_16() { - let ba_1: ByteArray = "$"; - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - - let ba_concat = ByteArrayTrait::concat(@ba_1, @ba_32); - - assert_eq!( - ba_concat, "$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef", "Error concat with split index < 16", - ); -} - -// Test concat/append, split index of the words of the second byte array is > 16, specifically 30. -#[test] -fn test_concat_split_index_gt_16() { - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabc$"; - let ba_33: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"; - - let ba_concat = ByteArrayTrait::concat(@ba_30, @ba_33); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabc$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg", - "Error concat with split index > 16", - ); -} - -// Sum of the lengths of the pending words of both byte arrays is 31 (a full word). -#[test] -fn test_concat_pending_sum_up_to_full() { - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$"; - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"; - - let ba_concat = ByteArrayTrait::concat(@ba_32, @ba_30); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde$ABCDEFGHIJKLMNOPQRSTUVWXYZabcd", - "Error concat with pending word sum up to full", - ); -} - -// Sum of the lengths of the pending words of both byte arrays is 31+16. -// That is, the pending words aggregate to a full word, and the last split index is 16. -#[test] -fn test_concat_pending_sum_up_to_more_than_word_16() { - let ba_17: ByteArray = "ABCDEFGHIJKLMNOP$"; - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"; - - let ba_concat = ByteArrayTrait::concat(@ba_17, @ba_30); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOP$ABCDEFGHIJKLMNOPQRSTUVWXYZabcd", - "Error pending word overflowed concat with split index 16", - ); -} - -// Sum of the lengths of the pending words of both byte arrays is in [32, 31+15]. -// That is, the pending words aggregate to a full word, and the last split index is <16. -#[test] -fn test_concat_pending_sum_up_to_more_than_word_lt16() { - let ba_2: ByteArray = "A$"; - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"; - - let ba_concat = ByteArrayTrait::concat(@ba_2, @ba_30); - - assert_eq!( - ba_concat, - "A$ABCDEFGHIJKLMNOPQRSTUVWXYZabcd", - "Error pending word overflowed concat with split index < 16", - ); -} - -// Sum of the lengths of the pending words of both byte arrays is >31+15 -// That is, the pending words aggregate to a full word, and the last split index is >16. -#[test] -fn test_concat_pending_sum_up_to_more_than_word_gt16() { - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabc$"; - - let ba_concat = ByteArrayTrait::concat(@ba_30, @ba_30); - - assert_eq!( - ba_concat, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabc$ABCDEFGHIJKLMNOPQRSTUVWXYZabc$", - "Error pending word overflowed concat with split index > 16", - ); -} - -#[test] -fn test_len() { - let ba: ByteArray = Default::default(); - assert_eq!(ba.len(), 0, "wrong ByteArray len"); - - let mut ba_33: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef$"; - let mut ba = ba_33; - assert_eq!(ba.len(), 33, "wrong ByteArray len"); - - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabc$"; - ba.append(@ba_30); - assert_eq!(ba.len(), 63, "wrong ByteArray len"); -} - -#[test] -fn test_at_empty() { - let ba: ByteArray = Default::default(); - - assert_eq!(ba.at(0), None, "index 0 is not out of bounds"); - assert_eq!(ba.at(1), None, "index 1 is not out of bounds"); - assert_eq!(ba.at(30), None, "index 30 is not out of bounds"); - assert_eq!(ba.at(31), None, "index 31 is not out of bounds"); -} - -#[test] -fn test_at() { - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let mut ba = ba_31.clone(); - ba.append(@ba_31); - - let ba_17: ByteArray = "ABCDEFGHIJKLMNOPQ"; - ba.append(@ba_17); - - assert_eq!(ba.at(0), Some('A'), "wrong byte at index 0"); - assert_eq!(ba.at(1), Some('B'), "wrong byte at index 1"); - assert_eq!(ba.at(2), Some('C'), "wrong byte at index 2"); - assert_eq!(ba.at(14), Some('O'), "wrong byte at index 14"); - assert_eq!(ba.at(15), Some('P'), "wrong byte at index 15"); - assert_eq!(ba.at(16), Some('Q'), "wrong byte at index 16"); - assert_eq!(ba.at(17), Some('R'), "wrong byte at index 17"); - assert_eq!(ba.at(29), Some('d'), "wrong byte at index 29"); - assert_eq!(ba.at(30), Some('e'), "wrong byte at index 30"); - assert_eq!(ba.at(31), Some('A'), "wrong byte at index 31"); - assert_eq!(ba.at(32), Some('B'), "wrong byte at index 32"); - assert_eq!(ba.at(61), Some('e'), "wrong byte at index 61"); - assert_eq!(ba.at(62), Some('A'), "wrong byte at index 62"); - assert_eq!(ba.at(63), Some('B'), "wrong byte at index 63"); - assert_eq!(ba.at(76), Some('O'), "wrong byte at index 76"); - assert_eq!(ba.at(77), Some('P'), "wrong byte at index 77"); - assert_eq!(ba.at(78), Some('Q'), "wrong byte at index 78"); - assert_eq!(ba.at(79), None, "index 79 is not out of bounds"); -} - -// Same as the previous test, but with [] instead of .at() (and without the out-of-bounds case). -#[test] -fn test_index_view() { - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let mut ba = ba_31.clone(); - ba.append(@ba_31); - - let ba_17: ByteArray = "ABCDEFGHIJKLMNOPQ"; - ba.append(@ba_17); - - assert_eq!(ba[0], 'A', "wrong byte at index 0"); - assert_eq!(ba[1], 'B', "wrong byte at index 1"); - assert_eq!(ba[2], 'C', "wrong byte at index 2"); - assert_eq!(ba[14], 'O', "wrong byte at index 14"); - assert_eq!(ba[15], 'P', "wrong byte at index 15"); - assert_eq!(ba[16], 'Q', "wrong byte at index 16"); - assert_eq!(ba[17], 'R', "wrong byte at index 17"); - assert_eq!(ba[29], 'd', "wrong byte at index 29"); - assert_eq!(ba[30], 'e', "wrong byte at index 30"); - assert_eq!(ba[31], 'A', "wrong byte at index 31"); - assert_eq!(ba[32], 'B', "wrong byte at index 32"); - assert_eq!(ba[61], 'e', "wrong byte at index 61"); - assert_eq!(ba[62], 'A', "wrong byte at index 62"); - assert_eq!(ba[63], 'B', "wrong byte at index 63"); - assert_eq!(ba[76], 'O', "wrong byte at index 76"); - assert_eq!(ba[77], 'P', "wrong byte at index 77"); - assert_eq!(ba[78], 'Q', "wrong byte at index 78"); -} - -// Test panic with [] in case of out-of-bounds -#[test] -#[should_panic(expected: ('Index out of bounds',))] -fn test_index_view_out_of_bounds() { - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let mut ba = ba_31.clone(); - ba.append(@ba_31); - let ba_17: ByteArray = "ABCDEFGHIJKLMNOPQ"; - ba.append(@ba_17); - - let _x = ba[79]; -} - -#[test] -fn test_string_literals() { - let _ba: ByteArray = "12345"; // len < 16 - let _ba: ByteArray = "1234567890123456"; // len == 16 - let _ba: ByteArray = "123456789012345678"; // 16 < len < 31 - let _ba: ByteArray = "1234567890123456789012345678901"; // len == 31 - let _ba: ByteArray = "123456789012345678901234567890123"; // 31 < len < 47 - let _ba: ByteArray = "12345678901234567890123456789012345678901234567"; // len == 47 - let _ba: ByteArray = "123456789012345678901234567890123456789012345678"; // len > 47 -} - -#[test] -fn test_equality() { - let byte_array: ByteArray = "a"; - assert_eq!(byte_array, "a", "Same strings are not equal"); - assert_ne!(byte_array, "b", "Different strings are equal"); - - let mut ba1: ByteArray = "01"; - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - ba1.append(@ba_31); - let ba_33: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"; - let ba2 = ba_33; - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - let ba3 = ba_32.clone(); - let mut ba4 = ba_32; - ba4.append(@"a"); - - assert_eq!(ba1, ba1, "Same ByteArrays are not equal"); - assert_eq!(ba2, ba2, "Same ByteArrays are not equal"); - assert_eq!(ba3, ba3, "Same ByteArrays are not equal"); - assert_eq!(ba4, ba4, "Same ByteArrays are not equal"); - - // Different data - assert_ne!(ba1, ba2, "Different ByteArrays are equal"); - - // Different pending word length - assert_ne!(ba2, ba3, "Different ByteArrays are equal"); - - // Different pending word - assert_ne!(ba2, ba4, "Different ByteArrays are equal"); -} - -#[test] -fn test_reverse() { - // Arrays of length < 16 - let ba: ByteArray = "abc"; - let ba_rev: ByteArray = "cba"; - let palindrome: ByteArray = "rotator"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of length 16 - let ba: ByteArray = "my length is 16."; - let ba_rev: ByteArray = ".61 si htgnel ym"; - let palindrome: ByteArray = "nolemon nomelon"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of 16 < length < 31 - let ba: ByteArray = "I am a medium byte array"; - let ba_rev: ByteArray = "yarra etyb muidem a ma I"; - let palindrome: ByteArray = "nolemon nomelon"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of length 31 - let ba: ByteArray = "I didn't find a good palindrome"; - let ba_rev: ByteArray = "emordnilap doog a dnif t'ndid I"; - let palindrome: ByteArray = "kayak level rotator level kayak"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of 31 < length < 47 (31+16) - let ba: ByteArray = "This time I did find a good palindrome!"; - let ba_rev: ByteArray = "!emordnilap doog a dnif did I emit sihT"; - let palindrome: ByteArray = "noitneverpropagatesifisetagaporprevention"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of length 47 (31+16) - let ba: ByteArray = "I have found a palindrome, exactly 47 in length"; - let ba_rev: ByteArray = "htgnel ni 74 yltcaxe ,emordnilap a dnuof evah I"; - let palindrome: ByteArray = "onacloverifaliveeruptsavastpureevilafirevolcano"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); - - // Arrays of length > 47 (31+16) - let ba: ByteArray = "This palindrome is not as good, but at least it's long enough"; - let ba_rev: ByteArray = "hguone gnol s'ti tsael ta tub ,doog sa ton si emordnilap sihT"; - let palindrome: ByteArray = "docnoteidissentafastneverpreventsafatnessidietoncod"; - assert_ne!(ba, ba.rev(), "ba == ba.rev()"); - assert_ne!(ba_rev, ba_rev.rev(), "ba_rev == ba_rev.rev()"); - assert_eq!(ba, ba_rev.rev(), "ba != ba_rev.rev()"); - assert_eq!(palindrome, palindrome.rev(), "palindrome is not a palindrome"); -} - -#[test] -fn test_serde() { - let mut serialized = array![]; - let ba: ByteArray = ""; - ba.serialize(ref serialized); - assert_eq!(serialized.span(), [0, 0, 0].span()); - - let mut serialized = array![]; - let ba: ByteArray = "hello"; - ba.serialize(ref serialized); - assert_eq!( - serialized.span(), - [0, // data len - 0x68656c6c6f, // pending_word - 5 // pending_word_len - ].span(), - ); - - let mut serialized = array![]; - let ba: ByteArray = "Long string, more than 31 characters."; - ba.serialize(ref serialized); - assert_eq!( - serialized.span(), - [ - 1, // data len - 0x4c6f6e6720737472696e672c206d6f7265207468616e203331206368617261, // data - 0x63746572732e, // pending_word - 6 // pending_word_len - ] - .span(), - ); -} - -#[test] -fn test_into_iterator() { - let ba: ByteArray = "hello"; - let mut iter = ba.into_iter(); - assert_eq!(iter.next(), Some('h')); - assert_eq!(iter.next(), Some('e')); - assert_eq!(iter.next(), Some('l')); - assert_eq!(iter.next(), Some('l')); - assert_eq!(iter.next(), Some('o')); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_from_iterator() { - assert_eq!(FromIterator::::from_iter(array!['h'_u8, 'e', 'l', 'l', 'o']), "hello"); -} - -#[test] -fn test_from_collect() { - let ba: ByteArray = array!['h', 'e', 'l', 'l', 'o'].into_iter().collect(); - assert_eq!(ba, "hello"); -} - -#[test] -fn test_span_len() { - // TODO(giladchase): add short string test here once supported cast into span. - let ba: ByteArray = "A"; - assert_eq!(ba.span().len(), 1); - assert!(!ba.span().is_empty()); - - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - assert_eq!(ba_31.span().len(), 31); - assert!(!ba_31.span().is_empty()); - - let empty_ba: ByteArray = ""; - assert_eq!(empty_ba.span().len(), 0); - assert!(empty_ba.span().is_empty()); - assert_eq!(ba_31.span()[0..0], empty_ba.span()); - - // First word in the array, second in last word. - let two_byte31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"; - let single_span = two_byte31.span()[1..=32]; - assert_eq!(single_span.len(), 32, "len error with start offset"); - assert!(!single_span.is_empty()); - - // First word in the array, second in the array, third in remainder. - let three_bytes31: ByteArray = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$"; // 64 chars. - let three_span = three_bytes31.span().get(1..64); - assert_eq!(three_span.map(|s| s.len()), Some(63), "len error with size-3 bytearray"); - assert_eq!(three_span.map(|s| s.is_empty()), Some(false)); -} - -#[test] -fn test_span_slice_is_empty() { - let ba: ByteArray = "hello"; - let span = ba.span(); - let is_empty = |span: ByteSpan| span.is_empty(); - - let empty = span[2..2]; - assert_eq!(empty.len(), 0); - assert!(empty.is_empty()); - assert_eq!(empty.to_byte_array(), ""); - - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - assert_eq!(ba_31.span().get(30..30).map(is_empty), Some(true)); - assert_eq!(ba_31.span().get(31..31).map(is_empty), Some(true)); - assert_eq!(ba_31.span().get(15..30).map(is_empty), Some(false)); - - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"; - assert_eq!(ba_30.span().get(29..29).map(is_empty), Some(true)); - assert_eq!(ba_30.span().get(30..30).map(is_empty), Some(true)); - assert_eq!(ba_30.span().get(15..29).map(is_empty), Some(false)); -} - -#[test] -fn test_span_copy() { - let ba: ByteArray = "12"; - let span = ba.span(); - assert_eq!(span.len(), 2); - - let other_span = span; - assert_eq!(other_span.len(), 2); - assert_eq!(ba, span.to_byte_array()); - assert_eq!(span, other_span); - - let span_again = span.span(); - assert_eq!(ba, span_again.to_byte_array()); - assert_eq!(span, span_again); - - let even_more_span_again = other_span.span(); - assert_eq!(ba, even_more_span_again.to_byte_array()); - assert_eq!(other_span, even_more_span_again); - assert_eq!(span, other_span); -} - -#[test] -fn test_span_slice_empty() { - let ba: ByteArray = "hello"; - let span = ba.span(); - - let empty = span[2..2]; - assert_eq!(empty.len(), 0); - assert!(empty.is_empty()); - assert_eq!(empty.to_byte_array(), ""); -} - -#[test] -fn test_span_slice_out_of_bounds() { - let ba: ByteArray = "hello"; - let span = ba.span(); - - assert_eq!(span.get(3..=7), None, "end out of bounds"); - assert_eq!(span.get(6..=6), None, "start out of bounds (inclusive)"); - - const MAX_INDEX: usize = Bounded::MAX; - assert_eq!( - span.get(2..4).unwrap().get((MAX_INDEX - 1)..MAX_INDEX), None, "start offset overflow", - ); - assert_eq!(span.get(2..=3).unwrap().get((MAX_INDEX - 1)..MAX_INDEX), None); - assert_eq!(span.get(2..4).unwrap().get((MAX_INDEX - 1)..=MAX_INDEX), None); - assert_eq!(span.get(2..=3).unwrap().get((MAX_INDEX - 1)..=MAX_INDEX), None); - assert_eq!(span.get(MAX_INDEX..0), None, "backwards range"); - - let empty_string: ByteArray = ""; - assert_eq!(empty_string.span().get(0..2), None, "empty slice is sliceable"); -} - -#[test] -fn test_span_slice_under_31_bytes() { - // Word entirely in remainder word. - let ba: ByteArray = "abcde"; - let span = ba.span(); - let tba = |ba: ByteSpan| ba.to_byte_array(); - - assert_eq!(span.get(0..=2).map(tba), Some("abc")); - assert_eq!(span.get(2..4).map(tba), Some("cd")); - assert_eq!(span.get(4..=4).map(tba), Some("e")); -} -#[test] -fn test_span_slice_exactly_31_bytes() { - // 1 full data word, empty last_word. - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let span = ba_31.span(); - - assert_eq!(span.len(), 31); - assert_eq!(span.get(0..31).unwrap().to_byte_array(), ba_31); - assert_eq!(span[10..=19].to_byte_array(), "KLMNOPQRST"); -} - -#[test] -fn test_span_slice_positions() { - // Two full bytes31 + remainder with 2 bytes. - let ba_64: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$"; - - assert_eq!(ba_64.span()[10..=39].to_byte_array(), "KLMNOPQRSTUVWXYZabcdefghijklmn"); - assert_eq!( - ba_64.span().get(5..64).map(|s| s.to_byte_array()), - Some("FGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$"), - ); - assert_eq!(ba_64.span().get(29..=48).map(|s| s.to_byte_array()), Some("defghijklmnopqrstuvw")); -} - -#[test] -fn test_span_to_bytearray() { - let empty_ba: ByteArray = ""; - assert_eq!(empty_ba.span().to_byte_array(), empty_ba); - - // Only remainder. - let small_ba: ByteArray = "hello"; - assert_eq!(small_ba.span().to_byte_array(), small_ba); - - // Data word and remainder. - let large_ba: ByteArray = "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW"; // 40 bytes - assert_eq!(large_ba.span().to_byte_array(), large_ba); - - // Two data words and remainder. - let even_larger_ba: ByteArray = - "abcdeFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$"; // 64 bytes - assert_eq!(even_larger_ba.span().to_byte_array(), even_larger_ba); -} - -#[test] -fn test_span_multiple_start_offset_slicing() { - let ba_6: ByteArray = "abcdef"; - - let slice1_inc = ba_6.span().get(1..=5); - let slice2_inc = slice1_inc.map(|s| s[1..=4]); - let slice3_inc = slice2_inc.map(|s| s.get(1..4)).flatten(); - - let tba = |ba: ByteSpan| ba.to_byte_array(); - assert_eq!(slice1_inc.map(tba), Some("bcdef")); - assert_eq!(slice2_inc.map(tba), Some("cdef")); - assert_eq!(slice3_inc.map(tba), Some("def")); -} - -#[test] -fn test_span_at_and_index() { - // Test simple access. - let ba: ByteArray = "AB"; - let span = ba.span(); - assert_eq!(span[0_usize], 'A'); - assert_eq!(span.get(1_usize), Some('B')); - assert_eq!(span.get(2_usize), None); - - // Test with offset and two words. - let ba_33: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"; - let mut span = ba_33.span(); - span = span.get(1..33).unwrap(); - assert_eq!(span.get(0_usize), Some('B')); - assert_eq!(span.get(30_usize), Some('f')); - assert_eq!(span[31_usize], 'g'); - assert_eq!(span.get(32_usize), None); - - // Test with offset and two words. - // 64 bytes: 31 + 31 + 2. - let ba_64: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$"; - let mut span = ba_64.span(); - span = span.get(1..64).unwrap(); - assert_eq!(span.get(30_usize), Some('f')); - assert_eq!(span[31_usize], 'g'); - assert_eq!(span.get(60_usize), Some('9')); - assert_eq!(span[61_usize], '#'); - assert_eq!(span.get(62_usize), Some('$')); - assert_eq!(span.get(63_usize), None); - - // Test empty span. - let empty: ByteArray = Default::default(); - let empty_span = empty.span(); - assert_eq!(empty_span.get(0_usize), None); -} - -#[test] -#[should_panic(expected: ('Index out of bounds',))] -fn test_span_index_out_of_bounds() { - let ba: ByteArray = "AB"; - let span = ba.span(); - let _x = span[2_usize]; // Should panic -} - -#[test] -fn test_span_at_overflows() { - // Test overflow protection with large indices. - let ba: ByteArray = "test"; - let span = ba.span(); - assert_eq!(span.get(Bounded::::MAX), None); - - let sliced = ba.span().get(1..3).unwrap(); - assert_eq!(sliced.get(Bounded::::MAX - 1), None); - assert_eq!(sliced.get(Bounded::::MAX), None); -} - -#[test] -fn test_byte_span_simple() { - let empty: ByteArray = ""; - assert_eq!(empty.span().into_iter().collect(), array![]); - - let ba: ByteArray = "A"; - assert_eq!(ba.span().into_iter().collect(), array!['A']); - - let ba: ByteArray = "AB"; - assert_eq!(ba.span().into_iter().collect(), array!['A', 'B']); -} - -#[test] -fn test_byte_span_iterator_word_boundaries() { - // Test 30, 31, 32 bytes (1 word boundary). - let ba_30: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"; - let mut iter = ba_30.span().into_iter(); - iter.advance_by(29).unwrap(); - assert_eq!(iter.collect(), array!['d'], "30 bytes - last byte"); - - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let mut iter = ba_31.span().into_iter(); - assert_eq!(iter.next(), Some('A')); - iter.advance_by(29).unwrap(); - assert_eq!(iter.collect(), array!['e'], "31 bytes - last byte"); - - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - let mut iter = ba_32.span().into_iter(); - iter.advance_by(30).unwrap(); - assert_eq!(iter.collect(), array!['e', 'f'], "32 bytes - last two bytes"); - - // Test 62, 63, 64 bytes (2 word boundaries). - let ba_62: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let mut iter = ba_62.span().into_iter(); - iter.advance_by(61).unwrap(); - assert_eq!(iter.collect(), array!['9'], "62 bytes - last byte"); - - let ba_63: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!"; - let mut iter = ba_63.span().into_iter(); - iter.advance_by(62).unwrap(); - assert_eq!(iter.collect(), array!['!'], "63 bytes - last byte"); - - let ba_64: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@"; - let mut iter = ba_64.span().into_iter(); - iter.advance_by(62).unwrap(); - assert_eq!(iter.collect(), array!['!', '@'], "64 bytes - last two bytes"); -} - -#[test] -fn test_byte_span_iterator_multiple_words() { - // Test with 3+ words to verify iteration works across multiple word boundaries. - // 92 bytes: 31 + 31 + 30. - let ba_92: ByteArray = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;':,.<>?/~`"; - let span = ba_92.span(); - assert_eq!(span.into_iter().count(), 92, "should iterate all 92 bytes"); - - // Verify correctness at specific positions. - let mut iter = span.into_iter(); - assert_eq!(iter.next(), Some('A')); - - // Skip to last byte. - iter.advance_by(90).unwrap(); - assert_eq!(iter.collect(), array!['`'], "90 bytes - last byte"); -} - -#[test] -fn test_byte_span_iterator_for_loop_collect() { - let small_ba: ByteArray = "Hello"; - let span = small_ba.span(); - - let mut collected = Default::default(); - let mut count = 0; - for byte in span { - collected.append_byte(byte); - count += 1; - } - assert_eq!(collected, small_ba); - assert_eq!(count, 5); - assert_eq!(span.into_iter().collect(), small_ba); - - // Test with 2 words. - let ba_40: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"; - collected = Default::default(); - count = 0; - for byte in ba_40.span() { - collected.append_byte(byte); - count += 1; - } - assert_eq!(collected, ba_40); - assert_eq!(count, 40); - assert_eq!(ba_40.span().into_iter().collect(), ba_40); - - // Test with 3 words. - let ba_70: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*"; - collected = Default::default(); - count = 0; - for byte in ba_70.span() { - collected.append_byte(byte); - count += 1; - } - assert_eq!(collected, ba_70); - assert_eq!(count, 70); - assert_eq!(ba_70.span().into_iter().collect(), ba_70); -} - -#[test] -fn test_byte_span_iterator_slices() { - // Slice within remainder word (< 31 bytes). - let ba_13: ByteArray = "Hello Shmello"; - let span = ba_13.span().get(2..7).unwrap(); - assert_eq!( - span.into_iter().collect(), array!['l', 'l', 'o', ' ', 'S'], "slice within remainder word", - ); - - // Iterate slice across 2 words (1 data + remainder). - let ba_33: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg"; - let span = ba_33.span().get(27..32).unwrap(); - assert_eq!(span.into_iter().collect(), array!['b', 'c', 'd', 'e', 'f'], "slice across 2 words"); - - // Iterate slice across 3 words. - let ba_66: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$"; - let span = ba_66.span().get(29..64).unwrap(); - assert_eq!( - span.into_iter().collect(), - array![ - 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', - '@', - ], - "slice across 3 words", - ); - - // Test case where data array is exhausted and remainder has exactly 1 byte. - let ba_32: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"; - let span = ba_32.span().get(31..32).unwrap(); - assert_eq!(span.into_iter().collect(), array!['f'], "1 byte in remainder after data exhausted"); -} - -#[test] -fn test_span_equality() { - let empty: ByteArray = ""; - let empty_copy: ByteArray = ""; - let a: ByteArray = "A"; - let a_copy: ByteArray = "A"; - let b: ByteArray = "B"; - let hello_world: ByteArray = "Hello World"; - let hello_world_copy: ByteArray = "Hello World"; - let hello_cairo: ByteArray = "Hello Cairo"; - let ba_31: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let ba_31_copy: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"; - let ba_64: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@"; - let ba_64_copy: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@"; - - assert_eq!(empty.span(), empty_copy.span()); - assert_eq!(a.span(), a_copy.span()); - assert_eq!(hello_world.span(), hello_world_copy.span()); - assert_eq!(ba_31.span(), ba_31_copy.span()); - assert_eq!(ba_64.span(), ba_64_copy.span()); - - assert_ne!(a.span(), b.span()); - assert_ne!(hello_world.span(), hello_cairo.span()); - assert_ne!(empty.span(), a.span()); - assert_ne!(ba_31.span(), ba_64.span()); - - // Test slice equality. - let ba_37: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij"; - let slice_5_15 = ba_37.span()[5..15]; - let slice_5_15_copy = ba_37.span()[5..15]; - let slice_10_20 = ba_37.span()[10..20]; - assert_eq!(slice_5_15, slice_5_15_copy); - assert_ne!(slice_5_15, slice_10_20); -} diff --git a/corelib/src/test/bytes31_test.cairo b/corelib/src/test/bytes31_test.cairo deleted file mode 100644 index f5b4fa9931..0000000000 --- a/corelib/src/test/bytes31_test.cairo +++ /dev/null @@ -1,193 +0,0 @@ -use crate::byte_array::split_bytes31_for_testing as split_bytes31; -use crate::bytes_31::bytes31_const; - -const POW_2_248: felt252 = 0x100000000000000000000000000000000000000000000000000000000000000; - -#[test] -fn test_at() { - let b1 = bytes31_const::<0x01>(); - assert_eq!(b1.at(0), 0x01); - - let b17 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f1011>(); - assert_eq!(b17.at(0), 0x11); - assert_eq!(b17.at(1), 0x10); - assert_eq!(b17.at(2), 0x0f); - assert_eq!(b17.at(14), 0x03); - assert_eq!(b17.at(15), 0x02); - assert_eq!(b17.at(16), 0x01); - - let b31 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f>(); - assert_eq!(b31.at(0), 0x1f); - assert_eq!(b31.at(1), 0x1e); - assert_eq!(b31.at(2), 0x1d); - assert_eq!(b31.at(14), 0x11); - assert_eq!(b31.at(15), 0x10); - assert_eq!(b31.at(16), 0x0f); - assert_eq!(b31.at(17), 0x0e); - assert_eq!(b31.at(29), 0x02); - assert_eq!(b31.at(30), 0x01); -} - -// Same as the previous test, but with [] instead of .at() -#[test] -fn test_index_view() { - let b1 = bytes31_const::<0x01>(); - assert_eq!(b1[0], 0x01); - - let b17 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f1011>(); - assert_eq!(b17[0], 0x11); - assert_eq!(b17[1], 0x10); - assert_eq!(b17[2], 0x0f); - assert_eq!(b17[14], 0x03); - assert_eq!(b17[15], 0x02); - assert_eq!(b17[16], 0x01); - - let b31 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f>(); - assert_eq!(b31[0], 0x1f); - assert_eq!(b31[1], 0x1e); - assert_eq!(b31[2], 0x1d); - assert_eq!(b31[14], 0x11); - assert_eq!(b31[15], 0x10); - assert(b31[16] == 0x0f, 'wrong byte at index 16'); - assert(b31[17] == 0x0e, 'wrong byte at index 17'); - assert(b31[29] == 0x02, 'wrong byte at index 29'); - assert(b31[30] == 0x01, 'wrong byte at index 30'); -} - - -#[test] -fn test_bytes31_to_from_felt252() { - let zero_as_bytes31: Option = 0.try_into(); - assert(zero_as_bytes31.is_some(), '0 is not a bytes31'); - let zero_as_felt252 = zero_as_bytes31.unwrap().into(); - assert(zero_as_felt252 == 0_felt252, 'bad cast: 0'); - - let one_as_bytes31: Option = 1.try_into(); - assert(one_as_bytes31.is_some(), '1 is not a bytes31'); - let one_as_felt252 = one_as_bytes31.unwrap().into(); - assert(one_as_felt252 == 1_felt252, 'bad cast: 1'); - - let max_as_bytes31: Option = (POW_2_248 - 1).try_into(); - assert(max_as_bytes31.is_some(), '2^248 - 1 is not a bytes31'); - let max_as_felt252 = max_as_bytes31.unwrap().into(); - assert(max_as_felt252 == POW_2_248 - 1, 'bad cast: 2^248 - 1'); - - let out_of_range: Option = POW_2_248.try_into(); - assert(out_of_range.is_none(), '2^248 is a bytes31'); - - let out_of_range: Option = (-1).try_into(); - assert(out_of_range.is_none(), '-1 is a bytes31'); -} - -#[test] -fn test_u8_into_bytes31() { - let one_u8 = 1_u8; - let one_as_bytes31: bytes31 = one_u8.into(); - assert(one_as_bytes31.into() == 1_felt252, 'bad cast: 1'); - - let max_u8 = 0xff_u8; - let max_as_bytes31: bytes31 = max_u8.into(); - assert(max_as_bytes31.into() == 0xff_felt252, 'bad cast: 2^8 - 1'); -} - -#[test] -fn test_u16_into_bytes31() { - let one_u16 = 1_u16; - let one_as_bytes31: bytes31 = one_u16.into(); - assert(one_as_bytes31.into() == 1_felt252, 'bad cast: 1'); - - let max_u16 = 0xffff_u16; - let max_as_bytes31: bytes31 = max_u16.into(); - assert(max_as_bytes31.into() == 0xffff_felt252, 'bad cast: 2^16 - 1'); -} - -#[test] -fn test_u32_into_bytes31() { - let one_u32 = 1_u32; - let one_as_bytes31: bytes31 = one_u32.into(); - assert(one_as_bytes31.into() == 1_felt252, 'bad cast: 1'); - - let max_u32 = 0xffffffff_u32; - let max_as_bytes31: bytes31 = max_u32.into(); - assert(max_as_bytes31.into() == 0xffffffff_felt252, 'bad cast: 2^32 - 1'); -} - -#[test] -fn test_u64_into_bytes31() { - let one_u64 = 1_u64; - let one_as_bytes31: bytes31 = one_u64.into(); - assert(one_as_bytes31.into() == 1_felt252, 'bad cast: 1'); - - let max_u64 = 0xffffffffffffffff_u64; - let max_as_bytes31: bytes31 = max_u64.into(); - assert(max_as_bytes31.into() == 0xffffffffffffffff_felt252, 'bad cast: 2^64 - 1'); -} - -#[test] -fn test_u128_into_bytes31() { - let one_u128 = 1_u128; - let one_as_bytes31: bytes31 = one_u128.into(); - assert(one_as_bytes31.into() == 1_felt252, 'bad cast: 1'); - - let max_u128 = 0xffffffffffffffffffffffffffffffff_u128; - let max_as_bytes31: bytes31 = max_u128.into(); - assert( - max_as_bytes31.into() == 0xffffffffffffffffffffffffffffffff_felt252, 'bad cast: 2^128 - 1', - ); -} - -#[test] -fn test_split_bytes31() { - let (left, right) = split_bytes31(0x1122, 1); - assert(left == 0x22, 'bad split (2, 1) left'); - assert(right == 0x11, 'bad split (2, 1) right'); - - let x = 0x112233445566778899aabbccddeeff00112233; - let (left, right) = split_bytes31(x, 0); - assert(left == 0, 'bad split (19, 0) left'); - assert(right == 0x112233445566778899aabbccddeeff00112233, 'bad split (19, 0) right'); - - let (left, right) = split_bytes31(x, 1); - assert(left == 0x33, 'bad split (19, 1) left'); - assert(right == 0x112233445566778899aabbccddeeff001122, 'bad split (19, 1) right'); - - let (left, right) = split_bytes31(x, 15); - assert(left == 0x5566778899aabbccddeeff00112233, 'bad split (19, 15) left'); - assert(right == 0x11223344, 'bad split (19, 15) right'); - - let (left, right) = split_bytes31(x, 16); - assert(left == 0x445566778899aabbccddeeff00112233, 'bad split (19, 16) left'); - assert(right == 0x112233, 'bad split (19, 16) right'); - - let (left, right) = split_bytes31(x, 18); - assert(left == 0x2233445566778899aabbccddeeff00112233, 'bad split (19, 18) left'); - assert(right == 0x11, 'bad split (19, 18) right'); - - let (left, right) = split_bytes31(x, 19); - assert(left == 0x112233445566778899aabbccddeeff00112233, 'bad split (19, 19) left'); - assert(right == 0, 'bad split (19, 19) right'); -} - -#[test] -fn test_equality() { - let b1 = bytes31_const::<0x01>(); - let b2 = bytes31_const::<0x0102>(); - let b3 = bytes31_const::<0x0201>(); - assert(b1 == b1, 'b1 != b1'); - assert(b2 == b2, 'b2 != b2'); - assert(b3 == b3, 'b3 != b3'); - assert(b1 != b2, 'b1 == b2'); - assert(b1 != b3, 'b1 == b3'); - assert(b2 != b3, 'b2 == b3'); - - let b4 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f>(); - let b5 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1e>(); - let b6 = bytes31_const::<0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e>(); - - assert(b4 == b4, 'b4 != b4'); - assert(b5 == b5, 'b5 != b5'); - assert(b6 == b6, 'b6 != b6'); - assert(b4 != b5, 'b4 == b5'); - assert(b4 != b6, 'b4 == b6'); - assert(b5 != b6, 'b5 == b6'); -} diff --git a/corelib/src/test/circuit_test.cairo b/corelib/src/test/circuit_test.cairo deleted file mode 100644 index cef993d57d..0000000000 --- a/corelib/src/test/circuit_test.cairo +++ /dev/null @@ -1,163 +0,0 @@ -use crate::circuit::{ - AddInputResultTrait, AddMod, CircuitElement, CircuitInput, CircuitInputs, CircuitModulus, - CircuitOutputsTrait, EvalCircuitTrait, MulMod, RangeCheck96, circuit_add, circuit_inverse, - circuit_mul, circuit_sub, u384, u96, -}; -use crate::num::traits::Zero; -use crate::traits::TryInto; - -#[test] -fn test_u96() { - let a: u96 = 0x123; - assert_eq!(a, 0x123); -} - -#[test] -fn test_try_into_u96() { - assert_eq!(0x123_felt252.try_into(), Option::::Some(0x123)); - assert_eq!(0x1000000000000000000000000_felt252.try_into(), Option::::None); -} - -#[test] -fn test_builtins() { - crate::internal::require_implicit::(); - crate::internal::require_implicit::(); - crate::internal::require_implicit::(); -} - -#[test] -fn test_circuit_success() { - let in1 = CircuitElement::> {}; - let in2 = CircuitElement::> {}; - let add = circuit_add(in1, in2); - let inv = circuit_inverse(add); - let sub = circuit_sub(inv, in2); - let mul = circuit_mul(inv, sub); - - let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap(); - let outputs = (mul, add, inv) - .new_inputs() - .next([3, 0, 0, 0]) - .next([6, 0, 0, 0]) - .done() - .eval(modulus) - .unwrap(); - - assert_eq!(outputs.get_output(add), u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 }); - assert_eq!(outputs.get_output(inv), u384 { limb0: 4, limb1: 0, limb2: 0, limb3: 0 }); - assert_eq!(outputs.get_output(sub), u384 { limb0: 5, limb1: 0, limb2: 0, limb3: 0 }); - assert_eq!(outputs.get_output(mul), u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 }); -} - - -#[test] -fn test_circuit_failure() { - let in0 = CircuitElement::> {}; - let out0 = circuit_inverse(in0); - - let modulus = TryInto::<_, CircuitModulus>::try_into([55, 0, 0, 0]).unwrap(); - (out0,).new_inputs().next([11, 0, 0, 0]).done().eval(modulus).unwrap_err(); - (out0,).new_inputs().next([11, 0, 0, 0]).done().eval(modulus).unwrap_err(); -} - -#[test] -fn test_into_u384() { - assert!( - 0x100000023000000450000006700000089000000ab000000cd000000ef0000000_u256 - .into() == u384 { - limb0: 0xb000000cd000000ef0000000, - limb1: 0x50000006700000089000000a, - limb2: 0x1000000230000004, - limb3: 0, - }, - ); - assert!( - 0x10000002300000045000000670000008_u128 - .into() == u384 { - limb0: 0x300000045000000670000008, limb1: 0x10000002, limb2: 0, limb3: 0, - }, - ); - assert!( - 0x70000023000000450000006700000089000000ab000000cd000000ef0000000_felt252 - .into() == u384 { - limb0: 0xb000000cd000000ef0000000, - limb1: 0x50000006700000089000000a, - limb2: 0x700000230000004, - limb3: 0, - }, - ); -} - -#[test] -fn test_from_u384() { - let limb0 = 0xb000000cd000000ef0000000; - let limb1 = 0x50000006700000089000000a; - let limb2 = 0x1000000230000004; - let limb3 = 0; - assert!( - u384 { limb0, limb1, limb2, limb3 } - .try_into() == Some( - 0x100000023000000450000006700000089000000ab000000cd000000ef0000000_u256, - ), - ); - assert!(u384 { limb0, limb1, limb2, limb3: 1 }.try_into() == Option::::None); - assert!( - u384 { limb0, limb1, limb2: 0x11000000230000004, limb3 }.try_into() == Option::::None, - ); - let limb0 = 0x300000045000000670000008; - let limb1 = 0x10000002; - let limb2 = 0; - let limb3 = 0; - assert!( - u384 { limb0, limb1, limb2, limb3 } - .try_into() == Some(0x10000002300000045000000670000008_u128), - ); - assert!(u384 { limb0, limb1: 0x110000002, limb2, limb3 }.try_into() == Option::::None); - assert!(u384 { limb0, limb1, limb2: 1, limb3 }.try_into() == Option::::None); - assert!(u384 { limb0, limb1, limb2, limb3: 1 }.try_into() == Option::::None); -} - -#[test] -fn test_fill_inputs_loop() { - let in1 = CircuitElement::> {}; - let in2 = CircuitElement::> {}; - let add = circuit_add(in1, in2); - - let mut inputs: Array<[u96; 4]> = array![[1, 0, 0, 0], [2, 0, 0, 0]]; - let mut circuit_inputs = (add,).new_inputs(); - - while let Some(input) = inputs.pop_front() { - circuit_inputs = circuit_inputs.next(input); - } - - let modulus = TryInto::<_, CircuitModulus>::try_into([55, 0, 0, 0]).unwrap(); - circuit_inputs.done().eval(modulus).unwrap(); -} - -#[test] -fn test_u384_serde() { - let value = u384 { - limb0: 0xb000000cd000000ef0000000, - limb1: 0x50000006700000089000000a, - limb2: 0x100000023000000450000000, - limb3: 0x80000009a000000bc0000000, - }; - let serialized = array![ - 0x50000006700000089000000ab000000cd000000ef0000000, - 0x80000009a000000bc0000000100000023000000450000000, - ]; - let mut buffer = array![]; - value.serialize(ref buffer); - assert!(buffer == serialized); - - let mut serialized = serialized.span(); - - assert!(Serde::::deserialize(ref serialized) == Some(value)); -} - -#[test] -fn test_u384_zero() { - assert_eq!(Zero::zero(), u384 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }); - assert!(Zero::is_zero(@u384 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 })); - assert!(Zero::is_non_zero(@u384 { limb0: 0, limb1: 1, limb2: 0, limb3: 0 })); -} diff --git a/corelib/src/test/clone_test.cairo b/corelib/src/test/clone_test.cairo deleted file mode 100644 index a6cb59f7dc..0000000000 --- a/corelib/src/test/clone_test.cairo +++ /dev/null @@ -1,11 +0,0 @@ -#[test] -fn test_tuple_clone() { - let tup = (array![10_u32, 11, 12], array![20_u64, 21, 22], array![30, 31, 32]); - assert!(tup.clone() == tup); -} - -#[test] -fn test_fixed_sized_array_clone() { - let arr = [array![10, 11, 12], array![20, 21, 22], array![30, 31, 32]]; - assert!(arr.clone() == arr); -} diff --git a/corelib/src/test/cmp_test.cairo b/corelib/src/test/cmp_test.cairo deleted file mode 100644 index f0960e6a6c..0000000000 --- a/corelib/src/test/cmp_test.cairo +++ /dev/null @@ -1,298 +0,0 @@ -use crate::cmp::{max, min, minmax}; -use crate::test::test_utils::assert_eq; - -// Integer tests - -#[test] -fn test_min_u8() { - assert_eq(@min(0_u8, 1_u8), @0_u8, '0 < 1'); - assert_eq(@min(5_u8, 7_u8), @5_u8, '5 < 7'); - assert_eq(@min(255_u8, 128_u8), @128_u8, '128 < 255'); - assert_eq(@min(10_u8, 10_u8), @10_u8, '10 == 10'); - assert_eq(@min(0_u8, 0_u8), @0_u8, '0 == 0'); - assert_eq(@min(255_u8, 255_u8), @255_u8, '255 == 255'); - assert_eq(@min(3_u8, 4_u8), @3_u8, '3 < 4'); - assert_eq(@min(255_u8, 200_u8), @200_u8, '200 < 255'); - assert_eq(@min(250_u8, 253_u8), @250_u8, '250 < 253'); -} - -#[test] -fn test_max_u8() { - assert_eq(@max(0_u8, 1_u8), @1_u8, '1 > 0'); - assert_eq(@max(5_u8, 7_u8), @7_u8, '7 > 5'); - assert_eq(@max(255_u8, 128_u8), @255_u8, '255 > 128'); - assert_eq(@max(10_u8, 10_u8), @10_u8, '10 == 10'); - assert_eq(@max(0_u8, 0_u8), @0_u8, '0 == 0'); - assert_eq(@max(255_u8, 255_u8), @255_u8, '255 == 255'); - assert_eq(@max(100_u8, 200_u8), @200_u8, '200 > 100'); - assert_eq(@max(1_u8, 2_u8), @2_u8, '2 > 1'); - assert_eq(@max(120_u8, 130_u8), @130_u8, '130 > 120'); - assert_eq(@max(200_u8, 150_u8), @200_u8, '200 > 150'); -} - -#[test] -fn test_minmax_u8() { - assert!(minmax(0_u8, 1_u8) == (0_u8, 1_u8), "1 > 0"); - assert!(minmax(5_u8, 7_u8) == (5_u8, 7_u8), "7 > 5"); - assert!(minmax(255_u8, 128_u8) == (128_u8, 255_u8), "255 > 128"); - assert!(minmax(10_u8, 10_u8) == (10_u8, 10_u8), "10 == 10"); - assert!(minmax(0_u8, 0_u8) == (0_u8, 0_u8), "0 == 0"); - assert!(minmax(255_u8, 255_u8) == (255_u8, 255_u8), "255 == 255"); - assert!(minmax(100_u8, 200_u8) == (100_u8, 200_u8), "200 > 100"); - assert!(minmax(1_u8, 2_u8) == (1_u8, 2_u8), "2 > 1"); - assert!(minmax(120_u8, 130_u8) == (120_u8, 130_u8), "130 > 120"); - assert!(minmax(200_u8, 150_u8) == (150_u8, 200_u8), "200 > 150"); -} - -#[test] -fn test_min_u16() { - assert_eq(@min(0_u16, 1_u16), @0_u16, '0 < 1'); - assert_eq(@min(5_u16, 7_u16), @5_u16, '5 < 7'); - assert_eq(@min(65535_u16, 32768_u16), @32768_u16, '32768 < 65535'); - assert_eq(@min(10_u16, 10_u16), @10_u16, '10 == 10'); - assert_eq(@min(0_u16, 0_u16), @0_u16, '0 == 0'); - assert_eq(@min(65535_u16, 65535_u16), @65535_u16, '65535 == 65535'); - assert_eq(@min(100_u16, 200_u16), @100_u16, '100 < 200'); - assert_eq(@min(1_u16, 2_u16), @1_u16, '1 < 2'); - assert_eq(@min(32767_u16, 32766_u16), @32766_u16, '32766 < 32767'); - assert_eq(@min(400_u16, 300_u16), @300_u16, '300 < 400'); -} - -#[test] -fn test_max_u16() { - assert_eq(@max(0_u16, 1_u16), @1_u16, '1 > 0'); - assert_eq(@max(5_u16, 7_u16), @7_u16, '7 > 5'); - assert_eq(@max(65535_u16, 32768_u16), @65535_u16, '65535 > 32768'); - assert_eq(@max(10_u16, 10_u16), @10_u16, '10 == 10'); - assert_eq(@max(0_u16, 0_u16), @0_u16, '0 == 0'); - assert_eq(@max(65535_u16, 65535_u16), @65535_u16, '65535 == 65535'); - assert_eq(@max(100_u16, 200_u16), @200_u16, '200 > 100'); - assert_eq(@max(1_u16, 2_u16), @2_u16, '2 > 1'); - assert_eq(@max(32767_u16, 32766_u16), @32767_u16, '32767 > 32766'); - assert_eq(@max(400_u16, 300_u16), @400_u16, '400 > 300'); -} - -#[test] -fn test_min_u32() { - assert_eq(@min(0_u32, 1_u32), @0_u32, '0 < 1'); - assert_eq(@min(5_u32, 7_u32), @5_u32, '5 < 7'); - assert_eq(@min(4294967295_u32, 2147483648_u32), @2147483648_u32, '2147483648 < 4294967295'); - assert_eq(@min(10_u32, 10_u32), @10_u32, '10 == 10'); - assert_eq(@min(0_u32, 0_u32), @0_u32, '0 == 0'); - assert_eq(@min(4294967295_u32, 4294967295_u32), @4294967295_u32, '4294967295 == 4294967295'); - assert_eq(@min(100_u32, 200_u32), @100_u32, '100 < 200'); - assert_eq(@min(1_u32, 2_u32), @1_u32, '1 < 2'); - assert_eq(@min(2147483647_u32, 2147483646_u32), @2147483646_u32, '2147483646 < 2147483647'); - assert_eq(@min(400_u32, 300_u32), @300_u32, '300 < 400'); -} - -#[test] -fn test_max_u32() { - assert_eq(@max(0_u32, 1_u32), @1_u32, '1 > 0'); - assert_eq(@max(5_u32, 7_u32), @7_u32, '7 > 5'); - assert_eq(@max(4294967295_u32, 2147483648_u32), @4294967295_u32, '4294967295 > 2147483648'); - assert_eq(@max(10_u32, 10_u32), @10_u32, '10 == 10'); - assert_eq(@max(0_u32, 0_u32), @0_u32, '0 == 0'); - assert_eq(@max(4294967295_u32, 4294967295_u32), @4294967295_u32, '4294967295 == 4294967295'); - assert_eq(@max(100_u32, 200_u32), @200_u32, '200 > 100'); - assert_eq(@max(1_u32, 2_u32), @2_u32, '2 > 1'); - assert_eq(@max(2147483647_u32, 2147483646_u32), @2147483647_u32, '2147483647 > 2147483646'); - assert_eq(@max(400_u32, 300_u32), @400_u32, '400 > 300'); -} - -#[test] -fn test_min_u64() { - assert_eq(@min(0_u64, 1_u64), @0_u64, '0 < 1'); - assert_eq(@min(5_u64, 7_u64), @5_u64, '5 < 7'); - assert_eq( - @min(18446744073709551615_u64, 9223372036854775808_u64), - @9223372036854775808_u64, - '92233... < 18446...', - ); - assert_eq(@min(10_u64, 10_u64), @10_u64, '10 == 10'); - assert_eq(@min(0_u64, 0_u64), @0_u64, '0 == 0'); - assert_eq( - @min(18446744073709551615_u64, 18446744073709551615_u64), - @18446744073709551615_u64, - '18446... == 18446...', - ); - assert_eq(@min(100_u64, 200_u64), @100_u64, '100 < 200'); - assert_eq(@min(1_u64, 2_u64), @1_u64, '1 < 2'); - assert_eq( - @min(9223372036854775807_u64, 9223372036854775806_u64), - @9223372036854775806_u64, - '92233... < 92233...', - ); - assert_eq(@min(400_u64, 300_u64), @300_u64, '300 < 400'); -} - -#[test] -fn test_max_u64() { - assert_eq(@max(0_u64, 1_u64), @1_u64, '1 > 0'); - assert_eq(@max(5_u64, 7_u64), @7_u64, '7 > 5'); - assert_eq( - @max(18446744073709551615_u64, 9223372036854775808_u64), - @18446744073709551615_u64, - '18446... > 92233...', - ); - assert_eq(@max(10_u64, 10_u64), @10_u64, '10 == 10'); - assert_eq(@max(0_u64, 0_u64), @0_u64, '0 == 0'); - assert_eq( - @max(18446744073709551615_u64, 18446744073709551615_u64), - @18446744073709551615_u64, - '18446... == 18446...', - ); - assert_eq(@max(100_u64, 200_u64), @200_u64, '200 > 100'); - assert_eq(@max(1_u64, 2_u64), @2_u64, '2 > 1'); - assert_eq( - @max(9223372036854775807_u64, 9223372036854775806_u64), - @9223372036854775807_u64, - '92233... > 92233...', - ); - assert_eq(@max(400_u64, 300_u64), @400_u64, '400 > 300'); -} - -#[test] -fn test_min_u128() { - assert_eq(@min(0_u128, 1_u128), @0_u128, '0 < 1'); - assert_eq(@min(5_u128, 7_u128), @5_u128, '5 < 7'); - assert_eq( - @min( - 340282366920938463463374607431768211455_u128, - 170141183460469231731687303715884105728_u128, - ), - @170141183460469231731687303715884105728_u128, - '170141... < 340282...', - ); - assert_eq(@min(10_u128, 10_u128), @10_u128, '10 == 10'); - assert_eq(@min(0_u128, 0_u128), @0_u128, '0 == 0'); - assert_eq( - @min( - 340282366920938463463374607431768211455_u128, - 340282366920938463463374607431768211455_u128, - ), - @340282366920938463463374607431768211455_u128, - '340282366... == 340282366...', - ); - assert_eq(@min(100_u128, 200_u128), @100_u128, '100 < 200'); - assert_eq(@min(1_u128, 2_u128), @1_u128, '1 < 2'); - assert_eq( - @min( - 170141183460469231731687303715884105727_u128, - 170141183460469231731687303715884105726_u128, - ), - @170141183460469231731687303715884105726_u128, - '17014118... < 1701411834...', - ); - assert_eq(@min(400_u128, 300_u128), @300_u128, '300 < 400'); -} - -#[test] -fn test_max_u128() { - assert_eq(@max(0_u128, 1_u128), @1_u128, '1 > 0'); - assert_eq(@max(5_u128, 7_u128), @7_u128, '7 > 5'); - assert_eq( - @max(18446744073709551615_u128, 9223372036854775808_u128), - @18446744073709551615_u128, - '18446744... > 922337...', - ); - assert_eq(@max(10_u128, 10_u128), @10_u128, '10 == 10'); - assert_eq(@max(0_u128, 0_u128), @0_u128, '0 == 0'); - assert_eq( - @max(18446744073709551615_u128, 18446744073709551615_u128), - @18446744073709551615_u128, - '184467...== 184467', - ); - assert_eq(@max(100_u128, 200_u128), @200_u128, '200 > 100'); - assert_eq(@max(1_u128, 2_u128), @2_u128, '2 > 1'); - assert_eq( - @max(9223372036854775807_u128, 9223372036854775806_u128), - @9223372036854775807_u128, - '922337203... > 922337...', - ); - assert_eq(@max(400_u128, 300_u128), @400_u128, '400 > 300'); -} - -#[test] -fn test_min_u256() { - let a = u256 { low: 0, high: 0 }; - let b = u256 { low: 1, high: 0 }; - let c = u256 { low: 5, high: 0 }; - let d = u256 { low: 7, high: 0 }; - let e = u256 { low: 0, high: 1 }; - let f = u256 { low: 0, high: 2 }; - - assert_eq(@min(a, b), @a, 'a < b'); - assert_eq(@min(c, d), @c, 'c < d'); - assert_eq(@min(e, f), @e, 'e < f'); - assert_eq(@min(a, a), @a, 'a == a'); - assert_eq(@min(b, b), @b, 'b == b'); - assert_eq(@min(f, f), @f, 'f == f'); -} - -#[test] -fn test_max_u256() { - let a = u256 { low: 0, high: 0 }; - let b = u256 { low: 1, high: 0 }; - let c = u256 { low: 5, high: 0 }; - let d = u256 { low: 7, high: 0 }; - let e = u256 { low: 0, high: 1 }; - let f = u256 { low: 0, high: 2 }; - - assert_eq(@max(a, b), @b, 'b > a'); - assert_eq(@max(c, d), @d, 'd > c'); - assert_eq(@max(e, f), @f, 'f > e'); - assert_eq(@max(a, a), @a, 'a == a'); - assert_eq(@max(b, b), @b, 'b == b'); - assert_eq(@max(f, f), @f, 'f == f'); -} - -// User-defined types -#[derive(Drop, Copy)] -struct Foo { - val: u128, -} - -impl FooPartialOrd of PartialOrd { - fn le(lhs: Foo, rhs: Foo) -> bool { - lhs.val <= rhs.val - } - - fn ge(lhs: Foo, rhs: Foo) -> bool { - lhs.val >= rhs.val - } - - fn lt(lhs: Foo, rhs: Foo) -> bool { - lhs.val < rhs.val - } - - fn gt(lhs: Foo, rhs: Foo) -> bool { - lhs.val > rhs.val - } -} - -#[test] -fn test_min_foo() { - let a = Foo { val: 0 }; - let b = Foo { val: 1 }; - let c = Foo { val: 5 }; - let d = Foo { val: 7 }; - - assert_eq(@min(a, b).val, @a.val, 'a < b'); - assert_eq(@min(c, d).val, @c.val, 'c < d'); - assert_eq(@min(a, a).val, @a.val, 'a == a'); - assert_eq(@min(b, b).val, @b.val, 'b == b'); -} - -#[test] -fn test_max_foo() { - let a = Foo { val: 0 }; - let b = Foo { val: 1 }; - let c = Foo { val: 5 }; - let d = Foo { val: 7 }; - - assert_eq(@max(a, b).val, @b.val, 'b > a'); - assert_eq(@max(c, d).val, @d.val, 'd > c'); - assert_eq(@max(a, a).val, @a.val, 'a == a'); - assert_eq(@max(b, b).val, @b.val, 'b == b'); -} diff --git a/corelib/src/test/coupon_test.cairo b/corelib/src/test/coupon_test.cairo deleted file mode 100644 index 2f157d1c89..0000000000 --- a/corelib/src/test/coupon_test.cairo +++ /dev/null @@ -1,25 +0,0 @@ -extern fn coupon_buy() -> T nopanic; - -#[feature("corelib-internal-use")] -fn arr_sum(arr: Array<(u128, arr_sum::Coupon)>) -> u128 nopanic { - match arr.pop_front_consume() { - Some(( - rem, (elm, coupon), - )) => crate::integer::u128_wrapping_add(elm, arr_sum(rem, __coupon__: coupon)), - None => 0, - } -} - -#[test] -fn test_arr_sum() { - let mut arr: Array<(u128, arr_sum::Coupon)> = array![]; - arr.append((3, coupon_buy())); - arr.append((4, coupon_buy())); - arr.append((5, coupon_buy())); - - let available_gas = crate::testing::get_available_gas(); - let res = arr_sum(arr); - // Check that arr_sum did not consume any gas. - assert_ge!(core::testing::get_available_gas(), available_gas, "Gas was consumed by arr_sum."); - assert_eq!(res, 12); -} diff --git a/corelib/src/test/deref_test.cairo b/corelib/src/test/deref_test.cairo deleted file mode 100644 index dec74d2e30..0000000000 --- a/corelib/src/test/deref_test.cairo +++ /dev/null @@ -1,131 +0,0 @@ -#[derive(Drop, Copy)] -struct S1 { - a: usize, - b: felt252, -} - -#[derive(Drop, Copy)] -struct S2 { - inner: S1, - a: usize, -} - -#[derive(Drop, Copy)] -struct S3 { - inner: S2, -} - -#[generate_trait] -impl MyImpl of MyTrait { - fn foo(self: @S1) {} -} - -impl S2Deref of crate::ops::Deref { - type Target = S1; - fn deref(self: S2) -> S1 { - self.inner - } -} - -impl S3Deref of crate::ops::Deref { - type Target = S2; - fn deref(self: S3) -> S2 { - self.inner - } -} - -#[test] -fn test_simple_deref() { - let s1 = S1 { a: 1, b: 2 }; - let s2 = S2 { inner: s1, a: 3 }; - let s3 = S3 { inner: s2 }; - assert_eq!(s1.a, 1); - assert_eq!(s2.a, 3); - assert_eq!(s3.a, 3); - assert_eq!(s3.inner.a, 3); - assert_eq!(s3.inner.inner.a, 1); - assert_eq!(s3.b, 2); - assert_eq!(s3.inner.b, 2); - assert_eq!(s3.foo(), ()); -} - -#[derive(Drop, Copy)] -enum E1 { - V1: S1, - V2: S1, -} - -impl E1Deref of crate::ops::Deref { - type Target = S1; - fn deref(self: E1) -> S1 { - match self { - E1::V1(s) => s, - E1::V2(s) => s, - } - } -} - -#[test] -fn test_simple_enum_deref() { - let s1 = S1 { a: 1, b: 2 }; - let e1 = E1::V1(s1); - assert_eq!(e1.a, 1); - assert_eq!(e1.b, 2); -} - -#[derive(Drop, Copy)] -enum E3 { - V1: S3, - V2: S3, -} - -impl E3Deref of crate::ops::Deref { - type Target = S3; - fn deref(self: E3) -> S3 { - match self { - E3::V1(s) => s, - E3::V2(s) => s, - } - } -} - -#[test] -fn test_nested_enum_deref() { - let s1 = S1 { a: 1, b: 2 }; - let s2 = S2 { inner: s1, a: 3 }; - let s3 = S3 { inner: s2 }; - let e3 = E3::V1(s3); - assert_eq!(e3.a, 3); - assert_eq!(e3.inner.a, 3); - assert_eq!(e3.inner.inner.a, 1); - assert_eq!(e3.b, 2); - assert_eq!(e3.inner.b, 2); -} - -#[derive(Drop, Copy)] -struct S4 { - e3: E3, - a: usize, -} - -impl S4Deref of crate::ops::Deref { - type Target = E3; - fn deref(self: S4) -> E3 { - self.e3 - } -} - -#[test] -fn test_struct_enum_deref() { - let s1 = S1 { a: 1, b: 2 }; - let s2 = S2 { inner: s1, a: 3 }; - let s3 = S3 { inner: s2 }; - let e3 = E3::V1(s3); - let s4 = S4 { e3: e3, a: 4 }; - assert_eq!(s4.a, 4); - assert_eq!(s4.e3.a, 3); - assert_eq!(s4.e3.inner.a, 3); - assert_eq!(s4.e3.inner.inner.a, 1); - assert_eq!(s4.e3.b, 2); - assert_eq!(s4.e3.inner.b, 2); -} diff --git a/corelib/src/test/dict_test.cairo b/corelib/src/test/dict_test.cairo deleted file mode 100644 index 6fe7ea3066..0000000000 --- a/corelib/src/test/dict_test.cairo +++ /dev/null @@ -1,186 +0,0 @@ -use crate::dict::{Felt252Dict, Felt252DictEntryTrait, SquashedFelt252DictImpl}; -use crate::nullable; -use crate::test::test_utils::assert_eq; - -#[test] -fn test_dict_new() -> Felt252Dict { - Default::default() -} - -#[test] -fn test_dict_squash_empty() { - let mut dict: Felt252Dict = Default::default(); - let _squashed_dict = dict.squash(); -} - -#[test] -fn test_dict_default_val() { - let mut dict: Felt252Dict = Default::default(); - let default_val = dict.get(0); - assert_eq!(default_val, 0); -} - -#[test] -fn test_dict_write_read() { - let mut dict = Default::default(); - dict.insert(10, 110); - dict.insert(11, 111); - let val10 = dict[10]; - let val11 = dict[11]; - let val12 = dict[12]; - assert_eq!(val10, 110); - assert_eq!(val11, 111); - assert_eq!(val12, 0); -} - -#[test] -fn test_dict_entry() { - let mut dict = Default::default(); - dict.insert(10, 110); - let (entry, value) = dict.entry(10); - assert_eq!(value, 110); - let mut dict = entry.finalize(11); - assert_eq!(dict[10], 11); -} - -#[test] -fn test_dict_entry_uninitialized() { - let mut dict = Default::default(); - let (entry, value) = dict.entry(10); - assert_eq!(value, 0_felt252); - let mut dict = entry.finalize(110); - assert_eq!(dict[10], 110); -} - -#[test] -fn test_dict_update_twice() { - let mut dict = Default::default(); - dict.insert(10, 110); - let (entry, value) = dict.entry(10); - assert_eq!(value, 110); - dict = entry.finalize(11); - assert_eq!(dict[10], 11); - let (entry, value) = dict.entry(10); - assert_eq!(value, 11); - dict = entry.finalize(12); - assert_eq(@dict[10], @12, 'dict[10] == 12'); -} - - -/// Tests the destruction of a non-finalized `Felt252DictEntry`. -/// -/// Calls the destructor of the entry, which in turn calls the destructor of the `Felt252Dict`. -#[test] -fn test_dict_entry_destruct() { - let mut dict = Default::default(); - dict.insert(10, 110); - let (_entry, _value) = dict.entry(10); -} - -const KEY1: felt252 = 10; -const KEY2: felt252 = 21; -// KEY3 is ~37% * PRIME. -const KEY3: felt252 = 1343531647004637707094910297222796970954128321746173119103571679493202324940; -// KEY4 and KEY5 are ~92% * PRIME. -const KEY4: felt252 = 3334603141101959564751596861783084684819726025596122159217101666076094555684; -const KEY5: felt252 = 3334603141101959564751596861783084684819726025596122159217101666076094555685; - -/// Tests the big-keys behavior of `felt252_dict_squash()`. -/// -/// Uses a few keys to simulate the 3 possible cases in `validate_felt252_le`. -#[test] -fn test_dict_big_keys() { - let mut dict = Default::default(); - - dict.insert(KEY1, 1); - dict.insert(KEY2, 2); - dict.insert(KEY3, 3); - dict.insert(KEY4, 4); - dict.insert(KEY5, 5); - - assert_eq(@dict[KEY1], @1, 'KEY1'); - assert_eq(@dict[KEY2], @2, 'KEY2'); - assert_eq(@dict[KEY3], @3, 'KEY3'); - assert_eq(@dict[KEY4], @4, 'KEY4'); - assert_eq(@dict[KEY5], @5, 'KEY5'); -} - -#[test] -fn test_dict_of_nullable() { - let mut dict = Default::default(); - dict.insert(10, nullable::nullable_from_box(BoxTrait::new(1))); - dict.insert(11, nullable::nullable_from_box(BoxTrait::new(2))); - let val10 = dict[10].deref(); - let val11 = dict[11].deref(); - let val12 = dict[12]; - assert_eq(@val10, @1, 'dict[10] == 1'); - assert_eq(@val11, @2, 'dict[11] == 2'); - assert( - match nullable::match_nullable(val12) { - nullable::FromNullableResult::Null => true, - nullable::FromNullableResult::NotNull(_) => false, - }, - 'default_val == null', - ); -} - -#[test] -fn test_bool_dict() { - let mut bool_dict: Felt252Dict = Default::default(); - let _squashed_dict = bool_dict.squash(); - let mut bool_dict: Felt252Dict = Default::default(); - assert(!bool_dict.get(0), 'default_val != false'); - bool_dict.insert(1, true); - assert(bool_dict.get(1), 'bool_dict[1] != true'); -} - -#[test] -fn test_array_dict() { - let mut dict = Default::default(); - dict.insert(10, NullableTrait::new(array![1, 2, 3])); - let (entry, value) = dict.entry(10); - assert_eq(@value.deref(), @array![1, 2, 3], 'dict[10] == [1, 2, 3]'); - dict = entry.finalize(NullableTrait::new(array![4, 5])); - let (entry, value) = dict.entry(10); - assert_eq(@value.deref(), @array![4, 5], 'dict[10] == [4, 5]'); - dict = entry.finalize(nullable::null()); - let (_entry, value) = dict.entry(10); - assert(value.is_null(), 'dict[10] == null'); -} - -#[test] -fn test_dict_from_iterator() { - let iter = (0..5_u32).into_iter().map(|x| (x.into(), x)); - let mut dict: Felt252Dict = FromIterator::from_iter(iter); - - assert_eq!(dict[0], 0); - assert_eq!(dict[1], 1); - assert_eq!(dict[2], 2); - assert_eq!(dict[3], 3); - assert_eq!(dict[4], 4); -} - -#[test] -fn test_dict_from_collect() { - let mut dict: Felt252Dict = (0..5_u32).into_iter().map(|x| (x.into(), x)).collect(); - - assert_eq!(dict[0], 0); - assert_eq!(dict[1], 1); - assert_eq!(dict[2], 2); - assert_eq!(dict[3], 3); - assert_eq!(dict[4], 4); -} - -#[test] -fn test_dict_from_collect_with_duplicate_keys() { - let mut dict = array![(0, 1_u32), (0, 2_u32)].into_iter().collect::>(); - assert_eq!(dict[0], 2); -} - -#[test] -fn test_array_from_squash_dict() { - let mut dict: Felt252Dict = (0..5_u32).into_iter().map(|x| (x.into(), x)).collect(); - assert_eq!( - dict.squash().into_entries(), array![(0, 0, 0), (1, 0, 1), (2, 0, 2), (3, 0, 3), (4, 0, 4)], - ); -} diff --git a/corelib/src/test/ec_test.cairo b/corelib/src/test/ec_test.cairo deleted file mode 100644 index 9a1387267d..0000000000 --- a/corelib/src/test/ec_test.cairo +++ /dev/null @@ -1,148 +0,0 @@ -use crate::ec::{EcPoint, EcPointTrait, EcStateTrait, stark_curve}; -use crate::ecdsa::{check_ecdsa_signature, recover_public_key}; -use crate::option::OptionTrait; -use crate::test::test_utils::assert_eq; -use crate::traits::TryInto; - -#[test] -#[should_panic] -fn test_ec_from_zero() { - EcPointTrait::new_from_x(0).expect('Not on curve.'); -} - -#[test] -fn test_ec_operations() { - // Beta + 2 is a square, and for x = 1 and alpha = 1, x^3 + alpha * x + beta = beta + 2. - let beta_p2_root = 2487829544412206244690656897973144572467842667075005257202960243805141046681; - let p = EcPointTrait::new_from_x(1).unwrap(); - let p_nz = p.try_into().unwrap(); - let (x, y) = p_nz.coordinates(); - assert_eq(@x, @1, 'x != 1'); - assert(y == beta_p2_root || y == -beta_p2_root, 'y is wrong'); - - let mut state = EcStateTrait::init(); - state.add(p_nz); - let q = state.finalize_nz().expect('zero point'); - let (qx, qy) = q.coordinates(); - assert_eq(@qx, @x, 'bad finalize x'); - assert_eq(@qy, @y, 'bad finalize y'); - - // Try doing the same thing with the EC op builtin. - let mut state = EcStateTrait::init(); - state.add_mul(1, p_nz); - let q3 = state.finalize_nz().expect('zero point'); - let (qx, qy) = q3.coordinates(); - assert_eq(@qx, @x, 'bad EC op x'); - assert_eq(@qy, @y, 'bad EC op y'); - - // Try computing `p + p` using the ec_mul function. - let double_p = p.mul(2); - let (double_x, double_y) = double_p.try_into().unwrap().coordinates(); - let expected_double_y = - 3572434102142093425782752266058856056057826477682467661647843687948039943621; - assert_eq( - @double_x, - @75984168971785666410219869038140038216102669781812169677875295511117260233, - 'bad double x', - ); - assert(double_y == expected_double_y || double_y == -expected_double_y, 'bad double y'); - - // Compute `2p - p`. - let (sub_x, sub_y) = (double_p - p).try_into().unwrap().coordinates(); - assert_eq(@sub_x, @x, 'bad x for 2p - p'); - assert_eq(@sub_y, @y, 'bad y for 2p - p'); - - // Compute `p - p`. - let p_diff: Option> = (p - p).try_into(); - assert(p_diff.is_none(), 'p - p did not return 0.'); - - // Compute `(-p) - p`. - let (sub2_x, sub2_y) = (-p - p).try_into().unwrap().coordinates(); - assert_eq(@sub2_x, @double_x, 'bad x for (-p) - p'); - assert_eq(@sub2_y, @-double_y, 'bad y for (-p) - p'); -} - -#[test] -#[should_panic] -fn test_bad_ec_point_creation() { - EcPointTrait::new(0, 0).unwrap(); -} - -#[test] -fn test_ec_point_finalization_zero() { - let state = EcStateTrait::init(); - let point_at_infinity = state.finalize_nz(); - assert(point_at_infinity.is_none(), 'Wrong point'); -} - -#[test] -fn test_ecdsa() { - let message_hash = 0x503f4bea29baee10b22a7f10bdc82dda071c977c1f25b8f3973d34e6b03b2c; - let public_key = 0x7b7454acbe7845da996377f85eb0892044d75ae95d04d3325a391951f35d2ec; - let signature_r = 0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb; - let signature_s = 0x677ae6bba6daf00d2631fab14c8acf24be6579f9d9e98f67aa7f2770e57a1f5; - assert!(check_ecdsa_signature(:message_hash, :public_key, :signature_r, :signature_s)); - let other_s = stark_curve::ORDER - signature_s; - assert!(check_ecdsa_signature(:message_hash, :public_key, :signature_r, signature_s: other_s)); - assert!( - !check_ecdsa_signature( - message_hash: message_hash + 1, :public_key, :signature_r, :signature_s, - ), - ); - assert!( - !check_ecdsa_signature( - :message_hash, public_key: public_key + 1, :signature_r, :signature_s, - ), - ); - assert!( - !check_ecdsa_signature( - :message_hash, :public_key, signature_r: signature_r + 1, :signature_s, - ), - ); - assert!( - !check_ecdsa_signature( - :message_hash, :public_key, :signature_r, signature_s: signature_s + 1, - ), - ); -} - -#[test] -fn test_ecdsa_recover_public_key() { - let message_hash = 0x503f4bea29baee10b22a7f10bdc82dda071c977c1f25b8f3973d34e6b03b2c; - let signature_r = 0xbe96d72eb4f94078192c2e84d5230cde2a70f4b45c8797e2c907acff5060bb; - let signature_s = 0x677ae6bba6daf00d2631fab14c8acf24be6579f9d9e98f67aa7f2770e57a1f5; - assert_eq!( - recover_public_key(:message_hash, :signature_r, :signature_s, y_parity: false), - Some(0x7b7454acbe7845da996377f85eb0892044d75ae95d04d3325a391951f35d2ec), - ); - let y_parity = true; - let pk = recover_public_key(:message_hash, :signature_r, :signature_s, :y_parity).unwrap(); - assert!(check_ecdsa_signature(:message_hash, public_key: pk, :signature_r, :signature_s)); - use stark_curve::ORDER as ORD; - assert_eq!(recover_public_key(:message_hash, signature_r: 0, :signature_s, :y_parity), None); - assert_eq!(recover_public_key(:message_hash, signature_r: ORD, :signature_s, :y_parity), None); - assert_eq!(recover_public_key(:message_hash, :signature_r, signature_s: 0, :y_parity), None); - assert_eq!(recover_public_key(:message_hash, :signature_r, signature_s: ORD, :y_parity), None); -} - -#[test] -fn test_ec_mul() { - let p = EcPointTrait::new( - x: 336742005567258698661916498343089167447076063081786685068305785816009957563, - y: 1706004133033694959518200210163451614294041810778629639790706933324248611779, - ) - .unwrap(); - let m = 2713877091499598330239944961141122840311015265600950719674787125185463975936; - let (x, y) = p.mul(m).try_into().unwrap().coordinates(); - - assert_eq( - @x, - @2881632108168892236043523177391659237686965655035240771134509747985978822780, - 'ec_mul failed (x).', - ); - assert_eq( - @y, - @591135563672138037839394207500885413019058613584891498394077262936524140839, - 'ec_mul failed (y).', - ); -} diff --git a/corelib/src/test/felt_test.cairo b/corelib/src/test/felt_test.cairo deleted file mode 100644 index e897d5724a..0000000000 --- a/corelib/src/test/felt_test.cairo +++ /dev/null @@ -1,19 +0,0 @@ -use crate::test::test_utils::assert_eq; - -#[test] -fn test_felt252_operators() { - assert_eq(@(1 + 3), @4, '1 + 3 == 4'); - assert_eq(@(3 + 6), @9, '3 + 6 == 9'); - assert_eq(@(3 - 1), @2, '3 - 1 == 2'); - assert_eq(@(1231 - 231), @1000, '1231-231=1000'); - assert_eq(@(1 * 3), @3, '1 * 3 == 3'); - assert_eq(@(3 * 6), @18, '3 * 6 == 18'); - assert_eq(@(-3), @(1 - 4), '-3 == 1 - 4'); -} - -#[test] -fn test_felt252_clone() { - let felt252_snap = @2; - let felt252_clone = felt252_snap.clone(); - assert_eq(@felt252_clone, @2, 'felt252_clone == 2'); -} diff --git a/corelib/src/test/fmt_test.cairo b/corelib/src/test/fmt_test.cairo deleted file mode 100644 index 87b6b87665..0000000000 --- a/corelib/src/test/fmt_test.cairo +++ /dev/null @@ -1,165 +0,0 @@ -#[feature("byte-span")] -use crate::byte_array::ToByteSpanTrait; - -#[test] -fn test_format() { - let ba: ByteArray = "hello"; - assert(format!("{}", ba) == ba, 'byte array bad formatting'); - let span = ba.span(); - assert(format!("{span}") == ba, 'byte span bad formatting'); - assert(format!("{}", span[1..4]) == "ell", 'byte span slice bad formatting'); - assert(format!("{}", 97_felt252) == "97", 'felt252 bad formatting'); - assert(format!("{}", 97_usize) == "97", 'usize bad formatting'); - assert(format!("{}", 34 - 5) == "29", 'expression bad formatting'); - assert(format!("no_format") == "no_format", 'no args bad formatting'); - assert(format!("{}{}", 12_usize, 14_u32) == "1214", 'two args bad formatting'); - assert(format!("{0}{0}", 12_usize) == "1212", 'positional bad formatting'); - assert(format!("{}{1}", 12_usize, 14_u32) == "1214", 'positional mix bad formatting'); - assert(format!("{ba}_{}_{}_{1}", 12, 14_u32) == "hello_12_14_14", 'full mix bad formatting'); - assert(format!("{{{{}}}}") == "{{}}", 'special cases bad formatting'); - let nz_value: NonZero = 1.try_into().unwrap(); - assert(format!("{}", nz_value) == "1", 'non zero bad formatting'); - assert( - format!("{}_{}_{}_{}_{}_{}", 0_i128, 1_i8, 2_i16, 3_i32, 4_i64, 5_i128) == "0_1_2_3_4_5", - 'signed positive bad formatting', - ); - assert( - format!("{}_{}_{}_{}_{}", -1_i8, -2_i16, -3_i32, -4_i64, -5_i128) == "-1_-2_-3_-4_-5", - 'signed negative bad formatting', - ); -} - -#[derive(Debug, Drop)] -struct StructExample { - felt_value: felt252, - bool_value: bool, - byte_array_value: ByteArray, - enum_value: EnumExample, -} - -#[derive(Debug, Drop)] -enum EnumExample { - Empty, - FeltValue: felt252, - BoolValue: bool, -} - -#[derive(Drop, Copy)] -struct IntoFelt252Based { - felt_value: felt252, -} - -impl IntoFelt252BasedInto of Into { - fn into(self: IntoFelt252Based) -> felt252 { - self.felt_value - } -} - -impl IntoFelt252BasedDebug = core::fmt::into_felt252_based::DebugImpl; -impl IntoFelt252BasedLowerHex = core::fmt::into_felt252_based::LowerHexImpl; - -#[test] -fn test_format_debug() { - let ba: ByteArray = "hello"; - assert(format!("{:?}", ba) == "\"hello\"", 'byte array bad formatting'); - assert(format!("{:?}", ba.span()) == "\"hello\"", 'byte span bad formatting'); - assert(format!("{:?}", ba.span()[1..4]) == "\"ell\"", 'byte span slice bad formatting'); - let ba_64: ByteArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@"; - let span_64 = ba_64.span(); - assert( - format!( - "{span_64:?}", - ) == "\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@\"", - 'long byte span', - ); - assert(format!("{:?}", span_64[20..30]) == "\"UVWXYZabcd\"", 'byte span 64 slice'); - - assert(format!("{:?}", 97_felt252) == "97", 'felt252 bad formatting'); - assert(format!("{:?}", 97_usize) == "97", 'usize bad formatting'); - assert(format!("{:?}{:?}", 12_usize, 14_u32) == "1214", 'two args bad formatting'); - assert(format!("{0:?}{0:?}", 12_usize) == "1212", 'positional bad formatting'); - assert(format!("{:?}{1:?}", 12_usize, 14_u32) == "1214", 'positional mix bad formatting'); - assert( - format!("{ba:?}_{:?}_{:?}_{1:?}", 12, 14_u32) == "\"hello\"_12_14_14", - 'full mix bad formatting', - ); - assert( - format!("{:?}", EnumExample::Empty) == "EnumExample::Empty(())", - 'bad enum empty derive fmt', - ); - assert( - format!("{:?}", EnumExample::FeltValue(4)) == "EnumExample::FeltValue(4)", - 'bad derive enum fmt', - ); - assert( - format!( - "{:?}", - StructExample { - felt_value: 6, - bool_value: false, - byte_array_value: "ByteArray", - enum_value: EnumExample::BoolValue(true), - }, - ) == "StructExample { felt_value: 6, bool_value: false, byte_array_value: \"ByteArray\", enum_value: EnumExample::BoolValue(true) }", - 'bad derive struct formatting', - ); - assert( - format!("{:?}", ((), (1,), (2, 3), (4, 5, 6))) == "((), (1,), (2, 3), (4, 5, 6))", - 'bad tuple fmt', - ); - let empty: [felt252; 0] = []; - assert( - format!("{:?}", (empty, [1], [2, 3], [4, 5, 6])) == "([], [1], [2, 3], [4, 5, 6])", - 'bad fixed sized array fmt', - ); - assert(format!("{:?}", crate::box::BoxTrait::new(1)) == "&1", 'bad box fmt'); - assert( - format!("{:?}", crate::nullable::NullableTrait::new(1)) == "&1", 'bad nullable value fmt', - ); - assert(format!("{:?}", crate::nullable::null::()) == "null", 'bad null fmt'); - - let s = IntoFelt252Based { felt_value: 42 }; - assert(format!("{:?}", s) == "42", 'felt252 based bad formatting'); -} - -#[test] -fn test_array_debug() { - let arr = array![1, 2, 3]; - assert(format!("{:?}", arr) == "[1, 2, 3]", 'bad array fmt'); -} - -#[test] -fn test_format_hex() { - assert(format!("{:x}", 42) == "2a", 'bad felt252 hex formatting'); - assert(format!("{:x}", 42_u8) == "2a", 'bad u8 lower hex formatting'); - assert(format!("{:x}", 42_u16) == "2a", 'bad u16 lower hex formatting'); - assert(format!("{:x}", 48879_u16) == "beef", 'bad u16 lower hex formatting'); - assert(format!("{:x}", 42_u32) == "2a", 'bad u32 lower hex formatting'); - assert(format!("{:x}", 3735928559_u32) == "deadbeef", 'bad u32 lower hex formatting'); - assert(format!("{:x}", 42_u64) == "2a", 'bad u64 lower hex formatting'); - assert( - format!("{:x}", 16045690984833335023_u64) == "deadbeefdeadbeef", - 'bad u64 lower hex formatting', - ); - assert(format!("{:x}", 42_u128) == "2a", 'bad u128 lower hex formatting'); - assert( - format!( - "{:x}", 295990755083049101712519384020072382191_u128, - ) == "deadbeefdeadbeefdeadbeefdeadbeef", - 'bad u128 lower hex formatting', - ); - assert(format!("{:x}", 42_u256) == "2a", 'bad u256 lower hex formatting'); - assert( - format!( - "{:x}", - 100720434726375746010458024839911619878118703404436202866098422983289408962287_u256, - ) == "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", - 'bad u256 lower hex formatting', - ); - - let nz_value: NonZero = 42.try_into().unwrap(); - assert(format!("{:x}", nz_value) == "2a", 'non zero bad formatting'); - - let s = IntoFelt252Based { felt_value: 42 }; - assert(format!("{:x}", s) == "2a", 'felt252 based bad formatting'); -} diff --git a/corelib/src/test/gas_reserve_test.cairo b/corelib/src/test/gas_reserve_test.cairo deleted file mode 100644 index df99b0774d..0000000000 --- a/corelib/src/test/gas_reserve_test.cairo +++ /dev/null @@ -1,29 +0,0 @@ -use core::gas::{GasReserve, gas_reserve_create, gas_reserve_utilize}; - -// Allow implicitly dropping GasReserve instances. -impl GasReserveDrop of Drop {} - -#[test] -fn test_create_and_utilize_gas_reserve() { - let gas0 = crate::testing::get_available_gas(); - - // Buy and redeposit a GasReserve. - let reserve1 = gas_reserve_create(1000).unwrap(); - let gas1 = crate::testing::get_available_gas(); - gas_reserve_utilize(reserve1); - let gas2 = crate::testing::get_available_gas(); - - // Buy the rest of the available gas. - let reserve2 = gas_reserve_create(gas2).unwrap(); - let gas3 = crate::testing::get_available_gas(); - - // Try to buy another reserve. This should fail. - let reserve3_opt = gas_reserve_create(1); - - gas_reserve_utilize(reserve2); - assert!(reserve3_opt.is_none()); - - assert_eq!(gas1, gas0 - 1000); - assert_eq!(gas2, gas0); - assert_eq!(gas3, 0); -} diff --git a/corelib/src/test/hash_test.cairo b/corelib/src/test/hash_test.cairo deleted file mode 100644 index 97d679dbe2..0000000000 --- a/corelib/src/test/hash_test.cairo +++ /dev/null @@ -1,131 +0,0 @@ -use crate::blake::{blake2s_compress, blake2s_finalize}; -use crate::hash::{HashStateExTrait, HashStateTrait}; -use crate::poseidon::PoseidonTrait; -use crate::test::test_utils::assert_eq; - -#[test] -fn test_pedersen_hash() { - assert_eq( - @crate::pedersen::pedersen(1, 2), - @2592987851775965742543459319508348457290966253241455514226127639100457844774, - 'Wrong hash value', - ); -} - -#[test] -fn test_poseidon_hades_permutation() { - let (s0, s1, s2) = crate::poseidon::hades_permutation(1, 2, 3); - assert_eq( - @s0, - @442682200349489646213731521593476982257703159825582578145778919623645026501, - 'wrong s0', - ); - assert_eq( - @s1, - @2233832504250924383748553933071188903279928981104663696710686541536735838182, - 'wrong s1', - ); - assert_eq( - @s2, - @2512222140811166287287541003826449032093371832913959128171347018667852712082, - 'wrong s2', - ); -} - -#[test] -fn test_poseidon_hash_span() { - // Test odd number of inputs. - assert_eq!( - crate::poseidon::poseidon_hash_span([1, 2, 3].span()), - 0x2f0d8840bcf3bc629598d8a6cc80cb7c0d9e52d93dab244bbf9cd0dca0ad082, - ); - - // Test even number of inputs. - assert_eq!( - crate::poseidon::poseidon_hash_span([1, 2, 3, 4].span()), - 0x26e3ad8b876e02bc8a4fc43dad40a8f81a6384083cabffa190bcf40d512ae1d, - ); -} - -#[derive(Hash)] -enum EnumForHash { - First, - Second: felt252, - Third: (felt252, felt252), -} - -#[derive(Hash)] -struct StructForHash { - first: (), - second: felt252, - third: (felt252, felt252), -} - -#[test] -fn test_user_defined_hash() { - assert_eq( - @PoseidonTrait::new().update_with(EnumForHash::First).finalize(), - @PoseidonTrait::new().update(0).finalize(), - 'Bad hash of EnumForHash::First', - ); - assert_eq( - @PoseidonTrait::new().update_with(EnumForHash::Second(5)).finalize(), - @PoseidonTrait::new().update(1).update(5).finalize(), - 'Bad hash of EnumForHash::Second', - ); - assert_eq( - @PoseidonTrait::new().update_with(EnumForHash::Third((6, 8))).finalize(), - @PoseidonTrait::new().update(2).update(6).update(8).finalize(), - 'Bad hash of EnumForHash::Third', - ); - assert_eq( - @PoseidonTrait::new() - .update_with(StructForHash { first: (), second: 10, third: (6, 17) }) - .finalize(), - @PoseidonTrait::new().update(10).update(6).update(17).finalize(), - 'Bad hash of StructForHash', - ); -} - - -#[test] -fn test_blake2s() { - let state = BoxTrait::new([0_u32; 8]); - let msg = BoxTrait::new([0_u32; 16]); - let byte_count = 64_u32; - assert_eq!( - blake2s_compress(state, byte_count, msg).unbox(), - [ - 0xe816e42a, 0x7d9875d8, 0xfda62c55, 0xa2c6f449, 0xca7af611, 0xdd2f7629, 0xbcd92323, - 0x15c3ab3b, - ], - ); - assert_eq!( - blake2s_finalize(state, byte_count, msg).unbox(), - [ - 0x7a59305, 0x56b8b489, 0xbe3bb37e, 0x58ec6ba0, 0x2f53d5d3, 0x26cd7988, 0xde14c740, - 0x3e3f372e, - ], - ); -} - -#[test] -fn test_blake2s_with_abc() { - // hashing `abc` as it is done in RFC 7693 Appendix B. - // Initial state is the IV, with keylen 0 and output length 32. - let state = BoxTrait::new( - [ - 0x6A09E667 ^ (0x01010000 ^ 0x20), 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, - 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, - ], - ); - // Message `abc` padded with zeros. - let msg = BoxTrait::new(['cba', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!( - blake2s_finalize(state, 3, msg).unbox(), - [ - 0x8c5e8c50, 0xe2147c32, 0xa32ba7e1, 0x2f45eb4e, 0x208b4537, 0x293ad69e, 0x4c9b994d, - 0x82596786, - ], - ); -} diff --git a/corelib/src/test/integer_test.cairo b/corelib/src/test/integer_test.cairo deleted file mode 100644 index 879e011c5f..0000000000 --- a/corelib/src/test/integer_test.cairo +++ /dev/null @@ -1,2379 +0,0 @@ -use crate::integer::{self, u512, u512_safe_div_rem_by_u256}; -use crate::num::traits::{Bounded, Pow, Sqrt, WideMul, WideSquare, WrappingSub}; -use crate::test::test_utils::{assert_eq, assert_ge, assert_gt, assert_le, assert_lt, assert_ne}; - -#[test] -fn test_u8_operators() { - assert_eq(@1_u8, @1_u8, '1 == 1'); - assert_ne(@1_u8, @2_u8, '1 != 2'); - assert_eq(@(1_u8 + 3_u8), @4_u8, '1 + 3 == 4'); - assert_eq(@(3_u8 + 6_u8), @9_u8, '3 + 6 == 9'); - assert_eq(@(3_u8 - 1_u8), @2_u8, '3 - 1 == 2'); - assert_eq(@(1_u8 * 3_u8), @3_u8, '1 * 3 == 3'); - assert_eq(@(2_u8 * 4_u8), @8_u8, '2 * 4 == 8'); - assert_eq(@(19_u8 / 7_u8), @2_u8, '19 / 7 == 2'); - assert_eq(@(19_u8 % 7_u8), @5_u8, '19 % 7 == 5'); - assert_eq(@(231_u8 - 131_u8), @100_u8, '231-131=100'); - assert_eq(@((1_u8 | 2_u8)), @3_u8, '1 | 2 == 3'); - assert_eq(@((1_u8 & 2_u8)), @0_u8, '1 & 2 == 0'); - assert_eq(@((1_u8 ^ 2_u8)), @3_u8, '1 ^ 2 == 3'); - assert_eq(@((2_u8 | 2_u8)), @2_u8, '2 | 2 == 2'); - assert_eq(@((2_u8 & 2_u8)), @2_u8, '2 & 2 == 2'); - assert_eq(@((2_u8 & 3_u8)), @2_u8, '2 & 3 == 2'); - assert_eq(@((3_u8 ^ 6_u8)), @5_u8, '3 ^ 6 == 5'); - assert_lt(1_u8, 4_u8, '1 < 4'); - assert_le(1_u8, 4_u8, '1 <= 4'); - assert(!(4_u8 < 4_u8), '!(4 < 4)'); - assert_le(5_u8, 5_u8, '5 <= 5'); - assert(!(5_u8 <= 4_u8), '!(5 <= 4)'); - assert_gt(5_u8, 2_u8, '5 > 2'); - assert_ge(5_u8, 2_u8, '5 >= 2'); - assert(!(3_u8 > 3_u8), '!(3 > 3)'); - assert_ge(3_u8, 3_u8, '3 >= 3'); - assert!(9_u8.sqrt() == 3); - assert!(10_u8.sqrt() == 3); - assert!(0x40_u8.sqrt() == 0x8); - assert!(0xff_u8.sqrt() == 0xf); - assert!(1_u8.sqrt() == 1); - assert!(0_u8.sqrt() == 0); - assert_eq(@~0x00_u8, @0xff, '~0x00 == 0xff'); - assert_eq(@~0x81_u8, @0x7e, '~0x81 == 0x7e'); -} - -#[test] -#[should_panic] -fn test_u8_sub_overflow_1() { - 0_u8 - 1_u8; -} - -#[test] -#[should_panic] -fn test_u8_sub_overflow_2() { - 0_u8 - 3_u8; -} - -#[test] -#[should_panic] -fn test_u8_sub_overflow_3() { - 1_u8 - 3_u8; -} - -#[test] -#[should_panic] -fn test_u8_sub_overflow_4() { - 100_u8 - 250_u8; -} - -#[test] -#[should_panic] -fn test_u8_add_overflow_1() { - 128_u8 + 128_u8; -} - -#[test] -#[should_panic] -fn test_u8_add_overflow_2() { - 200_u8 + 60_u8; -} - -#[test] -#[should_panic] -fn test_u8_mul_overflow_1() { - 0x10_u8 * 0x10_u8; -} - -#[test] -#[should_panic] -fn test_u8_mul_overflow_2() { - 0x11_u8 * 0x10_u8; -} - -#[test] -#[should_panic] -fn test_u8_mul_overflow_3() { - 2_u8 * 0x80_u8; -} - -#[test] -#[should_panic(expected: ('Division by 0',))] -fn test_u8_div_by_0() { - 2_u8 / 0_u8; -} - -#[test] -#[should_panic] -fn test_u8_mod_by_0() { - 2_u8 % 0_u8; -} - -#[test] -fn test_u16_operators() { - assert_eq(@1_u16, @1_u16, '1 == 1'); - assert_ne(@1_u16, @2_u16, '1 != 2'); - assert_eq(@(1_u16 + 3_u16), @4_u16, '1 + 3 == 4'); - assert_eq(@(3_u16 + 6_u16), @9_u16, '3 + 6 == 9'); - assert_eq(@(3_u16 - 1_u16), @2_u16, '3 - 1 == 2'); - assert_eq(@(231_u16 - 131_u16), @100_u16, '231-131=100'); - assert_eq(@(1_u16 * 3_u16), @3_u16, '1 * 3 == 3'); - assert_eq(@(2_u16 * 4_u16), @8_u16, '2 * 4 == 8'); - assert_eq(@(51725_u16 / 7_u16), @7389_u16, '51725 / 7 == 7389'); - assert_eq(@(51725_u16 % 7_u16), @2_u16, '51725 % 7 == 2'); - assert_eq(@((1_u16 | 2_u16)), @3_u16, '1 | 2 == 3'); - assert_eq(@((1_u16 & 2_u16)), @0_u16, '1 & 2 == 0'); - assert_eq(@((1_u16 ^ 2_u16)), @3_u16, '1 ^ 2 == 3'); - assert_eq(@((2_u16 | 2_u16)), @2_u16, '2 | 2 == 2'); - assert_eq(@((2_u16 & 2_u16)), @2_u16, '2 & 2 == 2'); - assert_eq(@((2_u16 & 3_u16)), @2_u16, '2 & 3 == 2'); - assert_eq(@((3_u16 ^ 6_u16)), @5_u16, '3 ^ 6 == 5'); - assert_lt(1_u16, 4_u16, '1 < 4'); - assert_le(1_u16, 4_u16, '1 <= 4'); - assert(!(4_u16 < 4_u16), '!(4 < 4)'); - assert_le(4_u16, 4_u16, '4 <= 4'); - assert_gt(5_u16, 2_u16, '5 > 2'); - assert_ge(5_u16, 2_u16, '5 >= 2'); - assert(!(3_u16 > 3_u16), '!(3 > 3)'); - assert_ge(3_u16, 3_u16, '3 >= 3'); - assert!(9_u16.sqrt() == 3); - assert!(10_u16.sqrt() == 3); - assert!(0x400_u16.sqrt() == 0x20); - assert!(0xffff_u16.sqrt() == 0xff); - assert!(1_u16.sqrt() == 1); - assert!(0_u16.sqrt() == 0); - assert_eq(@~0x0000_u16, @0xffff, '~0x0000 == 0xffff'); - assert_eq(@~0x8421_u16, @0x7bde, '~0x8421 == 0x7bde'); -} - -#[test] -#[should_panic] -fn test_u16_sub_overflow_1() { - 0_u16 - 1_u16; -} - -#[test] -#[should_panic] -fn test_u16_sub_overflow_2() { - 0_u16 - 3_u16; -} - -#[test] -#[should_panic] -fn test_u16_sub_overflow_3() { - 1_u16 - 3_u16; -} - -#[test] -#[should_panic] -fn test_u16_sub_overflow_4() { - 100_u16 - 250_u16; -} - -#[test] -#[should_panic] -fn test_u16_add_overflow_1() { - 0x8000_u16 + 0x8000_u16; -} - -#[test] -#[should_panic] -fn test_u16_add_overflow_2() { - 0x9000_u16 + 0x8001_u16; -} - -#[test] -#[should_panic] -fn test_u16_mul_overflow_1() { - 0x100_u16 * 0x100_u16; -} - -#[test] -#[should_panic] -fn test_u16_mul_overflow_2() { - 0x101_u16 * 0x100_u16; -} - -#[test] -#[should_panic] -fn test_u16_mul_overflow_3() { - 2_u16 * 0x8000_u16; -} - -#[test] -#[should_panic(expected: ('Division by 0',))] -fn test_u16_div_by_0() { - 2_u16 / 0_u16; -} - -#[test] -#[should_panic] -fn test_u16_mod_by_0() { - 0_u16 % 0_u16; -} - -#[test] -fn test_u32_operators() { - assert_eq(@1_u32, @1_u32, '1 == 1'); - assert_ne(@1_u32, @2_u32, '1 != 2'); - assert_eq(@(1_u32 + 3_u32), @4_u32, '1 + 3 == 4'); - assert_eq(@(3_u32 + 6_u32), @9_u32, '3 + 6 == 9'); - assert_eq(@(3_u32 - 1_u32), @2_u32, '3 - 1 == 2'); - assert_eq(@(231_u32 - 131_u32), @100_u32, '231-131=100'); - assert_eq(@(1_u32 * 3_u32), @3_u32, '1 * 3 == 3'); - assert_eq(@(2_u32 * 4_u32), @8_u32, '2 * 4 == 8'); - assert_eq(@(510670725_u32 / 7_u32), @72952960_u32, '510670725 / 7 == 72952960'); - assert_eq(@(510670725_u32 % 7_u32), @5_u32, '510670725 % 7 == 5'); - assert_eq(@((1_u32 | 2_u32)), @3_u32, '1 | 2 == 3'); - assert_eq(@((1_u32 & 2_u32)), @0_u32, '1 & 2 == 0'); - assert_eq(@((1_u32 ^ 2_u32)), @3_u32, '1 ^ 2 == 3'); - assert_eq(@((2_u32 | 2_u32)), @2_u32, '2 | 2 == 2'); - assert_eq(@((2_u32 & 2_u32)), @2_u32, '2 & 2 == 2'); - assert_eq(@((2_u32 & 3_u32)), @2_u32, '2 & 3 == 2'); - assert_eq(@((3_u32 ^ 6_u32)), @5_u32, '3 ^ 6 == 5'); - assert_lt(1_u32, 4_u32, '1 < 4'); - assert_le(1_u32, 4_u32, '1 <= 4'); - assert(!(4_u32 < 4_u32), '!(4 < 4)'); - assert_le(4_u32, 4_u32, '4 <= 4'); - assert_gt(5_u32, 2_u32, '5 > 2'); - assert_ge(5_u32, 2_u32, '5 >= 2'); - assert(!(3_u32 > 3_u32), '!(3 > 3)'); - assert_ge(3_u32, 3_u32, '3 >= 3'); - assert!(9_u32.sqrt() == 3); - assert!(10_u32.sqrt() == 3); - assert!(0x100000_u32.sqrt() == 0x400); - assert!(0xffffffff_u32.sqrt() == 0xffff); - assert!(1_u32.sqrt() == 1); - assert!(0_u32.sqrt() == 0); - assert_eq(@~0x00000000_u32, @0xffffffff, '~0x00000000 == 0xffffffff'); - assert_eq(@~0x12345678_u32, @0xedcba987, '~0x12345678 == 0xedcba987'); -} - -#[test] -#[should_panic] -fn test_u32_sub_overflow_1() { - 0_u32 - 1_u32; -} - -#[test] -#[should_panic] -fn test_u32_sub_overflow_2() { - 0_u32 - 3_u32; -} - -#[test] -#[should_panic] -fn test_u32_sub_overflow_3() { - 1_u32 - 3_u32; -} - -#[test] -#[should_panic] -fn test_u32_sub_overflow_4() { - 100_u32 - 250_u32; -} - -#[test] -#[should_panic] -fn test_u32_add_overflow_1() { - 0x80000000_u32 + 0x80000000_u32; -} - -#[test] -#[should_panic] -fn test_u32_add_overflow_2() { - 0x90000000_u32 + 0x80000001_u32; -} - -#[test] -#[should_panic] -fn test_u32_mul_overflow_1() { - 0x10000_u32 * 0x10000_u32; -} - -#[test] -#[should_panic] -fn test_u32_mul_overflow_2() { - 0x10001_u32 * 0x10000_u32; -} - -#[test] -#[should_panic] -fn test_u32_mul_overflow_3() { - 2_u32 * 0x80000000_u32; -} - -#[test] -#[should_panic(expected: ('Division by 0',))] -fn test_u32_div_by_0() { - 2_u32 / 0_u32; -} - -#[test] -#[should_panic] -fn test_u32_mod_by_0() { - 0_u32 % 0_u32; -} - -#[test] -fn test_u64_operators() { - assert_eq(@1_u64, @1_u64, '1 == 1'); - assert_ne(@1_u64, @2_u64, '1 != 2'); - assert_eq(@(1_u64 + 3_u64), @4_u64, '1 + 3 == 4'); - assert_eq(@(3_u64 + 6_u64), @9_u64, '3 + 6 == 9'); - assert_eq(@(3_u64 - 1_u64), @2_u64, '3 - 1 == 2'); - assert_eq(@(231_u64 - 131_u64), @100_u64, '231-131=100'); - assert_eq(@(1_u64 * 3_u64), @3_u64, '1 * 3 == 3'); - assert_eq(@(2_u64 * 4_u64), @8_u64, '2 * 4 == 8'); - assert_eq( - @(5010670477878974275_u64 / 7_u64), @715810068268424896_u64, 'Wrong division result.', - ); - assert_eq(@(5010670477878974275_u64 % 7_u64), @3_u64, '5010670477878974275 % 7 == 3'); - assert_eq(@((1_u64 | 2_u64)), @3_u64, '1 | 2 == 3'); - assert_eq(@((1_u64 & 2_u64)), @0_u64, '1 & 2 == 0'); - assert_eq(@((1_u64 ^ 2_u64)), @3_u64, '1 ^ 2 == 3'); - assert_eq(@((2_u64 | 2_u64)), @2_u64, '2 | 2 == 2'); - assert_eq(@((2_u64 & 2_u64)), @2_u64, '2 & 2 == 2'); - assert_eq(@((2_u64 & 3_u64)), @2_u64, '2 & 3 == 2'); - assert_eq(@((3_u64 ^ 6_u64)), @5_u64, '3 ^ 6 == 5'); - assert_lt(1_u64, 4_u64, '1 < 4'); - assert_le(1_u64, 4_u64, '1 <= 4'); - assert(!(4_u64 < 4_u64), '!(4 < 4)'); - assert_le(4_u64, 4_u64, '4 <= 4'); - assert_gt(5_u64, 2_u64, '5 > 2'); - assert_ge(5_u64, 2_u64, '5 >= 2'); - assert(!(3_u64 > 3_u64), '!(3 > 3)'); - assert_ge(3_u64, 3_u64, '3 >= 3'); - assert!(9_u64.sqrt() == 3); - assert!(10_u64.sqrt() == 3); - assert!(0x10000000000_u64.sqrt() == 0x100000); - assert!(0xffffffffffffffff_u64.sqrt() == 0xffffffff); - assert!(1_u64.sqrt() == 1); - assert!(0_u64.sqrt() == 0); - assert_eq(@~0x0000000000000000_u64, @0xffffffffffffffff, '~0x0..0 == 0xf..f'); - assert_eq(@~0x123456789abcdef1_u64, @0xedcba9876543210e, '~0x12..ef1 == 0xed..10e'); -} - -#[test] -#[should_panic] -fn test_u64_sub_overflow_1() { - 0_u64 - 1_u64; -} - -#[test] -#[should_panic] -fn test_u64_sub_overflow_2() { - 0_u64 - 3_u64; -} - -#[test] -#[should_panic] -fn test_u64_sub_overflow_3() { - 1_u64 - 3_u64; -} - -#[test] -#[should_panic] -fn test_u64_sub_overflow_4() { - 100_u64 - 250_u64; -} - -#[test] -#[should_panic] -fn test_u64_add_overflow_1() { - 0x8000000000000000_u64 + 0x8000000000000000_u64; -} - -#[test] -#[should_panic] -fn test_u64_add_overflow_2() { - 0x9000000000000000_u64 + 0x8000000000000001_u64; -} - -#[test] -#[should_panic] -fn test_u64_mul_overflow_1() { - 0x100000000_u64 * 0x100000000_u64; -} - -#[test] -#[should_panic] -fn test_u64_mul_overflow_2() { - 0x100000001_u64 * 0x100000000_u64; -} - -#[test] -#[should_panic] -fn test_u64_mul_overflow_3() { - 2_u64 * 0x8000000000000000_u64; -} - -#[test] -#[should_panic(expected: ('Division by 0',))] -fn test_u64_div_by_0() { - 2_u64 / 0_u64; -} - -#[test] -#[should_panic] -fn test_u64_mod_by_0() { - 0_u64 % 0_u64; -} - -#[test] -fn test_u128_operators() { - assert_eq(@1_u128, @1_u128, '1 == 1'); - assert_ne(@1_u128, @2_u128, '1 != 2'); - assert_eq(@(1_u128 + 3_u128), @4_u128, '1 + 3 == 4'); - assert_eq(@(3_u128 + 6_u128), @9_u128, '3 + 6 == 9'); - assert_eq(@(3_u128 - 1_u128), @2_u128, '3 - 1 == 2'); - assert_eq(@(1231_u128 - 231_u128), @1000_u128, '1231-231=1000'); - assert_eq(@(1_u128 * 3_u128), @3_u128, '1 * 3 == 3'); - assert_eq(@(2_u128 * 4_u128), @8_u128, '2 * 4 == 8'); - assert_eq(@(8_u128 / 2_u128), @4_u128, '8 / 2 == 4'); - assert_eq(@(8_u128 % 2_u128), @0_u128, '8 % 2 == 0'); - assert_eq(@(7_u128 / 3_u128), @2_u128, '7 / 3 == 2'); - assert_eq(@(7_u128 % 3_u128), @1_u128, '7 % 3 == 1'); - assert_lt(1_u128, 4_u128, '1 < 4'); - assert_le(1_u128, 4_u128, '1 <= 4'); - assert(!(4_u128 < 4_u128), '!(4 < 4)'); - assert_le(4_u128, 4_u128, '4 <= 4'); - assert_gt(5_u128, 2_u128, '5 > 2'); - assert_ge(5_u128, 2_u128, '5 >= 2'); - assert(!(3_u128 > 3_u128), '!(3 > 3)'); - assert_ge(3_u128, 3_u128, '3 >= 3'); - assert_eq(@((1_u128 | 2_u128)), @3_u128, '1 | 2 == 3'); - assert_eq(@((1_u128 & 2_u128)), @0_u128, '1 & 2 == 0'); - assert_eq(@((1_u128 ^ 2_u128)), @3_u128, '1 ^ 2 == 3'); - assert_eq(@((2_u128 | 2_u128)), @2_u128, '2 | 2 == 2'); - assert_eq(@((2_u128 & 2_u128)), @2_u128, '2 & 2 == 2'); - assert_eq(@((2_u128 & 3_u128)), @2_u128, '2 & 3 == 2'); - assert_eq(@((3_u128 ^ 6_u128)), @5_u128, '3 ^ 6 == 5'); - assert!(9_u128.sqrt() == 3); - assert!(10_u128.sqrt() == 3); - assert!(0x10000000000000000000000000_u128.sqrt() == 0x4000000000000); - assert!(0xffffffffffffffffffffffffffffffff_u128.sqrt() == 0xffffffffffffffff); - assert!(1_u128.sqrt() == 1); - assert!(0_u128.sqrt() == 0); - assert_eq( - @~0x00000000000000000000000000000000_u128, - @0xffffffffffffffffffffffffffffffff, - '~0x0..0 == 0xf..f', - ); - assert_eq( - @~0x123456789abcdef123456789abcdef12_u128, - @0xedcba9876543210edcba9876543210ed, - '~0x12..ef12 == 0xed..10ed', - ); -} - -fn pow_2_64() -> u128 { - 0x10000000000000000_u128 -} - -#[test] -#[should_panic] -fn test_u128_sub_overflow_1() { - 0_u128 - 1_u128; -} - -#[test] -#[should_panic] -fn test_u128_sub_overflow_2() { - 0_u128 - 3_u128; -} - -#[test] -#[should_panic] -fn test_u128_sub_overflow_3() { - 1_u128 - 3_u128; -} - -#[test] -#[should_panic] -fn test_u128_sub_overflow_4() { - 100_u128 - 1000_u128; -} - -#[test] -fn test_u128_wrapping_sub_1() { - assert!(0.wrapping_sub(1) == Bounded::::MAX); -} - -#[test] -fn test_u128_wrapping_sub_2() { - assert!(0.wrapping_sub(3) == Bounded::::MAX - 2); -} - -#[test] -fn test_u128_wrapping_sub_3() { - assert!(100.wrapping_sub(1000) == Bounded::::MAX - 899); -} - -#[test] -fn test_u128_wrapping_sub_4() { - assert!(0.wrapping_sub(0) == 0_u128); -} - -#[test] -#[should_panic] -fn test_u128_add_overflow_1() { - 0x80000000000000000000000000000000_u128 + 0x80000000000000000000000000000000_u128; -} - -#[test] -#[should_panic] -fn test_u128_add_overflow_2() { - (0x80000000000000000000000000000000_u128 + 12_u128) + 0x80000000000000000000000000000000_u128; -} - -#[test] -#[should_panic] -fn test_u128_mul_overflow_1() { - pow_2_64() * pow_2_64(); -} - -#[test] -#[should_panic] -fn test_u128_mul_overflow_2() { - (pow_2_64() + 1_u128) * pow_2_64(); -} - -#[test] -#[should_panic] -fn test_u128_mul_overflow_3() { - 2_u128 * 0x80000000000000000000000000000000_u128; -} - -#[test] -#[should_panic(expected: ('Division by 0',))] -fn test_u128_div_by_0() { - 2_u128 / 0_u128; -} - -#[test] -#[should_panic] -fn test_u128_mod_by_0() { - 2_u128 % 0_u128; -} - -fn pow_2_127() -> u256 { - 0x80000000000000000000000000000000_u256 -} - -#[test] -fn test_u256_from_felt252() { - assert_eq(@1.into(), @1_u256, 'into 1'); - assert_eq( - @(170141183460469231731687303715884105728 * 2).into(), - @0x100000000000000000000000000000000_u256, - 'into 2**128', - ); -} - -#[test] -fn test_u256_operators() { - let max_u128: u256 = Bounded::::MAX.into(); - assert!( - 0x100000000000000000000000000000001 - + 0x300000000000000000000000000000002 == 0x400000000000000000000000000000003_u256, - ); - assert!( - 0x180000000000000000000000000000000 - + 0x380000000000000000000000000000000 == 0x500000000000000000000000000000000_u256, - ); - assert!( - 0x400000000000000000000000000000003 - - 0x100000000000000000000000000000001 == 0x300000000000000000000000000000002_u256, - ); - assert!( - 0x500000000000000000000000000000000 - - 0x180000000000000000000000000000000 == 0x380000000000000000000000000000000_u256, - ); - assert!(0x400000000000000000000000000000003 * 1 == 0x400000000000000000000000000000003_u256); - assert!(0x400000000000000000000000000000003 * 2 == 0x800000000000000000000000000000006_u256); - assert!(0x80000000000000000000000000000000 * 2 == 0x100000000000000000000000000000000_u256); - assert!( - max_u128 * max_u128 == 0xfffffffffffffffffffffffffffffffe00000000000000000000000000000001, - ); - assert!(max_u128 * 1 == max_u128); - assert!(1 * max_u128 == max_u128); - let v0_2: u256 = 0x000000000000000000000000000000002; - let v0_3: u256 = 0x000000000000000000000000000000003; - let v1_1: u256 = 0x100000000000000000000000000000001; - let v1_2: u256 = 0x100000000000000000000000000000002; - let v2_0: u256 = 0x200000000000000000000000000000000; - let v2_1: u256 = 0x200000000000000000000000000000001; - let v2_2: u256 = 0x200000000000000000000000000000002; - let v2_3: u256 = 0x200000000000000000000000000000003; - let v3_0: u256 = 0x300000000000000000000000000000000; - let v3_2: u256 = 0x300000000000000000000000000000002; - assert!(v1_2 | v2_2 == v3_2); - assert!(v2_1 | v2_2 == v2_3); - assert!(v2_2 | v1_2 == v3_2); - assert!(v2_2 | v2_1 == v2_3); - assert!(v1_2 & v2_2 == v0_2); - assert!(v2_1 & v2_2 == v2_0); - assert!(v2_2 & v1_2 == v0_2); - assert!(v2_2 & v2_1 == v2_0); - assert!(v1_2 ^ v2_2 == v3_0); - assert!(v2_1 ^ v2_2 == v0_3); - assert!(v2_2 ^ v1_2 == v3_0); - assert!(v2_2 ^ v2_1 == v0_3); - assert!(v1_2 < v2_2); - assert!(v2_1 < v2_2); - assert!(v2_2 >= v1_2); - assert!(v2_2 >= v2_1); - assert!(v2_2 >= v2_2); - assert!(v1_2 <= v2_2); - assert!(v2_1 <= v2_2); - assert!(v2_2 > v1_2); - assert!(v2_2 > v2_1); - assert!(v2_2 <= v2_2); - assert!(v1_2 <= v2_2); - assert!(v2_1 <= v2_2); - assert!(v2_2 > v1_2); - assert!(v2_2 > v2_1); - assert!(v2_2 <= v2_2); - assert!(v1_2 < v2_2); - assert!(v2_1 < v2_2); - assert!(v2_2 >= v1_2); - assert!(v2_2 >= v2_1); - assert!(v2_2 >= v2_2); - - assert!(v3_2 / v1_1 == v0_2); - assert!(0x400000000000000000000000000000002 / 3 == 0x155555555555555555555555555555556_u256); - assert!(0x400000000000000000000000000000002 % 3 == 0_u256); - assert!(0x10000000000000000 / 0x10000000000000000 == 1_u256); - assert!(0x10000000000000000 % 0x10000000000000000 == 0_u256); - assert!( - 0x1000000000000000000000000000000000000000000000000 - / 0x1000000000000000000000000000000000000000000000000 == 1_u256, - ); - assert!( - 0x1000000000000000000000000000000000000000000000000 % 0x1000000000000000000000000000000000000000000000000 == 0_u256, - ); - assert!(Bounded::::MAX % 0x100000000 == 0xffffffff); - assert!(Bounded::::MAX % 0x10000000000000000 == 0xffffffffffffffff); - assert!( - Bounded::::MAX - / 0x10000000000000000000000000000000000000000 == 0xffffffffffffffffffffffff, - ); - assert!( - Bounded::::MAX - / 0x1000000000000000000000000000000000000000000000000 == 0xffffffffffffffff, - ); - assert!(~max_u128 == 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000); - assert!(~0xffffffffffffffffffffffffffffffff00000000000000000000000000000000 == max_u128); -} - -#[test] -#[should_panic] -fn test_u256_add_overflow() { - let v = 0x8000000000000000000000000000000000000000000000000000000000000001_u256; - v + v; -} - -#[test] -#[should_panic] -fn test_u256_sub_overflow() { - 0x100000000000000000000000000000001_u256 - 0x100000000000000000000000000000002; -} - -#[test] -#[should_panic] -fn test_u256_mul_overflow_1() { - 0x100000000000000000000000000000001_u256 * 0x100000000000000000000000000000002; -} - -#[test] -#[should_panic] -fn test_u256_mul_overflow_2() { - pow_2_127() * 0x200000000000000000000000000000000; -} - -#[test] -fn test_u256_wide_mul() { - assert!(0_u256.wide_mul(0_u256) == u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }); - assert!( - 0x1001001001001001001001001001001001001001001001001001_u256 - .wide_mul( - 0x1000100010001000100010001000100010001000100010001000100010001_u256, - ) == u512 { - limb0: 0x33233223222222122112111111011001, - limb1: 0x54455445544554454444443443343333, - limb2: 0x21222222322332333333433443444444, - limb3: 0x1001101111112112, - }, - ); -} - -#[test] -fn test_u256_wide_square() { - assert!(0_u256.wide_square() == u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }); - assert!( - 0x1001001001001001001001001001001001001001001001001001_u256 - .wide_square() == u512 { - limb0: 0x0b00a009008007006005004003002001, - limb1: 0xe00f01001101201101000f00e00d00c0, - limb2: 0x00400500600700800900a00b00c00d00, - limb3: 0x1002003, - }, - ); - assert!( - 0x1000100010001000100010001000100010001000100010001000100010001_u256 - .wide_square() == u512 { - limb0: 0x00080007000600050004000300020001, - limb1: 0x0010000f000e000d000c000b000a0009, - limb2: 0x00080009000a000b000c000d000e000f, - limb3: 0x1000200030004000500060007, - }, - ); -} - -#[test] -fn test_u512_safe_div_rem_by_u256() { - let zero = u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }; - assert!(u512_safe_div_rem_by_u256(zero, 1) == (zero, 0)); - let one = u512 { limb0: 1, limb1: 0, limb2: 0, limb3: 0 }; - assert!(u512_safe_div_rem_by_u256(one, 1) == (one, 0)); - let large_num = u512 { - limb0: 0x33233223222222122112111111011001, - limb1: 0x54455445544554454444443443343333, - limb2: 0x21222222322332333333433443444444, - limb3: 0x1001101111112112, - }; - assert!(u512_safe_div_rem_by_u256(large_num, 1) == (large_num, 0)); - assert!( - u512_safe_div_rem_by_u256( - large_num, 0x33233223222222122112111111011001, - ) == ( - u512 { - limb0: 0x365ec98ac1c2c57afaff780a20a0b2b1, - limb1: 0xf3dfa68ede27c4236ef0c6eb66a8e0a2, - limb2: 0x501e5b7ba7f4ec12, - limb3: 0, - }, - 0x1e0eb905027d0150d2618bbd71844d50, - ), - ); -} - -#[test] -fn test_u512_try_into_u256() { - assert!( - u512 { limb0: 1, limb1: 2, limb2: 0, limb3: 0 } - .try_into() == Some(0x200000000000000000000000000000001_u256), - ); - assert!(u512 { limb0: 1, limb1: 2, limb2: 3, limb3: 0 }.try_into() == Option::::None); - assert!(u512 { limb0: 1, limb1: 2, limb2: 0, limb3: 4 }.try_into() == Option::::None); - assert!(u512 { limb0: 1, limb1: 2, limb2: 3, limb3: 4 }.try_into() == Option::::None); -} - -#[test] -fn test_min() { - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == 0); - assert!(Bounded::::MIN == -0x80); - assert!(Bounded::::MIN == -0x8000); - assert!(Bounded::::MIN == -0x80000000); - assert!(Bounded::::MIN == -0x8000000000000000); - assert!(Bounded::::MIN == -0x80000000000000000000000000000000); -} - -#[test] -fn test_max() { - assert!(Bounded::::MAX == 0xff); - assert!(Bounded::::MAX == 0xffff); - assert!(Bounded::::MAX == 0xffffffff); - assert!(Bounded::::MAX == 0xffffffffffffffff); - assert!(Bounded::::MAX == 0xffffffffffffffffffffffffffffffff); - assert!( - Bounded::::MAX == 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - assert!(Bounded::::MAX == 0x7f); - assert!(Bounded::::MAX == 0x7fff); - assert!(Bounded::::MAX == 0x7fffffff); - assert!(Bounded::::MAX == 0x7fffffffffffffff); - assert!(Bounded::::MAX == 0x7fffffffffffffffffffffffffffffff); -} - -#[test] -#[should_panic] -fn test_max_u8_plus_1_overflow() { - Bounded::MAX + 1_u8; -} - -#[test] -#[should_panic] -fn test_max_u16_plus_1_overflow() { - Bounded::MAX + 1_u16; -} - -#[test] -#[should_panic] -fn test_max_u32_plus_1_overflow() { - Bounded::MAX + 1_u32; -} -#[test] -#[should_panic] -fn test_max_u64_plus_1_overflow() { - Bounded::MAX + 1_u64; -} - -#[test] -#[should_panic] -fn test_max_u128_plus_1_overflow() { - Bounded::MAX + 1_u128; -} - -#[test] -#[should_panic] -fn test_max_u256_plus_1_overflow() { - Bounded::MAX + Into::::into(1); -} - -#[test] -fn test_default_values() { - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); - assert!(Default::::default() == 0); -} - -#[test] -fn test_default_felt252dict_values() { - assert!(Felt252DictValue::::zero_default() == 0); - assert!(Felt252DictValue::::zero_default() == 0); - assert!(Felt252DictValue::::zero_default() == 0); - assert!(Felt252DictValue::::zero_default() == 0); - assert!(Felt252DictValue::::zero_default() == 0); - assert!(Felt252DictValue::::zero_default() == 0); -} - -#[test] -fn test_u256_sqrt() { - assert!(9_u256.sqrt() == 3); - assert!(10_u256.sqrt() == 3); - assert!(1267650600228229401496703205376_u256.sqrt() == 1125899906842624); - assert!(340282366920938463463374607431768211455_u256.sqrt() == 18446744073709551615); - assert!(1_u256.sqrt() == 1); - assert!(0_u256.sqrt() == 0); - assert!(Bounded::::MAX.sqrt() == Bounded::::MAX); - assert!(Bounded::::MAX.wide_square().sqrt() == Bounded::::MAX); -} - -#[test] -fn test_u256_try_into_felt252() { - assert_eq(@1_u256.try_into().unwrap(), @1_felt252, '1 == 1'_felt252); - assert_eq( - @0x800000000000011000000000000000000000000000000000000000000000000_u256.try_into().unwrap(), - @0x800000000000011000000000000000000000000000000000000000000000000_felt252, - 'P-1 == P-1'_felt252, - ); - assert_eq( - @0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffff_u256.try_into().unwrap(), - @0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffff_felt252, - 'P-2 == P-2'_felt252, - ); - let f: Option = 0x800000000000011000000000000000000000000000000000000000000000001_u256 - .try_into(); - assert(f.is_none(), 'prime is not felt252'); - let f: Option = 0x800000000000011000000000000000000000000000000000000000000000002_u256 - .try_into(); - assert(f.is_none(), 'prime+1 is not felt252'); - let f: Option = 0x800000000000011000000000000000100000000000000000000000000000001_u256 - .try_into(); - assert(f.is_none(), 'prime+2**128 is not felt252'); -} - -/// Checks if `b` is out of range of `A`. -fn is_out_of_range, +TryInto>(b: B) -> bool { - let no_a: Option = b.try_into(); - no_a.is_none() -} - -/// Checks if `SubType` is trivially castable to `SuperType`. -fn cast_subtype_valid< - SubType, - SuperType, - +Drop, - +Drop, - +Copy, - +Copy, - +Bounded, - +PartialEq, - +PartialEq, - +Into, - +TryInto, ->() -> bool { - let max_sub: SubType = Bounded::MAX; - let max_sub_as_super: SuperType = max_sub.into(); - let min_sub: SubType = Bounded::MIN; - let min_sub_as_super: SuperType = min_sub.into(); - min_sub_as_super.try_into().unwrap() == min_sub - && max_sub_as_super.try_into().unwrap() == max_sub -} - -/// Checks that `A::MAX` is castable to `B`, and `A::MAX + 1` is in `B`s range, and not -/// castable back to `A`. -fn validate_max_strictly_contained< - A, - B, - +Drop, - +Drop, - +Copy, - +Copy, - +Add, - +Bounded, - +PartialEq, - +PartialEq, - +TryInto, - +TryInto, - +TryInto, ->( - err: felt252, -) { - let max_a: A = Bounded::MAX; - let max_a_as_b: B = max_a.try_into().expect(err); - assert(Some(max_a) == max_a_as_b.try_into(), err); - assert(is_out_of_range::(max_a_as_b + 1.try_into().unwrap()), err); -} - -/// Checks that `A::min()` is castable to `B`, and `A::min() - 1` is in `B`s range, and not -/// castable back to `A`. -fn validate_min_strictly_contained< - A, - B, - +Drop, - +Drop, - +Copy, - +Copy, - +Sub, - +Bounded, - +PartialEq, - +PartialEq, - +TryInto, - +TryInto, - +TryInto, ->( - err: felt252, -) { - let min_sub: A = Bounded::MIN; - let min_sub_as_super: B = min_sub.try_into().expect(err); - assert(Some(min_sub) == min_sub_as_super.try_into(), err); - assert(is_out_of_range::(min_sub_as_super - 1.try_into().unwrap()), err); -} - -/// Checks that castings from `SubType` to `SuperType` are correct around the bounds, where -/// `SubType` is strictly contained (in both bounds) in `SuperType`. -fn validate_cast_bounds_strictly_contained< - SubType, - SuperType, - +Drop, - +Drop, - +Copy, - +Copy, - +Add, - +Sub, - +Bounded, - +PartialEq, - +PartialEq, - +Into, - +TryInto, - +TryInto, ->( - err: felt252, -) { - assert(cast_subtype_valid::(), err); - validate_min_strictly_contained::(err); - validate_max_strictly_contained::(err); -} - -/// Checks that castings from `SubType` to `SuperType` are correct around the bounds, where -/// `SubType` has the same min as `SuperType`, but has a lower max. -fn validate_cast_bounds_contained_same_min< - SubType, - SuperType, - +Drop, - +Drop, - +Copy, - +Copy, - +Add, - +Sub, - +Bounded, - +Bounded, - +PartialEq, - +PartialEq, - +Into, - +TryInto, - +TryInto, ->( - err: felt252, -) { - assert(cast_subtype_valid::(), err); - assert(Bounded::::MIN.into() == Bounded::::MIN, err); - validate_max_strictly_contained::(err); -} - -/// Checks that castings from `A` to `B` are correct around the bounds. -/// Assumes that the ordering of the bounds is: `a_min < b_min < a_max < b_max`. -fn validate_cast_bounds_overlapping< - A, - B, - +Drop, - +Drop, - +Copy, - +Copy, - +Sub, - +Add, - +Bounded, - +Bounded, - +PartialEq, - +PartialEq, - +TryInto, - +TryInto, - +TryInto, - +TryInto, ->( - err: felt252, -) { - validate_min_strictly_contained::(err); - validate_max_strictly_contained::(err); -} - -#[test] -fn proper_cast() { - validate_cast_bounds_contained_same_min::('u8 u16 casts'); - validate_cast_bounds_contained_same_min::('u8 u32 casts'); - validate_cast_bounds_contained_same_min::('u8 u64 casts'); - validate_cast_bounds_contained_same_min::('u8 u128 casts'); - validate_cast_bounds_contained_same_min::('u16 u32 casts'); - validate_cast_bounds_contained_same_min::('u16 u64 casts'); - validate_cast_bounds_contained_same_min::('u16 u128 casts'); - validate_cast_bounds_contained_same_min::('u32 u64 casts'); - validate_cast_bounds_contained_same_min::('u32 u128 casts'); - validate_cast_bounds_contained_same_min::('u64 u128 casts'); - - validate_cast_bounds_strictly_contained::('u8 i16 casts'); - validate_cast_bounds_strictly_contained::('u8 i32 casts'); - validate_cast_bounds_strictly_contained::('u8 i64 casts'); - validate_cast_bounds_strictly_contained::('u8 i128 casts'); - validate_cast_bounds_strictly_contained::('u16 i32 casts'); - validate_cast_bounds_strictly_contained::('u16 i64 casts'); - validate_cast_bounds_strictly_contained::('u16 i128 casts'); - validate_cast_bounds_strictly_contained::('u32 i64 casts'); - validate_cast_bounds_strictly_contained::('u32 i128 casts'); - validate_cast_bounds_strictly_contained::('u64 i128 casts'); - - validate_cast_bounds_strictly_contained::('i8 i16 casts'); - validate_cast_bounds_strictly_contained::('i8 i32 casts'); - validate_cast_bounds_strictly_contained::('i8 i64 casts'); - validate_cast_bounds_strictly_contained::('i8 i128 casts'); - validate_cast_bounds_strictly_contained::('i16 i32 casts'); - validate_cast_bounds_strictly_contained::('i16 i64 casts'); - validate_cast_bounds_strictly_contained::('i16 i128 casts'); - validate_cast_bounds_strictly_contained::('i32 i64 casts'); - validate_cast_bounds_strictly_contained::('i32 i128 casts'); - validate_cast_bounds_strictly_contained::('i64 i128 casts'); - - validate_cast_bounds_overlapping::('i8 u8 casts'); - validate_cast_bounds_overlapping::('i8 u16 casts'); - validate_cast_bounds_overlapping::('i8 u32 casts'); - validate_cast_bounds_overlapping::('i8 u64 casts'); - validate_cast_bounds_overlapping::('i8 u128 casts'); - validate_cast_bounds_overlapping::('i16 u16 casts'); - validate_cast_bounds_overlapping::('i16 u32 casts'); - validate_cast_bounds_overlapping::('i16 u64 casts'); - validate_cast_bounds_overlapping::('i16 u128 casts'); - validate_cast_bounds_overlapping::('i32 u32 casts'); - validate_cast_bounds_overlapping::('i32 u64 casts'); - validate_cast_bounds_overlapping::('i32 u128 casts'); - validate_cast_bounds_overlapping::('i64 u64 casts'); - validate_cast_bounds_overlapping::('i64 u128 casts'); - validate_cast_bounds_overlapping::('i128 u128 casts'); -} - -#[test] -fn test_into_self_type() { - assert_eq(@0xFF_u8.into(), @0xFF_u8, 'u8 into u8'); - assert_eq(@0xFFFF_u16.into(), @0xFFFF_u16, 'u16 into u16'); - assert_eq(@0xFFFFFFFF_u32.into(), @0xFFFFFFFF_u32, 'u32 into u32'); - assert_eq(@0xFFFFFFFFFFFFFFFF_u64.into(), @0xFFFFFFFFFFFFFFFF_u64, 'u64 into u64'); - assert_eq( - @0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128.into(), - @0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_u128, - 'u128 into u128', - ); - assert_eq( - @u256 { low: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, high: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF } - .into(), - @u256 { high: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, low: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF }, - 'u256 into u256', - ); -} - -#[test] -#[should_panic] -fn panic_u16_u8_1() { - let _out: u8 = (0xFF_u16 + 1_u16).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u16_u8_2() { - let max_u16: u16 = 0xFFFF; - let _out: u8 = max_u16.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u32_u8_1() { - let _out: u8 = (0xFF_u32 + 1_u32).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u32_u8_2() { - let max_u32: u32 = 0xFFFFFFFF; - let _out: u8 = max_u32.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u64_u8_1() { - let _out: u8 = (0xFF_u64 + 1_u64).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u64_u8_2() { - let max_u64: u64 = 0xFFFFFFFFFFFFFFFF; - let _out: u8 = max_u64.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u128_u8_1() { - let _out: u8 = (0xFF_u128 + 1_u128).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u8_2() { - let max_u128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - let _out: u8 = max_u128.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u32_u16_1() { - let _out: u16 = (0xFFFF_u32 + 1_u32).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u32_u16_2() { - let max_u32: u32 = 0xFFFFFFFF; - let _out: u16 = max_u32.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u64_u16_1() { - let _out: u16 = (0xFFFF_u64 + 1_u64).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u64_u16_2() { - let max_u64: u64 = 0xFFFFFFFFFFFFFFFF; - let _out: u16 = max_u64.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u128_u16_1() { - let _out: u16 = (0xFFFF_u128 + 1_u128).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u16_2() { - let max_u128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - let _out: u16 = max_u128.try_into().unwrap(); -} -#[test] -#[should_panic] -fn panic_u64_u32_1() { - let _out: u32 = (0xFFFFFFFF_u64 + 1_u64).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u64_u32_2() { - let max_u64: u64 = 0xFFFFFFFFFFFFFFFF; - let _out: u32 = max_u64.try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u32_1() { - let _out: u32 = (0xFFFFFFFF_u128 + 1_u128).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u32_2() { - let max_u128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - let _out: u32 = max_u128.try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u64_1() { - let _out: u64 = (0xFFFFFFFFFFFFFFFF_u128 + 1_u128).try_into().unwrap(); -} - -#[test] -#[should_panic] -fn panic_u128_u64_2() { - let max_u128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - let _out: u64 = max_u128.try_into().unwrap(); -} - -#[test] -fn test_u128_byte_reverse() { - assert_eq( - @integer::u128_byte_reverse(0x000102030405060708090a0b0c0d0e0f), - @0x0f0e0d0c0b0a09080706050403020100, - 'Wrong byte reverse', - ); -} - -#[test] -fn test_i8_operators() { - assert_eq(@1_i8, @1_i8, '1 == 1'); - assert_ne(@1_i8, @2_i8, '1 != 2'); - assert_eq(@0x7f_felt252.try_into().unwrap(), @0x7f_i8, '0x7f is not i8'); - let v: Option = 0x80_felt252.try_into(); - assert(v.is_none(), '0x80 is i8'); - assert_eq(@(-0x80_felt252).try_into().unwrap(), @-0x80_i8, '-0x80 is not i8'); - let v: Option = (-0x81_felt252).try_into(); - assert(v.is_none(), '-0x81 is i8'); - assert_eq(@(1_i8 + 3_i8), @4_i8, '1 + 3 == 4'); - assert_eq(@(3_i8 + 6_i8), @9_i8, '3 + 6 == 9'); - assert_eq(@(3_i8 - 1_i8), @2_i8, '3 - 1 == 2'); - assert_eq(@(121_i8 - 21_i8), @100_i8, '121-21=100'); - assert_eq(@(-1_i8 + -3_i8), @-4_i8, '-1 + -3 == -4'); - assert_eq(@(-3_i8 + -6_i8), @-9_i8, '-3 + -6 == -9'); - assert_eq(@(-3_i8 - -1_i8), @-2_i8, '-3 - -1 == -2'); - assert_eq(@(-121_i8 - -21_i8), @-100_i8, '-121--21=-100'); - assert_eq(@(1_i8 * 3_i8), @3_i8, '1 * 3 == 3'); - assert_eq(@(2_i8 * 4_i8), @8_i8, '2 * 4 == 8'); - assert_eq(@(-1_i8 * 3_i8), @-3_i8, '-1 * 3 == 3'); - assert_eq(@(-2_i8 * 4_i8), @-8_i8, '-2 * 4 == 8'); - assert_eq(@(1_i8 * -3_i8), @-3_i8, '1 * -3 == -3'); - assert_eq(@(2_i8 * -4_i8), @-8_i8, '2 * -4 == -8'); - assert_eq(@(-1_i8 * -3_i8), @3_i8, '-1 * -3 == 3'); - assert_eq(@(-2_i8 * -4_i8), @8_i8, '-2 * -4 == 8'); - assert_lt(1_i8, 4_i8, '1 < 4'); - assert_le(1_i8, 4_i8, '1 <= 4'); - assert(!(4_i8 < 4_i8), '!(4 < 4)'); - assert_le(5_i8, 5_i8, '5 <= 5'); - assert(!(5_i8 <= 4_i8), '!(5 <= 4)'); - assert_gt(5_i8, 2_i8, '5 > 2'); - assert_ge(5_i8, 2_i8, '5 >= 2'); - assert(!(3_i8 > 3_i8), '!(3 > 3)'); - assert_ge(3_i8, 3_i8, '3 >= 3'); - assert!(19_i8 / 7_i8 == 2_i8); - assert!(19_i8 % 7_i8 == 5_i8); - assert!(19_i8 / -7_i8 == -2_i8); - assert!(19_i8 % -7_i8 == 5_i8); - assert!(-19_i8 / 7_i8 == -2_i8); - assert!(-19_i8 % 7_i8 == -5_i8); - assert!(-19_i8 / -7_i8 == 2_i8); - assert!(-19_i8 % -7_i8 == -5_i8); -} - -#[test] -#[should_panic(expected: ('i8_sub Underflow',))] -fn test_i8_sub_underflow_1() { - -0x80_i8 - 1_i8; -} - -#[test] -#[should_panic(expected: ('i8_sub Underflow',))] -fn test_i8_sub_underflow_2() { - -0x80_i8 - 3_i8; -} - -#[test] -#[should_panic(expected: ('i8_sub Underflow',))] -fn test_i8_sub_underflow_3() { - -0x7f_i8 - 3_i8; -} - -#[test] -#[should_panic(expected: ('i8_sub Underflow',))] -fn test_i8_sub_underflow_4() { - -0x32_i8 - 0x7d_i8; -} - -#[test] -#[should_panic(expected: ('i8_sub Overflow',))] -fn test_i8_sub_overflow() { - 0x32_i8 - -0x7d_i8; -} - -#[test] -#[should_panic(expected: ('i8_add Overflow',))] -fn test_i8_add_overflow_1() { - 0x40_i8 + 0x40_i8; -} - -#[test] -#[should_panic(expected: ('i8_add Overflow',))] -fn test_i8_add_overflow_2() { - 0x64_i8 + 0x1e_i8; -} - -#[test] -#[should_panic(expected: ('i8_add Underflow',))] -fn test_i8_add_underflow() { - -0x64_i8 + -0x1e_i8; -} - -#[test] -#[should_panic] -fn test_i8_mul_overflow_1() { - 0x10_i8 * 0x10_i8; -} - -#[test] -#[should_panic] -fn test_i8_mul_overflow_2() { - 0x11_i8 * 0x10_i8; -} - -#[test] -#[should_panic] -fn test_i8_mul_overflow_3() { - 2_i8 * 0x40_i8; -} - -#[test] -#[should_panic(expected: 'attempt to divide with overflow')] -fn test_i8_divmod_overflow() { - -0x80_i8 / -1_i8; -} - -#[test] -fn test_i16_operators() { - assert_eq(@1_i16, @1_i16, '1 == 1'); - assert_ne(@1_i16, @2_i16, '1 != 2'); - assert_eq(@0x7fff_felt252.try_into().unwrap(), @0x7fff_i16, '0x7fff is not i16'); - let v: Option = 0x8000_felt252.try_into(); - assert(v.is_none(), '0x8000 is i16'); - assert_eq(@(-0x8000_felt252).try_into().unwrap(), @-0x8000_i16, '-0x8000 is not i16'); - let v: Option = (-0x8001_felt252).try_into(); - assert(v.is_none(), '-0x8001 is i16'); - assert_eq(@(1_i16 + 3_i16), @4_i16, '1 + 3 == 4'); - assert_eq(@(3_i16 + 6_i16), @9_i16, '3 + 6 == 9'); - assert_eq(@(3_i16 - 1_i16), @2_i16, '3 - 1 == 2'); - assert_eq(@(231_i16 - 131_i16), @100_i16, '231-131=100'); - assert_eq(@(-1_i16 + -3_i16), @-4_i16, '-1 + -3 == -4'); - assert_eq(@(-3_i16 + -6_i16), @-9_i16, '-3 + -6 == -9'); - assert_eq(@(-3_i16 - -1_i16), @-2_i16, '-3 - -1 == -2'); - assert_eq(@(-231_i16 - -131_i16), @-100_i16, '-231--131=-100'); - assert_eq(@(1_i16 * 3_i16), @3_i16, '1 * 3 == 3'); - assert_eq(@(2_i16 * 4_i16), @8_i16, '2 * 4 == 8'); - assert_eq(@(-1_i16 * 3_i16), @-3_i16, '-1 * 3 == 3'); - assert_eq(@(-2_i16 * 4_i16), @-8_i16, '-2 * 4 == 8'); - assert_eq(@(1_i16 * -3_i16), @-3_i16, '1 * -3 == -3'); - assert_eq(@(2_i16 * -4_i16), @-8_i16, '2 * -4 == -8'); - assert_eq(@(-1_i16 * -3_i16), @3_i16, '-1 * -3 == 3'); - assert_eq(@(-2_i16 * -4_i16), @8_i16, '-2 * -4 == 8'); - assert_lt(1_i16, 4_i16, '1 < 4'); - assert_le(1_i16, 4_i16, '1 <= 4'); - assert(!(4_i16 < 4_i16), '!(4 < 4)'); - assert_le(5_i16, 5_i16, '5 <= 5'); - assert(!(5_i16 <= 4_i16), '!(5 <= 4)'); - assert_gt(5_i16, 2_i16, '5 > 2'); - assert_ge(5_i16, 2_i16, '5 >= 2'); - assert(!(3_i16 > 3_i16), '!(3 > 3)'); - assert_ge(3_i16, 3_i16, '3 >= 3'); - assert!(19_i16 / -7_i16 == -2_i16); - assert!(19_i16 % -7_i16 == 5_i16); - assert!(-19_i16 / 7_i16 == -2_i16); - assert!(-19_i16 % 7_i16 == -5_i16); - assert!(-19_i16 / -7_i16 == 2_i16); - assert!(-19_i16 % -7_i16 == -5_i16); -} - -#[test] -#[should_panic(expected: ('i16_sub Underflow',))] -fn test_i16_sub_underflow_1() { - -0x8000_i16 - 1_i16; -} - -#[test] -#[should_panic(expected: ('i16_sub Underflow',))] -fn test_i16_sub_underflow_2() { - -0x8000_i16 - 3_i16; -} - -#[test] -#[should_panic(expected: ('i16_sub Underflow',))] -fn test_i16_sub_underflow_3() { - -0x7fff_i16 - 3_i16; -} - -#[test] -#[should_panic(expected: ('i16_sub Underflow',))] -fn test_i16_sub_underflow_4() { - -0x3200_i16 - 0x7d00_i16; -} - -#[test] -#[should_panic(expected: ('i16_sub Overflow',))] -fn test_i16_sub_overflow() { - 0x3200_i16 - -0x7d00_i16; -} - -#[test] -#[should_panic(expected: ('i16_add Overflow',))] -fn test_i16_add_overflow_1() { - 0x4000_i16 + 0x4000_i16; -} - -#[test] -#[should_panic(expected: ('i16_add Overflow',))] -fn test_i16_add_overflow_2() { - 0x6400_i16 + 0x1e00_i16; -} - -#[test] -#[should_panic(expected: ('i16_add Underflow',))] -fn test_i16_add_underflow() { - -0x6400_i16 + -0x1e00_i16; -} - -#[test] -#[should_panic] -fn test_i16_mul_overflow_1() { - 0x1000_i16 * 0x1000_i16; -} - -#[test] -#[should_panic] -fn test_i16_mul_overflow_2() { - 0x1100_i16 * 0x1000_i16; -} - -#[test] -#[should_panic] -fn test_i16_mul_overflow_3() { - 2_i16 * 0x4000_i16; -} - -#[test] -#[should_panic(expected: 'attempt to divide with overflow')] -fn test_i16_divmod_overflow() { - -0x8000_i16 / -1_i16; -} - -#[test] -fn test_i32_operators() { - assert_eq(@1_i32, @1_i32, '1 == 1'); - assert_ne(@1_i32, @2_i32, '1 != 2'); - assert_eq(@0x7fffffff_felt252.try_into().unwrap(), @0x7fffffff_i32, '0x7fffffff is not i32'); - let v: Option = 0x80000000_felt252.try_into(); - assert(v.is_none(), '0x80000000 is i32'); - assert_eq(@(-0x80000000_felt252).try_into().unwrap(), @-0x80000000_i32, '-0x8000 is not i32'); - let v: Option = (-0x80000001_felt252).try_into(); - assert(v.is_none(), '-0x80000001 is i32'); - assert_eq(@(1_i32 + 3_i32), @4_i32, '1 + 3 == 4'); - assert_eq(@(3_i32 + 6_i32), @9_i32, '3 + 6 == 9'); - assert_eq(@(3_i32 - 1_i32), @2_i32, '3 - 1 == 2'); - assert_eq(@(231_i32 - 131_i32), @100_i32, '231-131=100'); - assert_eq(@(-1_i32 + -3_i32), @-4_i32, '-1 + -3 == -4'); - assert_eq(@(-3_i32 + -6_i32), @-9_i32, '-3 + -6 == -9'); - assert_eq(@(-3_i32 - -1_i32), @-2_i32, '-3 - -1 == -2'); - assert_eq(@(-231_i32 - -131_i32), @-100_i32, '-231--131=-100'); - assert_eq(@(1_i32 * 3_i32), @3_i32, '1 * 3 == 3'); - assert_eq(@(2_i32 * 4_i32), @8_i32, '2 * 4 == 8'); - assert_eq(@(-1_i32 * 3_i32), @-3_i32, '-1 * 3 == 3'); - assert_eq(@(-2_i32 * 4_i32), @-8_i32, '-2 * 4 == 8'); - assert_eq(@(1_i32 * -3_i32), @-3_i32, '1 * -3 == -3'); - assert_eq(@(2_i32 * -4_i32), @-8_i32, '2 * -4 == -8'); - assert_eq(@(-1_i32 * -3_i32), @3_i32, '-1 * -3 == 3'); - assert_eq(@(-2_i32 * -4_i32), @8_i32, '-2 * -4 == 8'); - assert_lt(1_i32, 4_i32, '1 < 4'); - assert_le(1_i32, 4_i32, '1 <= 4'); - assert(!(4_i32 < 4_i32), '!(4 < 4)'); - assert_le(5_i32, 5_i32, '5 <= 5'); - assert(!(5_i32 <= 4_i32), '!(5 <= 4)'); - assert_gt(5_i32, 2_i32, '5 > 2'); - assert_ge(5_i32, 2_i32, '5 >= 2'); - assert(!(3_i32 > 3_i32), '!(3 > 3)'); - assert_ge(3_i32, 3_i32, '3 >= 3'); - assert!(19_i32 / -7_i32 == -2_i32); - assert!(19_i32 % -7_i32 == 5_i32); - assert!(-19_i32 / 7_i32 == -2_i32); - assert!(-19_i32 % 7_i32 == -5_i32); - assert!(-19_i32 / -7_i32 == 2_i32); - assert!(-19_i32 % -7_i32 == -5_i32); -} - -#[test] -#[should_panic(expected: ('i32_sub Underflow',))] -fn test_i32_sub_underflow_1() { - -0x80000000_i32 - 1_i32; -} - -#[test] -#[should_panic(expected: ('i32_sub Underflow',))] -fn test_i32_sub_underflow_2() { - -0x80000000_i32 - 3_i32; -} - -#[test] -#[should_panic(expected: ('i32_sub Underflow',))] -fn test_i32_sub_underflow_3() { - -0x7fffffff_i32 - 3_i32; -} - -#[test] -#[should_panic(expected: ('i32_sub Underflow',))] -fn test_i32_sub_underflow_4() { - -0x32000000_i32 - 0x7d000000_i32; -} - -#[test] -#[should_panic(expected: ('i32_sub Overflow',))] -fn test_i32_sub_overflow() { - 0x32000000_i32 - -0x7d000000_i32; -} - -#[test] -#[should_panic(expected: ('i32_add Overflow',))] -fn test_i32_add_overflow_1() { - 0x40000000_i32 + 0x40000000_i32; -} - -#[test] -#[should_panic(expected: ('i32_add Overflow',))] -fn test_i32_add_overflow_2() { - 0x64000000_i32 + 0x1e000000_i32; -} - -#[test] -#[should_panic(expected: ('i32_add Underflow',))] -fn test_i32_add_underflow() { - -0x64000000_i32 + -0x1e000000_i32; -} - -#[test] -#[should_panic] -fn test_i32_mul_overflow_1() { - 0x10000000_i32 * 0x10000000_i32; -} - -#[test] -#[should_panic] -fn test_i32_mul_overflow_2() { - 0x11000000_i32 * 0x10000000_i32; -} - -#[test] -#[should_panic] -fn test_i32_mul_overflow_3() { - 2_i32 * 0x40000000_i32; -} - -#[test] -#[should_panic(expected: 'attempt to divide with overflow')] -fn test_i32_divmod_overflow() { - -0x80000000_i32 / -1_i32; -} - -#[test] -fn test_i64_operators() { - assert_eq(@1_i64, @1_i64, '1 == 1'); - assert_ne(@1_i64, @2_i64, '1 != 2'); - assert_eq( - @0x7fffffffffffffff_felt252.try_into().unwrap(), - @0x7fffffffffffffff_i64, - '0x7fffffffffffffff is not i64', - ); - let v: Option = 0x8000000000000000_felt252.try_into(); - assert(v.is_none(), '0x8000000000000000 is i64'); - assert_eq( - @(-0x8000000000000000_felt252).try_into().unwrap(), - @-0x8000000000000000_i64, - '-0x8000000000000000 is not i64', - ); - let v: Option = (-0x8000000000000001_felt252).try_into(); - assert(v.is_none(), '-0x8000000000000001 is i64'); - assert_eq(@(1_i64 + 3_i64), @4_i64, '1 + 3 == 4'); - assert_eq(@(3_i64 + 6_i64), @9_i64, '3 + 6 == 9'); - assert_eq(@(3_i64 - 1_i64), @2_i64, '3 - 1 == 2'); - assert_eq(@(231_i64 - 131_i64), @100_i64, '231-131=100'); - assert_eq(@(-1_i64 + -3_i64), @-4_i64, '-1 + -3 == -4'); - assert_eq(@(-3_i64 + -6_i64), @-9_i64, '-3 + -6 == -9'); - assert_eq(@(-3_i64 - -1_i64), @-2_i64, '-3 - -1 == -2'); - assert_eq(@(-231_i64 - -131_i64), @-100_i64, '-231--131=-100'); - assert_eq(@(1_i64 * 3_i64), @3_i64, '1 * 3 == 3'); - assert_eq(@(2_i64 * 4_i64), @8_i64, '2 * 4 == 8'); - assert_eq(@(-1_i64 * 3_i64), @-3_i64, '-1 * 3 == 3'); - assert_eq(@(-2_i64 * 4_i64), @-8_i64, '-2 * 4 == 8'); - assert_eq(@(1_i64 * -3_i64), @-3_i64, '1 * -3 == -3'); - assert_eq(@(2_i64 * -4_i64), @-8_i64, '2 * -4 == -8'); - assert_eq(@(-1_i64 * -3_i64), @3_i64, '-1 * -3 == 3'); - assert_eq(@(-2_i64 * -4_i64), @8_i64, '-2 * -4 == 8'); - assert_lt(1_i64, 4_i64, '1 < 4'); - assert_le(1_i64, 4_i64, '1 <= 4'); - assert(!(4_i64 < 4_i64), '!(4 < 4)'); - assert_le(5_i64, 5_i64, '5 <= 5'); - assert(!(5_i64 <= 4_i64), '!(5 <= 4)'); - assert_gt(5_i64, 2_i64, '5 > 2'); - assert_ge(5_i64, 2_i64, '5 >= 2'); - assert(!(3_i64 > 3_i64), '!(3 > 3)'); - assert_ge(3_i64, 3_i64, '3 >= 3'); - assert!(19_i64 / -7_i64 == -2_i64); - assert!(19_i64 % -7_i64 == 5_i64); - assert!(-19_i64 / 7_i64 == -2_i64); - assert!(-19_i64 % 7_i64 == -5_i64); - assert!(-19_i64 / -7_i64 == 2_i64); - assert!(-19_i64 % -7_i64 == -5_i64); -} - -#[test] -#[should_panic(expected: ('i64_sub Underflow',))] -fn test_i64_sub_underflow_1() { - -0x8000000000000000_i64 - 1_i64; -} - -#[test] -#[should_panic(expected: ('i64_sub Underflow',))] -fn test_i64_sub_underflow_2() { - -0x8000000000000000_i64 - 3_i64; -} - -#[test] -#[should_panic(expected: ('i64_sub Underflow',))] -fn test_i64_sub_underflow_3() { - -0x7fffffffffffffff_i64 - 3_i64; -} - -#[test] -#[should_panic(expected: ('i64_sub Underflow',))] -fn test_i64_sub_underflow_4() { - -0x3200000000000000_i64 - 0x7d00000000000000_i64; -} - -#[test] -#[should_panic(expected: ('i64_sub Overflow',))] -fn test_i64_sub_overflow() { - 0x3200000000000000_i64 - -0x7d00000000000000_i64; -} - -#[test] -#[should_panic(expected: ('i64_add Overflow',))] -fn test_i64_add_overflow_1() { - 0x4000000000000000_i64 + 0x4000000000000000_i64; -} - -#[test] -#[should_panic(expected: ('i64_add Overflow',))] -fn test_i64_add_overflow_2() { - 0x6400000000000000_i64 + 0x1e00000000000000_i64; -} - -#[test] -#[should_panic(expected: ('i64_add Underflow',))] -fn test_i64_add_underflow() { - -0x6400000000000000_i64 + -0x1e00000000000000_i64; -} - -#[test] -#[should_panic] -fn test_i64_mul_overflow_1() { - 0x1000000000000000_i64 * 0x1000000000000000_i64; -} - -#[test] -#[should_panic] -fn test_i64_mul_overflow_2() { - 0x1100000000000000_i64 * 0x1000000000000000_i64; -} - -#[test] -#[should_panic] -fn test_i64_mul_overflow_3() { - 2_i64 * 0x4000000000000000_i64; -} - -#[test] -#[should_panic(expected: 'attempt to divide with overflow')] -fn test_i64_divmod_overflow() { - -0x8000000000000000_i64 / -1_i64; -} - -#[test] -fn test_i128_operators() { - assert_eq(@1_i128, @1_i128, '1 == 1'); - assert_ne(@1_i128, @2_i128, '1 != 2'); - assert_eq( - @0x7fffffffffffffffffffffffffffffff_felt252.try_into().unwrap(), - @0x7fffffffffffffffffffffffffffffff_i128, - '0x7f..f is not i128', - ); - let v: Option = 0x80000000000000000000000000000000_felt252.try_into(); - assert(v.is_none(), '0x80..0 is i128'); - assert_eq( - @(-0x80000000000000000000000000000000_felt252).try_into().unwrap(), - @-0x80000000000000000000000000000000_i128, - '-0x80..0 is not i128', - ); - let v: Option = (-0x80000000000000000000000000000001_felt252).try_into(); - assert(v.is_none(), '-0x80..01 is i128'); - assert_eq(@(1_i128 + 3_i128), @4_i128, '1 + 3 == 4'); - assert_eq(@(3_i128 + 6_i128), @9_i128, '3 + 6 == 9'); - assert_eq(@(3_i128 - 1_i128), @2_i128, '3 - 1 == 2'); - assert_eq(@(231_i128 - 131_i128), @100_i128, '231-131=100'); - assert_eq(@(-1_i128 + -3_i128), @-4_i128, '-1 + -3 == -4'); - assert_eq(@(-3_i128 + -6_i128), @-9_i128, '-3 + -6 == -9'); - assert_eq(@(-3_i128 - -1_i128), @-2_i128, '-3 - -1 == -2'); - assert_eq(@(-231_i128 - -131_i128), @-100_i128, '-231--131=-100'); - assert_eq(@(1_i128 * 3_i128), @3_i128, '1 * 3 == 3'); - assert_eq(@(7_i128 * 0_i128), @0_i128, '7 * 0 == 0'); - assert_eq(@(2_i128 * 4_i128), @8_i128, '2 * 4 == 8'); - assert_eq(@(-1_i128 * 3_i128), @-3_i128, '-1 * 3 == -3'); - assert_eq(@(-2_i128 * 4_i128), @-8_i128, '-2 * 4 == -8'); - assert_eq(@(1_i128 * -3_i128), @-3_i128, '1 * -3 == -3'); - assert_eq(@(2_i128 * -4_i128), @-8_i128, '2 * -4 == -8'); - assert_eq(@(-1_i128 * -3_i128), @3_i128, '-1 * -3 == 3'); - assert_eq(@(-2_i128 * -4_i128), @8_i128, '-2 * -4 == 8'); - assert_eq( - @(0x800000000000000_i128 * -0x100000000000000000_i128), - @-0x80000000000000000000000000000000_i128, - 'failed MIN_I128 as mul result', - ); - assert_lt(1_i128, 4_i128, '1 < 4'); - assert_le(1_i128, 4_i128, '1 <= 4'); - assert(!(4_i128 < 4_i128), '!(4 < 4)'); - assert_le(5_i128, 5_i128, '5 <= 5'); - assert(!(5_i128 <= 4_i128), '!(5 <= 4)'); - assert_gt(5_i128, 2_i128, '5 > 2'); - assert_ge(5_i128, 2_i128, '5 >= 2'); - assert(!(3_i128 > 3_i128), '!(3 > 3)'); - assert_ge(3_i128, 3_i128, '3 >= 3'); - assert!(19_i128 / -7_i128 == -2_i128); - assert!(19_i128 % -7_i128 == 5_i128); - assert!(-19_i128 / 7_i128 == -2_i128); - assert!(-19_i128 % 7_i128 == -5_i128); - assert!(-19_i128 / -7_i128 == 2_i128); - assert!(-19_i128 % -7_i128 == -5_i128); -} - -#[test] -#[should_panic] -fn test_i128_sub_underflow_1() { - -0x80000000000000000000000000000000_i128 - 1_i128; -} - -#[test] -#[should_panic(expected: ('i128_sub Underflow',))] -fn test_i128_sub_underflow_2() { - -0x80000000000000000000000000000000_i128 - 3_i128; -} - -#[test] -#[should_panic(expected: ('i128_sub Underflow',))] -fn test_i128_sub_underflow_3() { - -0x7fffffffffffffffffffffffffffffff_i128 - 3_i128; -} - -#[test] -#[should_panic(expected: ('i128_sub Underflow',))] -fn test_i128_sub_underflow_4() { - -0x32000000000000000000000000000000_i128 - 0x7d000000000000000000000000000000_i128; -} - -#[test] -#[should_panic(expected: ('i128_sub Overflow',))] -fn test_i128_sub_overflow() { - 0x32000000000000000000000000000000_i128 - -0x7d000000000000000000000000000000_i128; -} - -#[test] -#[should_panic(expected: ('i128_add Overflow',))] -fn test_i128_add_overflow_1() { - 0x40000000000000000000000000000000_i128 + 0x40000000000000000000000000000000_i128; -} - -#[test] -#[should_panic(expected: ('i128_add Overflow',))] -fn test_i128_add_overflow_2() { - 0x64000000000000000000000000000000_i128 + 0x1e000000000000000000000000000000_i128; -} - -#[test] -#[should_panic(expected: ('i128_add Underflow',))] -fn test_i128_add_underflow() { - -0x64000000000000000000000000000000_i128 + -0x1e000000000000000000000000000000_i128; -} - -#[test] -#[should_panic] -fn test_i128_mul_overflow_1() { - 0x10000000000000000000000000000000_i128 * 0x10000000000000000000000000000000_i128; -} - -#[test] -#[should_panic] -fn test_i128_mul_overflow_2() { - 0x11000000000000000000000000000000_i128 * 0x10000000000000000000000000000000_i128; -} - -#[test] -#[should_panic] -fn test_i128_mul_overflow_3() { - 2_i128 * 0x40000000000000000000000000000000_i128; -} - -#[test] -#[should_panic(expected: 'attempt to divide with overflow')] -fn test_i128_divmod_overflow() { - -0x80000000000000000000000000000000_i128 / -1_i128; -} - -#[test] -fn test_signed_int_diff() { - assert_eq(@integer::i8_diff(3, 3).unwrap(), @0, 'i8: 3 - 3 == 0'); - assert_eq(@integer::i8_diff(4, 3).unwrap(), @1, 'i8: 4 - 3 == 1'); - assert_eq(@integer::i8_diff(3, 5).unwrap_err(), @~(2 - 1), 'i8: 3 - 5 == -2'); - assert_eq(@integer::i16_diff(3, 3).unwrap(), @0, 'i16: 3 - 3 == 0'); - assert_eq(@integer::i16_diff(4, 3).unwrap(), @1, 'i16: 4 - 3 == 1'); - assert_eq(@integer::i16_diff(3, 5).unwrap_err(), @~(2 - 1), 'i16: 3 - 5 == -2'); - assert_eq(@integer::i32_diff(3, 3).unwrap(), @0, 'i32: 3 - 3 == 0'); - assert_eq(@integer::i32_diff(4, 3).unwrap(), @1, 'i32: 4 - 3 == 1'); - assert_eq(@integer::i32_diff(3, 5).unwrap_err(), @~(2 - 1), 'i32: 3 - 5 == -2'); - assert_eq(@integer::i64_diff(3, 3).unwrap(), @0, 'i64: 3 - 3 == 0'); - assert_eq(@integer::i64_diff(4, 3).unwrap(), @1, 'i64: 4 - 3 == 1'); - assert_eq(@integer::i64_diff(3, 5).unwrap_err(), @~(2 - 1), 'i64: 3 - 5 == -2'); - assert_eq(@integer::i128_diff(3, 3).unwrap(), @0, 'i128: 3 - 3 == 0'); - assert_eq(@integer::i128_diff(4, 3).unwrap(), @1, 'i128: 4 - 3 == 1'); - assert_eq(@integer::i128_diff(3, 5).unwrap_err(), @~(2 - 1), 'i128: 3 - 5 == -2'); -} - -#[inline(never)] -fn noopt(t: T) -> T { - t -} - -#[test] -fn test_signed_int_neg() { - assert_eq!(-noopt(1), -1_i8); - assert_eq!(-noopt(0), 0_i8); - assert_eq!(-noopt(-1), 1_i8); - assert_eq!(-noopt(Bounded::::MAX), Bounded::::MIN + 1); - assert_eq!(-noopt(Bounded::::MIN + 1), Bounded::::MAX); - assert_eq!(-noopt(1), -1_i16); - assert_eq!(-noopt(0), 0_i16); - assert_eq!(-noopt(-1), 1_i16); - assert_eq!(-noopt(Bounded::::MAX), Bounded::::MIN + 1); - assert_eq!(-noopt(Bounded::::MIN + 1), Bounded::::MAX); - assert_eq!(-noopt(1), -1_i32); - assert_eq!(-noopt(0), 0_i32); - assert_eq!(-noopt(-1), 1_i32); - assert_eq!(-noopt(Bounded::::MAX), Bounded::::MIN + 1); - assert_eq!(-noopt(Bounded::::MIN + 1), Bounded::::MAX); - assert_eq!(-noopt(1), -1_i64); - assert_eq!(-noopt(0), 0_i64); - assert_eq!(-noopt(-1), 1_i64); - assert_eq!(-noopt(Bounded::::MAX), Bounded::::MIN + 1); - assert_eq!(-noopt(Bounded::::MIN + 1), Bounded::::MAX); - assert_eq!(-noopt(1), -1_i128); - assert_eq!(-noopt(0), 0_i128); - assert_eq!(-noopt(-1), 1_i128); - assert_eq!(-noopt(Bounded::::MAX), Bounded::::MIN + 1); - assert_eq!(-noopt(Bounded::::MIN + 1), Bounded::::MAX); -} - -#[test] -#[should_panic(expected: 'i8_neg Underflow')] -fn test_signed_int_neg_i8_min() { - -noopt(Bounded::::MIN); -} - -#[test] -#[should_panic(expected: 'i16_neg Underflow')] -fn test_signed_int_neg_i16_min() { - -noopt(Bounded::::MIN); -} - -#[test] -#[should_panic(expected: 'i32_neg Underflow')] -fn test_signed_int_neg_i32_min() { - -noopt(Bounded::::MIN); -} - -#[test] -#[should_panic(expected: 'i64_neg Underflow')] -fn test_signed_int_neg_i64_min() { - -noopt(Bounded::::MIN); -} - -#[test] -#[should_panic(expected: 'i128_neg Underflow')] -fn test_signed_int_neg_i128_min() { - -noopt(Bounded::::MIN); -} - -#[feature("bounded-int-utils")] -mod bounded_int { - use crate::internal::bounded_int::{ - self, AddHelper, BoundedInt, ConstrainHelper, DivRemHelper, MulHelper, SubHelper, UnitInt, - downcast, upcast, - }; - - const U128_UPPER: felt252 = 0x100000000000000000000000000000000; - const U128_MAX: felt252 = U128_UPPER - 1; - - /// Is `value` the equivalent value of `expected` in `T` type. - fn is_some_of(value: Option, expected: felt252) -> bool { - match value { - Some(v) => upcast(v) == expected, - None => false, - } - } - - /// Is `value` the equivalent value (as `felt252`) of `expected` in `T` type. - fn felt252_downcast_valid(value: felt252) -> bool { - is_some_of(downcast::(value), value) - } - - #[test] - fn test_felt252_downcasts() { - assert!(!felt252_downcast_valid::>(1)); - assert!(felt252_downcast_valid::>(0)); - assert!(!felt252_downcast_valid::>(-1)); - assert!(!felt252_downcast_valid::>(-2)); - assert!(felt252_downcast_valid::>(-1)); - assert!(!felt252_downcast_valid::>(0)); - assert!(!felt252_downcast_valid::>(119)); - assert!(felt252_downcast_valid::>(120)); - assert!(felt252_downcast_valid::>(180)); - assert!(!felt252_downcast_valid::>(181)); - assert!(!felt252_downcast_valid::>(U128_MAX - 1)); - assert!(felt252_downcast_valid::>(U128_MAX)); - assert!(!felt252_downcast_valid::>(U128_MAX + 1)); - assert!(!felt252_downcast_valid::>(U128_UPPER - 1)); - assert!(felt252_downcast_valid::>(U128_UPPER)); - assert!(!felt252_downcast_valid::>(U128_UPPER + 1)); - } - - const ONE_MINUS_P: felt252 = -0x800000000000011000000000000000000000000000000000000000000000000; - - // Full prime range, but where the max element is 0. - type OneMinusPToZero = BoundedInt; - - fn bi_const() -> UnitInt { - downcast(V).unwrap() - } - - #[test] - fn test_bounded_int_casts() { - assert!(downcast::(upcast(bi_const::<-1>())).is_none()); - assert!(downcast::(0) == Some(0)); - assert!(downcast::(upcast(bi_const::())).is_none()); - assert!(downcast::, BoundedInt<120, 180>>(119).is_none()); - assert!(is_some_of(downcast::, BoundedInt<120, 180>>(120), 120)); - assert!(is_some_of(downcast::, BoundedInt<120, 180>>(180), 180)); - assert!(downcast::, BoundedInt<120, 180>>(181).is_none()); - } - - impl U8BIAdd of AddHelper { - type Result = BoundedInt<0, 510>; - } - impl I8BIAdd of AddHelper { - type Result = BoundedInt<-256, 254>; - } - - #[test] - fn test_add() { - assert!(upcast(bounded_int::add(0_u8, 0_u8)) == 0_felt252); - assert!(upcast(bounded_int::add(0_u8, 255_u8)) == 255_felt252); - assert!(upcast(bounded_int::add(255_u8, 0_u8)) == 255_felt252); - assert!(upcast(bounded_int::add(255_u8, 255_u8)) == 510_felt252); - assert!(upcast(bounded_int::add(-128_i8, -128_i8)) == -256_felt252); - assert!(upcast(bounded_int::add(-128_i8, 127_i8)) == -1_felt252); - assert!(upcast(bounded_int::add(127_i8, -128_i8)) == -1_felt252); - assert!(upcast(bounded_int::add(127_i8, 127_i8)) == 254_felt252); - } - - impl U8BISub of SubHelper { - type Result = BoundedInt<-255, 255>; - } - impl I8BISub of SubHelper { - type Result = BoundedInt<-255, 255>; - } - - #[test] - fn test_sub() { - assert!(upcast(bounded_int::sub(0_u8, 0_u8)) == 0_felt252); - assert!(upcast(bounded_int::sub(0_u8, 255_u8)) == -255_felt252); - assert!(upcast(bounded_int::sub(255_u8, 0_u8)) == 255_felt252); - assert!(upcast(bounded_int::sub(255_u8, 255_u8)) == 0_felt252); - assert!(upcast(bounded_int::sub(-128_i8, -128_i8)) == 0_felt252); - assert!(upcast(bounded_int::sub(-128_i8, 127_i8)) == -255_felt252); - assert!(upcast(bounded_int::sub(127_i8, -128_i8)) == 255_felt252); - assert!(upcast(bounded_int::sub(127_i8, 127_i8)) == 0_felt252); - } - - impl U8BIMul of MulHelper { - type Result = BoundedInt<0, { 255 * 255 }>; - } - impl I8BIMul of MulHelper { - type Result = BoundedInt<{ 127 * -128 }, { 128 * 128 }>; - } - - #[test] - fn test_mul() { - assert!(upcast(bounded_int::mul(0_u8, 0_u8)) == 0_felt252); - assert!(upcast(bounded_int::mul(0_u8, 255_u8)) == 0_felt252); - assert!(upcast(bounded_int::mul(255_u8, 0_u8)) == 0_felt252); - assert!(upcast(bounded_int::mul(255_u8, 255_u8)) == 255_felt252 * 255); - assert!(upcast(bounded_int::mul(-128_i8, -128_i8)) == -128_felt252 * -128); - assert!(upcast(bounded_int::mul(-128_i8, 127_i8)) == -128_felt252 * 127); - assert!(upcast(bounded_int::mul(127_i8, -128_i8)) == 127_felt252 * -128); - assert!(upcast(bounded_int::mul(127_i8, 127_i8)) == 127_felt252 * 127); - } - - fn bi_value(v: u128) -> BoundedInt { - downcast(v).unwrap() - } - - extern fn bounded_int_wrap_non_zero(v: T) -> NonZero nopanic; - - /// Same as `bounded_int_div_rem`, but unwraps the result into felt252s. - fn bounded_int_div_rem_unwrapped>( - a: T1, b: T2, - ) -> (felt252, felt252) { - let (q, r) = bounded_int::div_rem(a, bounded_int_wrap_non_zero(b)); - (upcast(q), upcast(r)) - } - - impl SmallNumDivRemRes of DivRemHelper, BoundedInt<3, 8>> { - type DivT = BoundedInt<16, 85>; - type RemT = BoundedInt<0, 7>; - } - fn div_rem_helper(a: u128, b: u128) -> (felt252, felt252) { - bounded_int_div_rem_unwrapped(bi_value::<128, 255>(a), bi_value::<3, 8>(b)) - } - - #[test] - fn test_div_rem() { - assert!(div_rem_helper(128, 3) == (42, 2)); - assert!(div_rem_helper(255, 3) == (85, 0)); - assert!(div_rem_helper(128, 8) == (16, 0)); - assert!(div_rem_helper(255, 8) == (31, 7)); - } - - impl U128DivRemRes of DivRemHelper> { - type DivT = BoundedInt<0, 0xffffffffffffffffffffffffffffffff>; - type RemT = BoundedInt<0, 0xfffffffffffffffffffffffffffffffe>; - } - fn div_rem_wide_helper(a: u128, b: u128) -> (felt252, felt252) { - bounded_int_div_rem_unwrapped(a, bi_value::<1, 0xffffffffffffffffffffffffffffffff>(b)) - } - - #[test] - fn test_div_rem_wide() { - assert!(div_rem_wide_helper(128, 3) == (42, 2)); - assert!(div_rem_wide_helper(255, 3) == (85, 0)); - assert!(div_rem_wide_helper(128, 8) == (16, 0)); - assert!(div_rem_wide_helper(255, 8) == (31, 7)); - } - - mod helpers { - pub impl DivRemHelperImpl< - const A: felt252, const B: felt252, const MAX_Q: felt252, const MAX_R: felt252, - > of super::DivRemHelper, super::UnitInt> { - type DivT = super::BoundedInt<0, MAX_Q>; - type RemT = super::BoundedInt<0, MAX_R>; - } - } - - fn div_rem_small_quotient_helper< - const A_MAX: felt252, - const B: felt252, - const A: felt252, - +DivRemHelper, UnitInt>, - >( - a: UnitInt, - ) -> (felt252, felt252) { - bounded_int_div_rem_unwrapped::>(upcast(a), bi_const::()) - } - - const POW_2_124: felt252 = 0x10000000000000000000000000000000; - const MASK4: felt252 = 0xf; - const MASK124: felt252 = POW_2_124 - 1; - const POW_2_251: felt252 = 0x800000000000000000000000000000000000000000000000000000000000000; - const POW_2_123: felt252 = 0x8000000000000000000000000000000; - - impl U128Pow124DivRemHelper = helpers::DivRemHelperImpl; - impl U251Pow128DivRemHelper = - helpers::DivRemHelperImpl; - - // Test an extreme case where BoundedIntDivRemAlgorithm::KnownSmallLhs is used, - // and `min{b, q} = lhs_upper_sqrt - 1`. - type MaxRootLhs = - BoundedInt<1, 0x1000000000000000000000000000001000000000000000000000000000001>; - type MaxRootRhs = - BoundedInt<0x20000000000000000000000000000, { 0x100000000000000000000000000000000 - 1 }>; - impl MaxRootDivRemHelper of DivRemHelper { - type DivT = BoundedInt<0, 0x80000000000000000000000000000080>; - type RemT = BoundedInt<0, { 0x100000000000000000000000000000000 - 2 }>; - } - - #[test] - fn test_div_rem_small_quotient() { - assert!(div_rem_small_quotient_helper::(bi_const::<0>()) == (0, 0)); - let dividend = bi_const::<{ 0x5 * POW_2_124 + 0x32 }>(); - assert!(div_rem_small_quotient_helper::(dividend) == (0x5, 0x32)); - let dividend = bi_const::<{ 0xf * POW_2_124 + 0x12345 }>(); - assert!(div_rem_small_quotient_helper::(dividend) == (0xf, 0x12345)); - let dividend = bi_const::(); - assert!(div_rem_small_quotient_helper::(dividend) == (MASK4, MASK124)); - let dividend = bi_const::(); - assert!( - div_rem_small_quotient_helper::< - POW_2_251, U128_MAX, - >(dividend) == (POW_2_123, POW_2_123), - ); - assert!( - bounded_int_div_rem_unwrapped::< - MaxRootLhs, MaxRootRhs, - >( - 0x1000000000000000000000000000001000000000000000000000000000000, - 0x1000000000000000000000000000000, - ) == (0x1000000000000000000000000000001, 0), - ); - } - - fn test_constrain_helper, +Copy>( - value: T, - ) -> bool { - match bounded_int::constrain::<_, BOUNDARY>(value) { - Ok(result) => upcast(result), - Err(result) => upcast(result), - } == upcast::<_, felt252>(value) - } - - impl U8BIConstrain of ConstrainHelper { - type LowT = BoundedInt<0, 0x7f>; - type HighT = BoundedInt<0x80, 0xff>; - } - const U129_MAX: felt252 = U128_MAX + U128_UPPER; - type u129 = BoundedInt<0, U129_MAX>; - impl U129BIConstrain of ConstrainHelper { - type LowT = BoundedInt<0, U128_MAX>; - type HighT = BoundedInt; - } - - #[test] - fn test_constrain() { - assert!(test_constrain_helper::(0)); - assert!(test_constrain_helper::(0x7f)); - assert!(test_constrain_helper::(0x80)); - assert!(test_constrain_helper::(0xff)); - assert!(test_constrain_helper::(-0x80)); - assert!(test_constrain_helper::(-1)); - assert!(test_constrain_helper::(0)); - assert!(test_constrain_helper::(0x7f)); - assert!(test_constrain_helper::(upcast(bi_const::<0>()))); - assert!(test_constrain_helper::(upcast(bi_const::()))); - assert!(test_constrain_helper::(upcast(bi_const::()))); - assert!(test_constrain_helper::(upcast(bi_const::()))); - } - - #[test] - fn test_trim() { - use core::internal::OptionRev; - assert!(bounded_int::trim_min::(0) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0xff) == OptionRev::None); - assert!(bounded_int::trim_max::(0xfe) == OptionRev::Some(0xfe)); - assert!(bounded_int::trim_min::(-0x80) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0x7f) == OptionRev::None); - assert!(bounded_int::trim_max::(1) == OptionRev::Some(1)); - - assert!(bounded_int::trim_min::(0) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0xffff) == OptionRev::None); - assert!(bounded_int::trim_max::(0xfffe) == OptionRev::Some(0xfffe)); - assert!(bounded_int::trim_min::(-0x8000) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0x7fff) == OptionRev::None); - assert!(bounded_int::trim_max::(1) == OptionRev::Some(1)); - - assert!(bounded_int::trim_min::(0) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0xffffffff) == OptionRev::None); - assert!(bounded_int::trim_max::(0xfffffffe) == OptionRev::Some(0xfffffffe)); - assert!(bounded_int::trim_min::(-0x80000000) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0x7fffffff) == OptionRev::None); - assert!(bounded_int::trim_max::(1) == OptionRev::Some(1)); - - assert!(bounded_int::trim_min::(0) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0xffffffffffffffff) == OptionRev::None); - assert!( - bounded_int::trim_max::(0xfffffffffffffffe) == OptionRev::Some(0xfffffffffffffffe), - ); - assert!(bounded_int::trim_min::(-0x8000000000000000) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!(bounded_int::trim_max::(0x7fffffffffffffff) == OptionRev::None); - assert!(bounded_int::trim_max::(1) == OptionRev::Some(1)); - - assert!(bounded_int::trim_min::(0) == OptionRev::None); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!( - bounded_int::trim_max::(0xffffffffffffffffffffffffffffffff) == OptionRev::None, - ); - assert!( - bounded_int::trim_max::< - u128, - >( - 0xfffffffffffffffffffffffffffffffe, - ) == OptionRev::Some(0xfffffffffffffffffffffffffffffffe), - ); - assert!( - bounded_int::trim_min::(-0x80000000000000000000000000000000) == OptionRev::None, - ); - assert!(bounded_int::trim_min::(1) == OptionRev::Some(1)); - assert!( - bounded_int::trim_max::(0x7fffffffffffffffffffffffffffffff) == OptionRev::None, - ); - assert!(bounded_int::trim_max::(1) == OptionRev::Some(1)); - } -} - -#[test] -fn test_upcast_in_const() { - const AS_U8: u8 = 10; - const AS_U16: u16 = AS_U8.into(); - assert_eq!(AS_U16, 10); -} - -#[test] -fn test_downcast_in_const() { - const IN_RANGE: u16 = 10; - const OUT_OF_RANGE: u16 = 300; - const IN_RANGE_AS_U8: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_U8: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_U8, Some(10)); - assert_eq!(OUT_OF_RANGE_AS_U8, None); -} - -#[test] -fn test_const_into_felt252_casts() { - const U8: u8 = 0; - const U8_AS_FELT: felt252 = U8.into(); - assert_eq!(U8_AS_FELT, 0); - - const U16: u16 = 0; - const U16_AS_FELT: felt252 = U16.into(); - assert_eq!(U16_AS_FELT, 0); - - const U32: u32 = 0; - const U32_AS_FELT: felt252 = U32.into(); - assert_eq!(U32_AS_FELT, 0); - - const U64: u64 = 0; - const U64_AS_FELT: felt252 = U64.into(); - assert_eq!(U64_AS_FELT, 0); - - const U128: u128 = 0; - const U128_AS_FELT: felt252 = U128.into(); - assert_eq!(U128_AS_FELT, 0); - - const I8: u8 = 0; - const I8_AS_FELT: felt252 = I8.into(); - assert_eq!(I8_AS_FELT, 0); - - const I16: i16 = 0; - const I16_AS_FELT: felt252 = I16.into(); - assert_eq!(I16_AS_FELT, 0); - - const I32: i32 = 0; - const I32_AS_FELT: felt252 = I32.into(); - assert_eq!(I32_AS_FELT, 0); - - const I64: i64 = 0; - const I64_AS_FELT: felt252 = I64.into(); - assert_eq!(I64_AS_FELT, 0); - - const I128: i128 = 0; - const I128_AS_FELT: felt252 = I128.into(); - assert_eq!(I128_AS_FELT, 0); -} - -#[test] -fn test_const_from_felt252_casts() { - const IN_RANGE: felt252 = 0; - const OUT_OF_RANGE: felt252 = 2_felt252.pow(200); - - const IN_RANGE_AS_U8: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_U8: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_U8, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_U8, None); - - const IN_RANGE_AS_U16: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_U16: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_U16, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_U16, None); - - const IN_RANGE_AS_U32: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_U32: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_U32, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_U32, None); - - const IN_RANGE_AS_U64: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_U64: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_U64, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_U64, None); - - const IN_RANGE_AS_I8: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_I8: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_I8, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_I8, None); - - const IN_RANGE_AS_I16: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_I16: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_I16, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_I16, None); - - const IN_RANGE_AS_I32: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_I32: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_I32, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_I32, None); - - const IN_RANGE_AS_I64: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_I64: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_I64, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_I64, None); - - const IN_RANGE_AS_I128: Option = IN_RANGE.try_into(); - const OUT_OF_RANGE_AS_I128: Option = OUT_OF_RANGE.try_into(); - assert_eq!(IN_RANGE_AS_I128, Some(0)); - assert_eq!(OUT_OF_RANGE_AS_I128, None); -} diff --git a/corelib/src/test/iter_test.cairo b/corelib/src/test/iter_test.cairo deleted file mode 100644 index f3606b71a5..0000000000 --- a/corelib/src/test/iter_test.cairo +++ /dev/null @@ -1,266 +0,0 @@ -use core::iter::{PeekableTrait, zip}; - -#[test] -fn test_iter_count() { - let mut empty_iter = ArrayTrait::::new().into_iter(); - let count = empty_iter.count(); - assert_eq!(count, 0); - - let mut iter = array![1, 2, 3].into_iter(); - let count = iter.count(); - - assert_eq!(count, 3); -} - -#[test] -fn test_iter_last() { - assert_eq!(array![1_u8, 2, 3].into_iter().last(), Option::Some(3)); - assert_eq!(array![].into_iter().last(), Option::::None); -} - -#[test] -fn test_advance_by() { - let mut iter = array![1_u8, 2, 3, 4].into_iter(); - - assert_eq!(iter.advance_by(2), Ok(())); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.advance_by(0), Ok(())); - assert_eq!(iter.advance_by(100), Err(99)); -} - -#[test] -fn test_iter_nth() { - let mut iter = array![1_u8, 2, 3].into_iter(); - - assert_eq!(iter.nth(1), Some(2)); - assert_eq!(iter.nth(0), Some(3)); - assert_eq!(iter.nth(0), None); -} - -#[test] -fn test_iter_adapter_map() { - let mut iter = array![1, 2, 3].into_iter().map(|x| 2 * x); - - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next(), Some(6)); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iterator_enumerate() { - let mut iter = array!['a', 'b', 'c'].into_iter().enumerate(); - - assert_eq!(iter.next(), Some((0, 'a'))); - assert_eq!(iter.next(), Some((1, 'b'))); - assert_eq!(iter.next(), Some((2, 'c'))); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iterator_zip() { - let mut iter = zip(array![1, 2, 3], array![4, 5, 6]); - - assert_eq!(iter.next(), Some((1, 4))); - assert_eq!(iter.next(), Some((2, 5))); - assert_eq!(iter.next(), Some((3, 6))); - assert_eq!(iter.next(), None); - - // Nested zips - let mut iter = array![1, 2, 3].into_iter().zip(array![4, 5, 6]).zip(array![7, 8, 9]); - - assert_eq!(iter.next(), Some(((1, 4), 7))); - assert_eq!(iter.next(), Some(((2, 5), 8))); - assert_eq!(iter.next(), Some(((3, 6), 9))); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iter_adapter_fold() { - assert_eq!((1..=4_u32).into_iter().fold(0, |acc, x| acc + x), 10); - assert_eq!((2..=5_u32).into_iter().fold(1, |acc, x| acc * x), 120); -} - -#[test] -fn test_iter_adapter_collect() { - assert_eq!((0..3_u32).into_iter().collect(), array![0, 1, 2]); -} - -#[test] -fn test_iter_adapter_peekable() { - let mut iter = (1..4_u8).into_iter().peekable(); - - // peek() lets us see one step into the future - assert_eq!(iter.peek(), Option::Some(1)); - assert_eq!(iter.next(), Option::Some(1)); - assert_eq!(iter.next(), Option::Some(2)); - - // The iterator does not advance even if we `peek` multiple times - assert_eq!(iter.peek(), Option::Some(3)); - assert_eq!(iter.peek(), Option::Some(3)); - assert_eq!(iter.next(), Option::Some(3)); - - // After the iterator is finished, so is `peek()` - assert_eq!(iter.peek(), Option::None); - assert_eq!(iter.next(), Option::None); -} - -#[test] -fn test_iter_adapter_take() { - assert_eq!((1_u8..=10).into_iter().take(4).collect(), array![1, 2, 3, 4]); - assert_eq!((1_u8..=10).into_iter().take(0).collect(), array![]); -} - -#[test] -fn test_iter_adapter_take_next() { - let mut iter = (1_u8..=10).into_iter().take(2); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), None); -} - -#[test] -fn test_iter_adapter_take_nth() { - // Test when n > requested nth - let mut iter = (1_u8..=10).into_iter().take(8); - assert_eq!(iter.nth(5), Some(6)); - assert_eq!(iter.nth(1), Some(8)); - assert_eq!(iter.nth(0), None); - - // Test when n > 0 but not enough elements - let mut iter = (1_u8..=10).into_iter().take(5); - assert_eq!(iter.nth(15), None); - assert_eq!(iter.next(), None); - - // Test when n = 0 - let mut iter = (1_u8..=3).into_iter().take(0); - assert_eq!(iter.nth(0), None); -} - -#[test] -fn test_iter_adapter_take_advance_by() { - let mut iter = (1_u8..=10).into_iter().take(8); - // self.n >= n and inner iterator succeeds - assert_eq!(iter.advance_by(7), Ok(())); - assert_eq!(iter.next(), Some(8)); - assert_eq!(iter.next(), None); - - // self.n >= n but inner iterator fails - let mut iter = (1_u8..=3).into_iter().take(10); - assert_eq!(iter.advance_by(5), Err(2)); - - // self.n < n and inner iterator succeeds - let mut iter = (1_u8..=10).into_iter().take(8); - assert_eq!(iter.advance_by(9), Err(1)); - assert_eq!(iter.next(), None); - - let mut iter = (1_u8..=2).into_iter().take(10); - // self.n < n and inner iterator fails - assert_eq!(iter.advance_by(20), Err(18)); - assert_eq!(iter.next(), None); - - // self.n = 0 - let mut iter = (1_u8..=10).into_iter().take(8); - assert_eq!(iter.advance_by(0), Ok(())); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); -} - -#[test] -fn test_iter_accum_sum() { - assert_eq!(array![1, 2, 3].into_iter().sum(), 6); - assert_eq!(array![].into_iter().sum(), 0); -} - -#[test] -fn test_iter_accum_product() { - assert_eq!((1_usize..=0).into_iter().product(), 1); - assert_eq!((1_usize..=1).into_iter().product(), 1); - assert_eq!((1_usize..=5).into_iter().product(), 120); -} - -#[test] -fn test_iter_any() { - let mut iter = array![1, 2, 3].into_iter(); - assert!(iter.any(|x| x == 2)); - assert_eq!(iter.next(), Some(3)); - - let mut iter = array![1, 2, 3].into_iter(); - assert!(!iter.any(|x| x == 5)); - assert_eq!(iter.next(), None); - - let mut iter = array![].into_iter(); - assert!(!iter.any(|x| x == 1)); - - assert!(array![1, 2, 3].into_iter().any(|x| x == 2)); - assert!(!array![1, 2, 3].into_iter().any(|x| x == 5)); - assert!(!array![].into_iter().any(|x| x == 1)); -} - -#[test] -fn test_iter_all() { - let mut iter = array![1, 1, 1].into_iter(); - assert!(iter.all(|x| x == 1)); - assert_eq!(iter.next(), None); - - let mut iter = array![1, 2, 3].into_iter(); - assert!(!iter.all(|x| x == 1)); - assert_eq!(iter.next(), Some(3)); - - let mut iter = array![].into_iter(); - assert!(iter.all(|x| x == 1)); - - assert!(array![1, 1, 1].into_iter().all(|x| x == 1)); - assert!(!array![1, 2, 3].into_iter().all(|x| x == 1)); - assert!(array![].into_iter().all(|x| x == 1)); -} - -#[test] -fn test_iter_find() { - let mut iter = array![1, 2, 3].into_iter(); - assert_eq!(iter.find(|x| *x == 2), Some(2)); - assert_eq!(iter.find(|x| *x == 5), None); - - let mut iter = array![1, 2, 3].into_iter(); - assert_eq!(iter.find(|x| *x == 2), Some(2)); - assert_eq!(iter.next(), Some(3)); - - assert_eq!(array![1, 2, 3].into_iter().find(|x| *x == 2), Some(2)); - assert_eq!(array![1, 2, 3].into_iter().find(|x| *x == 5), None); -} - -#[test] -fn test_iter_adapter_filter() { - let mut iter = array![0_u32, 1, 2].into_iter().filter(|x| *x > 0); - assert_eq!(iter.next(), Option::Some(1)); - assert_eq!(iter.next(), Option::Some(2)); - assert_eq!(iter.next(), Option::None); -} - -#[test] -fn test_iterator_chain_different_types() { - let mut iter = array![7, 8, 9].into_iter().chain((0..5_u8)); - - assert_eq!(iter.next(), Option::Some(7)); - assert_eq!(iter.next(), Option::Some(8)); - assert_eq!(iter.next(), Option::Some(9)); - assert_eq!(iter.next(), Option::Some(0)); - assert_eq!(iter.next(), Option::Some(1)); - assert_eq!(iter.next(), Option::Some(2)); - assert_eq!(iter.next(), Option::Some(3)); - assert_eq!(iter.next(), Option::Some(4)); - assert_eq!(iter.next(), Option::None); -} - -#[test] -fn test_iterator_chain_same_types() { - let mut iter = array![1, 2, 3].into_iter().chain(array![4, 5, 6]); - - assert_eq!(iter.next(), Option::Some(1)); - assert_eq!(iter.next(), Option::Some(2)); - assert_eq!(iter.next(), Option::Some(3)); - assert_eq!(iter.next(), Option::Some(4)); - assert_eq!(iter.next(), Option::Some(5)); - assert_eq!(iter.next(), Option::Some(6)); - assert_eq!(iter.next(), Option::None); -} diff --git a/corelib/src/test/keccak_test.cairo b/corelib/src/test/keccak_test.cairo deleted file mode 100644 index b5e2471ea1..0000000000 --- a/corelib/src/test/keccak_test.cairo +++ /dev/null @@ -1,160 +0,0 @@ -use crate::keccak; - -#[test] -fn test_keccak_syscall() { - assert_eq!( - starknet::syscalls::keccak_syscall( - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17].span(), - ), - Ok(0xd2eb808dfba4703c528d145dfe6571afec687be9c50d2218388da73622e8fdd5), - ); -} - -#[test] -fn test_keccak_hash() { - assert_eq!( - keccak::keccak_u256s_le_inputs([1].span()), - 0xa5963aa610cb75ba273817bce5f8c48f587f7cc3722e9654ea3963d5fe8c0748, - ); - assert_eq!( - keccak::keccak_u256s_be_inputs([1].span()), - 0xf60cfab7e2cb9f2d73b0c2fa4a4bf40c326a7e71fdcdee263b071276522d0eb1, - ); - assert_eq!( - keccak::keccak_u256s_le_inputs([1, 2, 3, 4].span()), - 0x17a2126cf7391a26b41c36a687090cc5845f8e9f5191367fb5181e74f6eb550d, - ); - assert_eq!( - keccak::keccak_u256s_be_inputs([1, 2, 3, 4].span()), - 0x2d9982dfaf468a9ddf7101b6323aa9d56510e6fd534f267a01086462df912739, - ); -} - -// Same input as in `test_keccak_hash` but as a u64 array. -#[test] -fn test_keccak_u64() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, - ]; - assert_eq!( - keccak::cairo_keccak(ref input, 0, 0), - 0xa5963aa610cb75ba273817bce5f8c48f587f7cc3722e9654ea3963d5fe8c0748, - ); -} - -#[test] -fn test_keccak_u64_full_block() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, - 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, - 0x0000000000000009, 0x000000000000000a, 0x000000000000000b, 0x000000000000000c, - 0x000000000000000d, 0x000000000000000e, 0x000000000000000f, 0x0000000000000010, - 0x0000000000000011, - ]; - assert_eq!( - keccak::cairo_keccak(ref input, 0, 0), - 0x210740d45b1fe2ac908a497ef45509f55d291eebae35b254ff50ec1fc57832e8, - ); -} - -#[test] -fn test_keccak_u64_full_block_minus_byte() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, - 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, - 0x0000000000000009, 0x000000000000000a, 0x000000000000000b, 0x000000000000000c, - 0x000000000000000d, 0x000000000000000e, 0x000000000000000f, 0x0000000000000010, - ]; - - // We must clone the array to be used in the second part, as it's modified by `cairo_keccak`. - let mut orig_array = input.clone(); - - assert_eq!( - keccak::cairo_keccak(ref input, 0x12000000000011, 7), - 0xc98592786514c87f1a1a3d567b4dcd75bb968836d1704bea541a8d79dcc9067c, - ); - - // With "garbage" at the end (note the `aa`), we should get the same result. - assert_eq!( - keccak::cairo_keccak(ref orig_array, 0xaa12000000000011, 7), - 0xc98592786514c87f1a1a3d567b4dcd75bb968836d1704bea541a8d79dcc9067c, - ); -} - -#[test] -fn test_keccak_u64_full_block_minus_word() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, - 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, - 0x0000000000000009, 0x000000000000000a, 0x000000000000000b, 0x000000000000000c, - 0x000000000000000d, 0x000000000000000e, 0x000000000000000f, 0x0000000000000010, - ]; - assert_eq!( - keccak::cairo_keccak(ref input, 0, 0), - 0x6851f2dbbfb3bfadff94db3ad476164ffd9895001ee22e79b59c7997b3618a01, - ); -} - -#[test] -fn test_keccak_u64_full_block_minus_word_minus_byte() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, - 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, - 0x0000000000000009, 0x000000000000000a, 0x000000000000000b, 0x000000000000000c, - 0x000000000000000d, 0x000000000000000e, 0x000000000000000f, - ]; - - // We must clone the array to be used in the second part, as it's modified by `cairo_keccak`. - let mut orig_array = input.clone(); - - assert_eq!( - keccak::cairo_keccak(ref input, 0x11000000000010, 7), - 0xdd7e11698dc8b37323c854a53abcd3302cc6d33d8630a63c428d9cf38a89568b, - ); - - // With "garbage" at the end (note the `aa`), we should get the same result. - assert_eq!( - keccak::cairo_keccak(ref orig_array, 0xaa11000000000010, 7), - 0xdd7e11698dc8b37323c854a53abcd3302cc6d33d8630a63c428d9cf38a89568b, - ); -} - -#[test] -fn test_keccak_u64_full_block_minus_3_words_minus_4_bytes() { - let mut input = array![ - 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, - 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, - 0x0000000000000009, 0x000000000000000a, 0x000000000000000b, 0x000000000000000c, - 0x000000000000000d, - ]; - - // We must clone the array to be used in the second part, as it's modified by `cairo_keccak`. - let mut orig_array = input.clone(); - - assert_eq!( - keccak::cairo_keccak(ref input, 0x11000010, 4), - 0xf3cc56e9bd860f83e3e3bc69919b176a43ccdbe17ae03b02b308ebe4a23c4cc9, - ); - - // With "garbage" at the end (note the `aa`s), we should get the same result. - assert_eq!( - keccak::cairo_keccak(ref orig_array, 0xaaaaaaaa11000010, 4), - 0xf3cc56e9bd860f83e3e3bc69919b176a43ccdbe17ae03b02b308ebe4a23c4cc9, - ); -} - -#[test] -fn test_keccak_byte_array() { - assert_eq!( - keccak::compute_keccak_byte_array(@""), - 0x70a4855d04d8fa7b3b2782ca53b600e5c003c7dcb27d7e923c23f7860146d2c5, - ); - assert_eq!( - keccak::compute_keccak_byte_array(@"0123456789abedef"), - 0x156c8d1049ee26f4f392bf8260b9e1c5ad5542778f003235f8cf5e0a19520886, - ); - assert_eq!( - keccak::compute_keccak_byte_array(@"hello-world"), - 0xd9ba3e823d55e5075f58ee022c16025c3abe8b41b95d7b4651a3cf8422ad1bd4, - ); -} diff --git a/corelib/src/test/language_features/block_level_items_test.cairo b/corelib/src/test/language_features/block_level_items_test.cairo deleted file mode 100644 index fbbf186faf..0000000000 --- a/corelib/src/test/language_features/block_level_items_test.cairo +++ /dev/null @@ -1,202 +0,0 @@ -#[test] -fn test_const_to_const_shadowing() { - const X: u8 = 1; - assert_eq!(X, 1); - { - const X: u8 = 4; - assert_eq!(X, 4); - } - assert_eq!(X, 1); -} - -#[test] -fn test_let_to_const_shadowing() { - let X = 2; - assert_eq!(X, 2); - { - const X: u8 = 5; - assert_eq!(X, 5); - } - assert_eq!(X, 2); -} - -#[test] -fn test_const_to_let_shadowing() { - const X: u8 = 3; - assert_eq!(X, 3); - { - let X = 6; - assert_eq!(X, 6); - } - assert_eq!(X, 3); -} - -const A: u8 = 1; -#[test] -fn test_global_const_to_const_shadowing() { - assert_eq!(A, 1); - const A: u8 = 4; - assert_eq!(A, 4); -} - -#[test] -fn test_global_const_to_let_shadowing() { - assert_eq!(A, 1); - let A = 4; - assert_eq!(A, 4); -} - -pub mod single_const { - pub const A: u8 = 1; -} - -#[test] -fn test_use_usage() { - use single_const::A; - assert_eq!(A, 1); -} - -#[test] -fn test_use_usage_with_alias() { - use single_const::A as B; - assert_eq!(B, 1); -} - -#[test] -fn test_use_constant_shadowing() { - use single_const::A; - assert_eq!(A, 1); - { - const A: u8 = 4; - assert_eq!(A, 4); - } - assert_eq!(A, 1); -} - -pub mod double_const { - pub const A: u8 = 4; - pub const B: u8 = 6; -} - -#[test] -fn test_use_use_shadowing() { - use single_const::A; - assert_eq!(A, 1); - { - use double_const::A; - assert_eq!(A, 4); - } - assert_eq!(A, 1); -} - -#[test] -fn test_const_use_shadowing() { - const A: u8 = 1; - assert_eq!(A, 1); - { - use double_const::A; - assert_eq!(A, 4); - } - assert_eq!(A, 1); -} - -#[test] -fn test_use_let_shadowing() { - use single_const::A; - assert_eq!(A, 1); - { - let A = 4; - assert_eq!(A, 4); - } - assert_eq!(A, 1); -} - -#[test] -fn test_let_use_shadowing() { - let A = 1; - assert_eq!(A, 1); - { - use double_const::A; - assert_eq!(A, 4); - } - assert_eq!(A, 1); -} - -#[test] -fn test_multiple_use() { - use double_const::{A, B}; - assert_eq!(A, 4); - assert_eq!(B, 6); -} - -pub mod generic_type { - pub struct S { - pub x: u8, - } - pub enum E { - A: u8, - B: u16, - } -} - -#[test] -fn test_type_struct_usage() { - use generic_type::S; - let s = S { x: 1 }; - assert_eq!(s.x, 1); -} - -#[test] -fn test_type_enum_usage() { - use generic_type::E; - let e = E::A(1); - match e { - E::A(val) => assert_eq!(val, 1), - E::B(_) => panic!("Shouldn't get here"), - } -} - -pub mod generic_type_generics { - pub struct S { - pub x: T, - } - pub enum E { - A: T, - B: u16, - } -} - -#[test] -fn test_type_struct_generic_usage() { - use generic_type_generics::S; - let s = S:: { x: 1 }; - assert_eq!(s.x, 1); -} - -#[test] -fn test_type_enum_generic_usage() { - use generic_type_generics::E; - let e = E::A::(1); - match e { - E::A(val) => assert_eq!(val, 1), - E::B(_) => panic!("Shouldn't get here"), - } -} - -mod a { - pub mod b { - pub const C: u8 = 1; - } -} - -#[test] -fn use_module_in_statement() { - use a::b; - assert_eq!(b::C, 1); -} - -#[test] -fn use_module_in_statement_with_self() { - use a::b::{self, C}; - assert_eq!(C, b::C); -} diff --git a/corelib/src/test/language_features/box_test.cairo b/corelib/src/test/language_features/box_test.cairo deleted file mode 100644 index 9d42e4e844..0000000000 --- a/corelib/src/test/language_features/box_test.cairo +++ /dev/null @@ -1,18 +0,0 @@ -extern fn local_into_box(value: T) -> Box nopanic; - -/// Boxes a value by storing it in a local variable first (via calling conventions), then delegating -/// to `local_into_box` which expects a local. -#[inline(never)] -pub fn into_box(value: T) -> Box { - local_into_box(value) -} - -#[test] -fn test_local_into_box() { - assert_eq!(into_box((1, 2_u256, 3)).unbox(), (1, 2, 3)); - assert_eq!(into_box(()).unbox(), ()); - assert_eq!(into_box(Some(6_u8)).unbox(), Some(6)); - assert_eq!(into_box(None::).unbox(), None); - assert_eq!(into_box(Ok::(7)).unbox(), Ok(7)); - assert_eq!(into_box(Err::(8)).unbox(), Err(8)); -} diff --git a/corelib/src/test/language_features/closure_test.cairo b/corelib/src/test/language_features/closure_test.cairo deleted file mode 100644 index c08a7c3976..0000000000 --- a/corelib/src/test/language_features/closure_test.cairo +++ /dev/null @@ -1,108 +0,0 @@ -#[test] -fn closure() { - let x = 8; - let c = |a| { - if a == 2 { - return x * (a + 3); - } - 7_felt252 - }; - assert_eq!(c(2), 40); -} - -#[derive(Destruct)] -struct DestructOnly {} - -#[test] -fn closure_destruct() { - let a = DestructOnly {}; - || { - let _b = a; - }; -} - -#[derive(PanicDestruct)] -struct PanicDestructOnly {} - -#[test] -#[should_panic(expected: "outer")] -fn closure_panic_destruct() { - let a = PanicDestructOnly {}; - || -> () { - let _b = a; - panic!("inner") - }; - panic!("outer") -} - -#[test] -fn panicable_closure() { - let c = |a: u32| { - a + 3 - }; - assert_eq!(c(2), 5); -} - -struct Callable> { - f: F, -} - -#[test] -fn closure_snapshot_call() { - let callable = Callable { f: || 10_u8 }; - assert_eq!(core::ops::FnOnce::call(callable.f, ()), 10); - assert_eq!(core::ops::Fn::call(@callable.f, ()), 10); - // With snapshot - assert_eq!(core::ops::FnOnce::call(@callable.f, ()), 10); - assert_eq!(core::ops::Fn::call(@@callable.f, ()), 10); -} - -fn option_map, +Drop>( - opt: Option, f: F, -) -> Option::Output> { - match opt { - Some(x) => Some(f(x)), - None => None, - } -} - -#[test] -fn option_map_test() { - assert_eq!(option_map(Some(2), |x| x + 3), Some(5)); - assert_eq!(option_map(None, |x| x + 3), None); - assert_eq!(option_map(Some(2), |x| Some(x)), Some(Some(2))); -} - -fn fix_sized_array_map< - T, F, impl Fn: core::ops::Fn, +Drop, +Drop, +Drop, ->( - arr: [T; 2], f: F, -) -> [core::ops::Fn::::Output; 2] { - let [a, b] = arr; - [f(a), f(b)] -} - -#[test] -fn fix_sized_array_map_test() { - assert_eq!(fix_sized_array_map([2, 3], |x| x + 3), [5, 6]); -} - -#[generate_trait] -impl ArrayExt of ArrayExtTrait { - fn map, F, +Drop, impl func: core::ops::Fn, +Drop>( - self: Array, f: F, - ) -> Array { - let mut output: Array = array![]; - for elem in self { - output.append(f(elem)); - } - output - } -} - -#[test] -fn array_map_test() { - let arr = array![1, 2, 3]; - let result = arr.map(|x| x + 1); - assert_eq!(result, array![2, 3, 4]); -} diff --git a/corelib/src/test/language_features/const_folding_test.cairo b/corelib/src/test/language_features/const_folding_test.cairo deleted file mode 100644 index 42e80a383a..0000000000 --- a/corelib/src/test/language_features/const_folding_test.cairo +++ /dev/null @@ -1,59 +0,0 @@ -#[feature("bounded-int-utils")] -use core::internal::bounded_int::{BoundedInt, constrain}; -use crate::integer::i8_diff; -use crate::num::traits::{WrappingAdd, WrappingMul, WrappingSub}; - -/// Helper to prevent const folding. -#[inline(never)] -fn noop(t: T) -> T { - t -} - - -#[test] -fn test_add() { - assert!(WrappingAdd::wrapping_add(1_u8, 2) == WrappingAdd::wrapping_add(noop(1), noop(2))); - assert!( - WrappingAdd::wrapping_add(100_u8, 200) == WrappingAdd::wrapping_add(noop(100), noop(200)), - ); - assert!(WrappingAdd::wrapping_add(1_i8, 2) == WrappingAdd::wrapping_add(noop(1), noop(2))); - assert!( - WrappingAdd::wrapping_add(100_i8, 50) == WrappingAdd::wrapping_add(noop(100), noop(50)), - ); - assert!( - WrappingAdd::wrapping_add(-100_i8, -50) == WrappingAdd::wrapping_add(noop(-100), noop(-50)), - ); -} - -#[test] -fn test_sub() { - assert!(WrappingSub::wrapping_sub(1_u8, 2) == WrappingSub::wrapping_sub(noop(1), noop(2))); - assert!(WrappingSub::wrapping_sub(2_u8, 1) == WrappingSub::wrapping_sub(noop(2), noop(1))); - assert!(WrappingSub::wrapping_sub(1_i8, 2) == WrappingSub::wrapping_sub(noop(1), noop(2))); - assert!( - WrappingSub::wrapping_sub(100_i8, -50) == WrappingSub::wrapping_sub(noop(100), noop(-50)), - ); - assert!( - WrappingSub::wrapping_sub(-100_i8, 50) == WrappingSub::wrapping_sub(noop(-100), noop(50)), - ); -} - -#[test] -fn test_diff() { - assert!(i8_diff(1, 2) == i8_diff(noop(1), noop(2))); - assert!(i8_diff(2, 1) == i8_diff(noop(2), noop(1))); -} - -#[test] -fn test_mul() { - assert!(WrappingMul::wrapping_mul(1_u8, 2) == WrappingMul::wrapping_mul(noop(1), noop(2))); - assert!( - WrappingMul::wrapping_mul(100_u8, 200) == WrappingMul::wrapping_mul(noop(100), noop(200)), - ); -} - -#[test] -fn test_implied_non_zero() -> Result>, NonZero>> { - let x: NonZero = 5; - constrain::<_, 0>(x) -} diff --git a/corelib/src/test/language_features/const_test.cairo b/corelib/src/test/language_features/const_test.cairo deleted file mode 100644 index 4d03349d99..0000000000 --- a/corelib/src/test/language_features/const_test.cairo +++ /dev/null @@ -1,299 +0,0 @@ -use crate::box::BoxTrait; - -mod enum_value { - pub extern type Const; -} -mod value { - pub extern type Const; -} -mod struct0 { - pub extern type Const; -} -mod struct2 { - pub extern type Const; -} - -mod const_bool { - pub extern fn const_as_box() -> Box nopanic; -} - -#[test] -fn test_const_bool() { - assert!( - !const_bool::const_as_box::>, 0>().unbox(), - ); - assert!( - const_bool::const_as_box::>, 0>().unbox(), - ); -} - -mod const_felt252 { - pub extern fn const_as_box() -> Box nopanic; -} - -#[test] -fn test_const_felt252() { - assert!(const_felt252::const_as_box::, 1>().unbox() == 0); - assert!(const_felt252::const_as_box::, 2>().unbox() == -1); -} - -mod const_u8 { - pub extern fn const_as_box() -> Box nopanic; -} - -#[test] -fn test_const_u8() { - assert!(const_u8::const_as_box::, 0>().unbox() == 0); - assert!(const_u8::const_as_box::, 1>().unbox() == 255); -} - -mod const_u256 { - pub extern fn const_as_box() -> Box nopanic; -} - -#[test] -fn test_const_u256() { - assert!( - const_u256::const_as_box::< - struct2::Const, value::Const>, 0, - >() - .unbox() == 0x10, - ); - assert!( - const_u256::const_as_box::< - struct2::Const, value::Const>, 0, - >() - .unbox() == 0x1000000000000000000000000000000000, - ); -} - -#[derive(Copy, Drop, PartialEq, Debug)] -enum ThreeOptions { - A: felt252, - B: u256, - C, -} - -mod const_three_options { - pub extern fn const_as_box() -> Box nopanic; -} - -#[test] -fn test_complex_enum() { - assert!( - const_three_options::const_as_box::< - enum_value::Const>, 0, - >() - .unbox() == ThreeOptions::A(-1), - ); - assert!( - const_three_options::const_as_box::< - enum_value::Const< - ThreeOptions, - 1, - struct2::Const, value::Const>, - >, - 1, - >() - .unbox() == ThreeOptions::B(0x2000000000000000000000000000000010), - ); - assert!( - const_three_options::const_as_box::< - enum_value::Const>, 1, - >() - .unbox() == ThreeOptions::C, - ); -} - -#[derive(Copy, Drop, PartialEq, Debug)] -enum ThreeOptions2 { - A: felt252, - B: (u256, u256), - C, -} - -mod const_tuple_three_options { - pub extern fn const_as_box() -> Box< - (super::ThreeOptions2, super::ThreeOptions2), - > nopanic; -} - -#[test] -fn test_two_complex_enums() { - assert!( - const_tuple_three_options::const_as_box::< - struct2::Const< - (ThreeOptions2, ThreeOptions2), - enum_value::Const>, - enum_value::Const>, - >, - 0, - >() - .unbox() == (ThreeOptions2::A(1337), ThreeOptions2::C), - ); -} - -#[test] -fn test_complex_consts() { - const VAR_AND_MATCH_CONST: felt252 = { - let x = Some((1, 2_u8)); - match x { - Some((v, _)) => v, - None => 3, - } - }; - assert_eq!(VAR_AND_MATCH_CONST, 1); - const TRUE: bool = true; - const IF_CONST_TRUE: felt252 = if TRUE { - 4 - } else { - 5 - }; - assert_eq!(IF_CONST_TRUE, 4); - const FALSE: bool = false; - const IF_CONST_FALSE: felt252 = if FALSE { - 6 - } else { - 7 - }; - assert_eq!(IF_CONST_FALSE, 7); -} - -#[test] -fn test_const_casts_from_felt252() { - const _U8_UNDER_RANGE: () = assert((-1_felt252).try_into() == None::, 'U8 under range'); - const _U8_MIN_IN_RANGE: () = assert(0_felt252.try_into() == Some(0_u8), 'U8 min in range'); - const _U8_MAX_IN_RANGE: () = assert( - 0xff_felt252.try_into() == Some(0xff_u8), 'U8 max in range', - ); - const _U8_OVER_RANGE: () = assert(0x100_felt252.try_into() == None::, 'U8 over range'); - const _U16_UNDER_RANGE: () = assert((-1_felt252).try_into() == None::, 'U16 under range'); - const _U16_MIN_IN_RANGE: () = assert(0_felt252.try_into() == Some(0_u16), 'U16 min in range'); - const _U16_MAX_IN_RANGE: () = assert( - 0xffff_felt252.try_into() == Some(0xffff_u16), 'U16 max in range', - ); - const _U16_OVER_RANGE: () = assert(0x10000_felt252.try_into() == None::, 'U16 over range'); - const _U32_UNDER_RANGE: () = assert((-1_felt252).try_into() == None::, 'U32 under range'); - const _U32_MIN_IN_RANGE: () = assert(0_felt252.try_into() == Some(0_u32), 'U32 min in range'); - const _U32_MAX_IN_RANGE: () = assert( - 0xffffffff_felt252.try_into() == Some(0xffffffff_u32), 'U32 max in range', - ); - const _U32_OVER_RANGE: () = assert( - 0x100000000_felt252.try_into() == None::, 'U32 over range', - ); - const _U64_UNDER_RANGE: () = assert((-1_felt252).try_into() == None::, 'U64 under range'); - const _U64_MIN_IN_RANGE: () = assert(0_felt252.try_into() == Some(0_u64), 'U64 min in range'); - const _U64_MAX_IN_RANGE: () = assert( - 0xffffffffffffffff_felt252.try_into() == Some(0xffffffffffffffff_u64), 'U64 max in range', - ); - const _U64_OVER_RANGE: () = assert( - 0x10000000000000000_felt252.try_into() == None::, 'U64 over range', - ); - const _U128_UNDER_RANGE: () = assert( - (-1_felt252).try_into() == None::, 'U128 under range', - ); - const _U128_MIN_IN_RANGE: () = assert( - 0_felt252.try_into() == Some(0_u128), 'U128 min in range', - ); - const _U128_MAX_IN_RANGE: () = assert( - 0xffffffffffffffffffffffffffffffff_felt252 - .try_into() == Some(0xffffffffffffffffffffffffffffffff_u128), - 'U128 max in range', - ); - const _U128_OVER_RANGE: () = assert( - 0x100000000000000000000000000000000_felt252.try_into() == None::, 'U128 over range', - ); - const _I8_UNDER_RANGE: () = assert((-0x81_felt252).try_into() == None::, 'I8 under range'); - const _I8_MIN_IN_RANGE: () = assert( - (-0x80_felt252).try_into() == Some(-0x80_i8), 'I8 min in range', - ); - const _I8_MAX_IN_RANGE: () = assert( - 0x7f_felt252.try_into() == Some(0x7f_i8), 'I8 max in range', - ); - const _I8_OVER_RANGE: () = assert(0x80_felt252.try_into() == None::, 'I8 over range'); - const _I16_UNDER_RANGE: () = assert( - (-0x8001_felt252).try_into() == None::, 'I16 under range', - ); - const _I16_MIN_IN_RANGE: () = assert( - (-0x8000_felt252).try_into() == Some(-0x8000_i16), 'I16 min in range', - ); - const _I16_MAX_IN_RANGE: () = assert( - 0x7fff_felt252.try_into() == Some(0x7fff_i16), 'I16 max in range', - ); - const _I16_OVER_RANGE: () = assert(0x8000_felt252.try_into() == None::, 'I16 over range'); - const _I32_UNDER_RANGE: () = assert( - (-0x80000001_felt252).try_into() == None::, 'I32 under range', - ); - const _I32_MIN_IN_RANGE: () = assert( - (-0x80000000_felt252).try_into() == Some(-0x80000000_i32), 'I32 min in range', - ); - const _I32_MAX_IN_RANGE: () = assert( - 0x7fffffff_felt252.try_into() == Some(0x7fffffff_i32), 'I32 max in range', - ); - const _I32_OVER_RANGE: () = assert( - 0x80000000_felt252.try_into() == None::, 'I32 over range', - ); - const _I64_UNDER_RANGE: () = assert( - (-0x8000000000000001_felt252).try_into() == None::, 'I64 under range', - ); - const _I64_MIN_IN_RANGE: () = assert( - (-0x8000000000000000_felt252).try_into() == Some(-0x8000000000000000_i64), - 'I64 min in range', - ); - const _I64_MAX_IN_RANGE: () = assert( - 0x7fffffffffffffff_felt252.try_into() == Some(0x7fffffffffffffff_i64), 'I64 max in range', - ); - const _I64_OVER_RANGE: () = assert( - 0x8000000000000000_felt252.try_into() == None::, 'I64 over range', - ); - const _I128_UNDER_RANGE: () = assert( - (-0x80000000000000000000000000000001_felt252).try_into() == None::, - 'I128 under range', - ); - const _I128_MIN_IN_RANGE: () = assert( - (-0x80000000000000000000000000000000_felt252) - .try_into() == Some(-0x80000000000000000000000000000000_i128), - 'I128 min in range', - ); - const _I128_MAX_IN_RANGE: () = assert( - 0x7fffffffffffffffffffffffffffffff_felt252 - .try_into() == Some(0x7fffffffffffffffffffffffffffffff_i128), - 'I128 max in range', - ); - const _I128_OVER_RANGE: () = assert( - 0x80000000000000000000000000000000_felt252.try_into() == None::, 'I128 over range', - ); - const _U256_FROM_ZERO: () = assert(0_felt252.into() == 0_u256, 'U256 from zero'); - const _U256_FROM_ONE: () = assert(1_felt252.into() == 1_u256, 'U256 from one'); - const _U256_FROM_MINUS_ONE: () = assert( - (-1_felt252) - .into() == 0x800000000000011000000000000000000000000000000000000000000000000_u256, - 'U256 under range', - ); -} - -mod const_starknet_consts { - pub extern fn const_as_box() -> Box< - (starknet::ContractAddress, starknet::ClassHash), - > nopanic; -} - -const STARKNET_CONSTS: (starknet::ContractAddress, starknet::ClassHash) = ( - 1000.try_into().unwrap(), 1001.try_into().unwrap(), -); - -#[test] -fn test_starknet_consts() { - assert!( - const_starknet_consts::const_as_box::< - struct2::Const< - (starknet::ContractAddress, starknet::ClassHash), - value::Const, - value::Const, - >, - 0, - >() - .unbox() == STARKNET_CONSTS, - ); -} - diff --git a/corelib/src/test/language_features/early_return_test.cairo b/corelib/src/test/language_features/early_return_test.cairo deleted file mode 100644 index 7e27696bc6..0000000000 --- a/corelib/src/test/language_features/early_return_test.cairo +++ /dev/null @@ -1,169 +0,0 @@ -#[test] -fn test_loop_with_early_return() { - let loop_func = |mut x: u32| { - loop { - let y = x + 1; - x = y; - if y == 10 { - break true; - } - - if y == 5 { - return 5; - } - } - 1 - }; - - assert_eq!(loop_func(4), 5); -} - -#[test] -fn test_nested_loop() { - let loop_func = |a| { - loop { - loop { - if a == 0 { - break; - } - return 6; - } - - return 5; - } - }; - - assert_eq!(loop_func(0), 5); - assert_eq!(loop_func(1), 6); -} - - -#[test] -fn test_loop_for_while() { - let loop_func = |a| { - loop { - for v in a { - if v == 0 { - break; - } - while v != 2 { - return 6; - } - return 7; - } - - return 5; - } - }; - - assert_eq!(loop_func(array![0]), 5); - assert_eq!(loop_func(array![1]), 6); - assert_eq!(loop_func(array![2]), 7); -} - - -#[test] -fn test_while_for() { - let loop_func = |a: Array<_>| { - while a.len() != 0 { - for v in a { - if v == 0 { - break; - } - - return 7; - } - - return 5; - } - - 8 - }; - - assert_eq!(loop_func(array![]), 8); - assert_eq!(loop_func(array![0]), 5); - assert_eq!(loop_func(array![1]), 7); -} - - -#[test] -fn test_loop_inside_for() { - let loop_func = |a: Array<_>| { - for v in a { - loop { - if v == 0 { - break; - } - - return 5; - } - - if v == 1 { - continue; - } - return 6; - } - - return 7; - }; - - assert_eq!(loop_func(array![]), 7); - assert_eq!(loop_func(array![0, 1]), 6); - assert_eq!(loop_func(array![1, 0]), 5); -} - - -#[test] -fn test_loop_inside_while() { - let loop_func = |mut a: Array<_>| { - while let Some(v) = a.pop_front() { - if v == 1 { - continue; - } - - loop { - if v == 0 { - break; - } - - return 5; - } - - return 6; - } - 7 - }; - - assert_eq!(loop_func(array![]), 7); - assert_eq!(loop_func(array![0, 1]), 6); - assert_eq!(loop_func(array![1, 1]), 7); - assert_eq!(loop_func(array![1, 1]), 7); -} - - -#[test] -fn test_error_propagation() { - let bar = |a: u32| -> Result<(), u32> { - if a == 0 { - return Ok(()); - } - Err(a) - }; - - let loop_func1 = |a: u32| -> Result<(), u32> { - loop { - bar(a)?; - } - }; - - let loop_func2 = |a: u32| -> Result<(), u32> { - for _ in 1..2_u32 { - bar(a)?; - } - Err(7) - }; - - assert_eq!(loop_func1(1), Result::Err(1)); - assert_eq!(loop_func2(0), Result::Err(7)); - assert_eq!(loop_func2(1), Result::Err(1)); -} diff --git a/corelib/src/test/language_features/for_test.cairo b/corelib/src/test/language_features/for_test.cairo deleted file mode 100644 index 3f1be94e94..0000000000 --- a/corelib/src/test/language_features/for_test.cairo +++ /dev/null @@ -1,65 +0,0 @@ -#[test] -fn test_for_loop_array_sum() { - let mut sum = 0; - for x in array![10, 11, 12] { - sum += x; - } - assert_eq!(sum, 33); -} - -#[test] -fn test_for_loop_array_variables() { - let mut i = 10; - for x in array![10, 11, 12] { - assert_eq!(i, x); - i += 1; - } -} - -#[test] -fn test_for_loop_array_tuples() { - let mut i = 10; - for (x, y) in array![ - (10, 10), (11, 11), (12, 12), (13, 13), (14, 14), (15, 15), (16, 16), (17, 17), - ] { - assert_eq!(x, i); - assert_eq!(y, i); - i += 1; - } -} - -#[test] -fn test_for_loop_span_iter() { - let mut i = 1; - let mut sum = 0; - for x in array![1, 2, 3].span() { - assert_eq!(*x, i); - i += 1; - sum += *x; - } - assert_eq!(sum, 6); -} - -#[test] -fn test_for_loop_array_iter() { - let arr_iter = array![1, 2, 3].into_iter(); - let mut i = 1; - let mut sum = 0; - for x in arr_iter { - assert_eq!(x, i); - i += 1; - sum += x; - } - assert_eq!(sum, 6); -} - -#[test] -fn test_for_loop_range() { - let mut sum = 0_u8; - for i in 5_u8..11 { - for j in 7..i { - sum += j; - } - } - assert_eq!(sum, 46); -} diff --git a/corelib/src/test/language_features/glob_use_test.cairo b/corelib/src/test/language_features/glob_use_test.cairo deleted file mode 100644 index c5df881479..0000000000 --- a/corelib/src/test/language_features/glob_use_test.cairo +++ /dev/null @@ -1,27 +0,0 @@ -mod a { - pub const NON_SHADOWED: felt252 = 'non_shadowed'; - pub const SHADOWED: felt252 = 'original_shadowed'; - pub const PUBLISHED_ONCE: felt252 = 'published_once'; -} - -mod b { - const PUBLISHED_ONCE: felt252 = 'ignored'; - #[allow(unused_imports)] - use core::array::Span; -} - -pub const SHADOWED: felt252 = 'new_shadowed'; -use a::*; -use b::*; - -#[test] -fn test_use_star_shadowing() { - assert_eq!(NON_SHADOWED, 'non_shadowed'); - assert_eq!(SHADOWED, 'new_shadowed'); -} - -#[test] -fn test_use_star_non_pub() { - assert_eq!(PUBLISHED_ONCE, 'published_once'); - let _x: Span = [].span(); -} diff --git a/corelib/src/test/language_features/macro_test.cairo b/corelib/src/test/language_features/macro_test.cairo deleted file mode 100644 index 7ca20a5418..0000000000 --- a/corelib/src/test/language_features/macro_test.cairo +++ /dev/null @@ -1,713 +0,0 @@ -macro count_idents { - ($x:ident) => { 1 }; - - ($x:ident, $y:ident) => { 2 }; - - ($x:ident, $y:ident, $z:ident) => { 3 }; - - ($x:ident $y:ident $z:ident) => { 3 }; - - ($x:ident | $y:ident | $z:ident) => { 3 }; - - (abc {$x:ident, (abc $y:ident) }) => { 2 }; -} - -#[test] -fn test_macro_count_idents() { - assert_eq!(count_idents!(x), 1); - assert_eq!(count_idents!(x, y), 2); - assert_eq!(count_idents!(x, y, z), 3); - assert_eq!(count_idents!(x y z), 3); - assert_eq!(count_idents!(x | y | z), 3); - assert_eq!(count_idents!(abc {x, (abc y) }), 2); -} - -macro add_one { - ($x:ident) => { $x + 1 }; -} - -#[test] -fn test_macro_add_one() { - let x1 = 1; - let x2 = 2; - let x3 = 3; - assert_eq!(add_one!(x1), 2); - assert_eq!(add_one!(x2), 3); - assert_eq!(add_one!(x3), 4); -} - -mod test_assert_eq { - macro assert_eq { - ($left:ident, $right:ident) => { - if $left != $right { - $callsite::panic!("PANIC!"); - } - }; - } - - #[test] - #[should_panic(expected: ("PANIC!",))] - fn test_user_defined_assert_eq() { - { - let x = 1; - let y = 2; - assert_eq!(x, y); - } - } -} - -macro add_exprs { - ($x:expr) => { $x + 1 }; - - ($x:expr 2) => { $x + 2 }; - - ($x:ident 1) => { $x + 1 }; - - ($x:expr $y:expr) => { $x + $y }; - - (abc $x:expr $y:expr) => { $x + $y }; -} - -#[test] -fn test_add_exprs() { - assert_eq!(add_exprs!(3), 4); - let x = 1; - assert_eq!(add_exprs!(x 1), 2); - assert_eq!(add_exprs!(2 - 1), 2); - assert_eq!(add_exprs!(3 123), 126); - assert_eq!(add_exprs!(abc 1 2), 3); - assert_eq!(add_exprs!(0 2), 2); - assert_eq!(add_exprs!(0 + 2), 3); -} - - -mod inner { - fn foo(x: felt252) -> felt252 { - x + 1 - } - - pub macro add_one { - ($x:ident) => { $defsite::foo($x) }; - } - - pub macro add_ten { - ($x:ident) => { $defsite::foo($x) + 9 }; - } - - pub macro add_recursive { - ($x:ident) => { - { - let x = $x; - $defsite::foo(x) + $defsite::inner::add_one!(x) - } - }; - } - mod inner { - fn foo(x: felt252) -> felt252 { - x + 2 - } - - pub macro add_one { - ($x:expr) => { $defsite::foo($x) }; - } - } -} - - -#[test] -fn test_macro_add_one_with_defsite() { - let x1 = 1; - let x2 = 2; - let x3 = 3; - assert_eq!(inner::add_one!(x1), 2); - assert_eq!(inner::add_one!(x2), 3); - assert_eq!(inner::add_one!(x3), 4); -} - - -#[test] -fn test_macro_add_recursive() { - let x1 = 1; - let x2 = 2; - let x3 = 3; - assert_eq!(inner::add_recursive!(x1), 5); - assert_eq!(inner::add_recursive!(x2), 7); - assert_eq!(inner::add_recursive!(x3), 9); -} - -#[test] -fn test_macro_add_ten() { - let x1 = 1; - let x2 = 2; - let x3 = 3; - assert_eq!(inner::add_ten!(x1), 11); - assert_eq!(inner::add_ten!(x2), 12); - assert_eq!(inner::add_ten!(x3), 13); -} - -macro accessing_expanded_placeholders { - ($x:expr, $y:expr) => { ($x, $y) }; - - ($x:expr) => { - { - let z = 2; - $defsite::accessing_expanded_placeholders!($x, z) - } - }; -} - -#[test] -fn test_accessing_expanded_placeholders() { - let x = 1; - assert_eq!(accessing_expanded_placeholders!(x), (1, 2)); -} - -macro use_z_from_callsite { - () => { - { - let z = 4; - ($callsite::z, z) - } - }; -} - -#[test] -fn test_use_z_from_callsite() { - let z = 3; - assert_eq!(use_z_from_callsite!(), (3, 4)); -} - -macro macro_wrapped_use_z_from_callsite { - () => { - { - let z = 2; - $defsite::use_z_from_callsite!() - } - }; -} - -#[test] -fn test_wrap_use_z_from_callsite() { - assert_eq!(macro_wrapped_use_z_from_callsite!(), (2, 4)); -} - -mod repetition_macro_matcher { - macro matcher_plus { - ($($x:expr), +) => { 111 }; - } - - macro matcher_star { - ($($x:expr), *) => { 222 }; - } - - macro matcher_optional { - ($($x:expr)?) => { 333 }; - } - - macro matcher_ident_star { - ($($x:ident) *) => { 444 }; - } - - #[test] - fn repetition_macro_matcher() { - assert_eq!(matcher_plus!(1), 111); - assert_eq!(matcher_plus!(1, 2), 111); - #[cairofmt::skip] - assert_eq!(matcher_plus!(1, 2,), 111); - #[cairofmt::skip] - assert_eq!(matcher_plus!(1,), 111); - - assert_eq!(matcher_star!(), 222); - assert_eq!(matcher_star!(3), 222); - assert_eq!(matcher_star!(4, 5), 222); - #[cairofmt::skip] - assert_eq!(matcher_star!(3,), 222); - #[cairofmt::skip] - assert_eq!(matcher_star!(4, 5,), 222); - - assert_eq!(matcher_optional!(), 333); - assert_eq!(matcher_optional!(9), 333); - - let _x1 = 42; - assert_eq!(matcher_ident_star!(_x1), 444); - assert_eq!(matcher_ident_star!(_x1 _x1 _x1), 444); - } -} - -mod repetition_macro_expansion { - macro repetition_macro_expansion { - ($($x:ident), +) => { array![$($x + 2), +] }; - - ($($x:expr), *) => { array![$($x + 1), *] }; - } - - - #[test] - fn test_repetition_macro_expansion() { - let expected_expr = array![2, 3]; - let actual_expr = repetition_macro_expansion!(1, 2); - assert_eq!(expected_expr, actual_expr); - let x = 1; - let expected_ident = array![3]; - let actual_ident = repetition_macro_expansion!(x); - assert_eq!(expected_ident, actual_ident); - } -} - -macro count_exprs_rec { - [] => { 0 }; - - [$x:expr] => { 1 }; - - [$x:expr, $($xs:expr), +] => { 1 + count_exprs_rec![$($xs), +] }; -} - -#[test] -fn test_count_exprs_rec() { - assert_eq!(count_exprs_rec![], 0); - assert_eq!(count_exprs_rec![5], 1); - assert_eq!(count_exprs_rec![5, 6], 2); - assert_eq!(count_exprs_rec![1 + 2, 3 * 4, 5 - 6], 3); - assert_eq!(count_exprs_rec![10, 20, 30, 40, 50], 5); -} - -macro rev_array { - [] => { - $defsite::ArrayTrait::new() - }; - - [$first:expr $(, $rest:expr)*] => { - { - let mut arr = $defsite::rev_array![$($rest), *]; - arr.append($first); - arr - } - }; -} - -#[test] -fn test_array_macro() { - let result = rev_array![1, 2, 3]; - let mut expected = array![3, 2, 1]; - assert_eq!(result, expected); -} - -mod callsite_test { - fn foo(x: felt252) -> felt252 { - x + 100 - } - - mod inner { - fn foo(x: felt252) -> felt252 { - x + 200 - } - - pub macro call_foo { - ($x:expr) => { $callsite::foo($x) }; - } - } - - #[test] - fn test_callsite_resolution() { - assert_eq!(inner::call_foo!(5), 105); - assert_eq!(inner::call_foo!((foo(5))), 205); - } -} - -macro statement_expansion { - [$($x:expr), *] => { - { - let mut arr = $defsite::ArrayTrait::new (); - $(arr.append ($x); arr.append ($x);)* - arr - } - }; -} - -#[test] -fn test_statement_expansion() { - let result = statement_expansion![1, 2, 3]; - let mut expected = array![1, 1, 2, 2, 3, 3]; - assert_eq!(result, expected); -} - -mod defsite_as_type { - type u32_redefinition = u32; - pub macro use_redefinition { - ($x:expr) => { - { - let mut x: $defsite::u32_redefinition = $x; - x - } - }; - } -} - -#[test] -fn test_defsite_as_type() { - let _y = defsite_as_type::use_redefinition!(5_u32); -} - - -mod defsite_inference { - #[derive(Drop, Copy, Default)] - pub struct A { - pub x: u32, - } - pub macro use_local_type { - ($y:expr) => { - { - let mut x: $defsite::A = $defsite::A{ - x: 0, - }; - x.x = $y; - x - } - }; - } - pub macro use_local_impl_inference { - ($y:expr) => { - { - let mut x: $defsite::A = $defsite::Default::default(); - x.x = $y; - x - } - }; - } -} - - -#[test] -fn test_defsite_inference() { - let y: defsite_inference::A = defsite_inference::use_local_type!(5); - let z: defsite_inference::A = defsite_inference::use_local_impl_inference!(5); - assert_eq!(y.x, z.x); -} - - -macro tail_only { - () => { - 123 - }; -} - -macro wrapped_tail_only { - () => { - $defsite::tail_only!() - }; -} - -macro statements_and_tail { - () => { - let _y = 5; - 42 - }; -} - -#[test] -fn test_tail_macro_in_statement_position() { - let _x = 1; - wrapped_tail_only!(); -} - -#[test] -fn test_tail_macro_in_tail_position() -> felt252 { - let _x = 1; - wrapped_tail_only!() -} - -#[test] -fn test_statements_and_tail_macro_in_statement_position() { - statements_and_tail!(); -} - -#[test] -fn test_statements_and_tail_macro_in_tail_position() -> felt252 { - statements_and_tail!() -} - -mod unhygienic_expose_plugin_macro { - #[test] - fn test_expose_variable() { - expose!(let a = 1;); - assert_eq!(a, 1); - } - - #[test] - fn test_expose_multiple_variables() { - expose!(let a = 10; let b = 20;); - assert_eq!(a, 10); - assert_eq!(b, 20); - } - - #[test] - fn test_expose_shadowing() { - let a = 5; - assert_eq!(a, 5); - expose!{let a = 42; }; - assert_eq!(a, 42); - } - - #[test] - fn test_expose_variable_and_use_in_macro() { - let x = 7; - expose!(let y = x + 1;); - assert_eq!(y, 8); - } - - #[test] - fn test_expose_variable_used_in_next_expose() { - expose!(let a = 2;); - expose!(let b = a + 3;); - assert_eq!(a, 2); - assert_eq!(b, 5); - } - - macro my_expose { - () => { - expose!(let a = 10;); - }; - } - #[test] - fn test_expose_inside_a_macro() { - my_expose!(); - assert_eq!(a, 10); - } - - macro outer { - () => { - expose!(let outer_var = 11;); - $defsite::middle!(); - }; - } - - macro middle { - () => { - expose!(let middle_var = 22;); - assert_eq!($callsite::outer_var, 11); - expose!(let outer_var = 1;); - assert_eq!(outer_var, 1); - $defsite::inner_most!(); - }; - } - - macro inner_most { - () => { - expose!(let deeply_nested = 3;); - assert_eq!($callsite::middle_var, 22); - expose!(let middle_var = 2;); - assert_eq!(middle_var, 2); - }; - } - - #[test] - fn test_expose_deep_nested_macros() { - outer!(); - assert_eq!(outer_var, 1); - assert_eq!(middle_var, 2); - assert_eq!(deeply_nested, 3); - } - - macro set_var_macro { - ($val:expr) => { - let from_inner = $val; - }; - } - - macro wrap_expose_macro { - () => { - expose!($defsite::set_var_macro!(123);); - }; - } - - #[test] - fn test_expose_expansion_inside_wrap_expose_macro_with_param() { - wrap_expose_macro!(); - assert_eq!(from_inner, 123); - } - - macro expose_let_var { - ($expr:expr) => { - expose!(let expose_var = $expr;); - }; - } - - #[test] - fn test_expose_let_var_macro() { - expose_let_var!(1); - assert_eq!(expose_var, 1); - } - - macro expose_mappings_shift { - ($x:ident) => { - expose!(let y = $x + 1;); - }; - } - - #[test] - fn test_mappings_shift() { - let z = 1; - expose_mappings_shift!(z); - assert_eq!(y, 2); - } -} - -mod item_level_macro { - macro define_fn { - ($name:ident) => { - expose! { - fn $name() -> felt252 { 100 } - } - }; - } - - define_fn!(func_macro_fn); - - #[test] - fn test_func_macro_fn() { - assert_eq!(func_macro_fn(), 100); - } - - macro define_ty_and_getter { - ($ty:ident) => { - expose! { - struct $ty { pub x: felt252 } - fn get_x(s: $ty) -> felt252 { - s.x - } - } - }; - } - - define_ty_and_getter!(MyStruct); - - #[test] - fn test_define_ty_and_getter() { - let s = MyStruct { x: 42 }; - assert_eq!(get_x(s), 42); - } - - macro define_enum { - ($name: ident) => { - expose! { - #[derive(PartialEq, Debug, Drop)] - enum $name { - A, - B, - } - } - }; - } - - define_enum!(MyEnum); - - #[test] - fn test_enum_macro() { - let e = MyEnum::B; - assert_eq!(e, MyEnum::B); - } - - macro generic_fn_macro { - () => { - expose! { - fn id(x: T) -> T { x } - } - }; - } - - generic_fn_macro!(); - - #[test] - fn test_generic_fn_macro() { - assert_eq!(id(5), 5); - assert_eq!(id(123), 123); - } - - macro define_in_mod { - ($module:ident, $name:ident) => { - expose! { - mod $module { - pub fn $name() -> felt252 { 77 } - } - } - }; - } - - define_in_mod!(a, b); - - #[test] - fn test_defined_in_mod_through_macro() { - assert_eq!(a::b(), 77); - } - - macro define_outer_and_call_inner { - () => { - expose! { - fn outer() -> felt252 { 10 } - $defsite::define_inner!(); - } - }; - } - - macro define_inner { - () => { - fn inner() -> felt252 { 20 } - }; - } - - define_outer_and_call_inner!(); - - #[test] - fn test_nested_macro_expansion() { - assert_eq!(outer(), 10); - assert_eq!(inner(), 20); - } - - mod macro_vs_global_use { - mod has_foo { - pub fn foo() -> felt252 { - 'in module' - } - } - - macro define_foo { - () => { - expose! { - fn foo() -> felt252 { - 'in macro' - } - } - }; - } - use has_foo::*; - define_foo!(); - - #[test] - fn test_macro_wins_over_global_use() { - assert_eq!(foo(), 'in macro'); - } - } - - mod unexposed_macro_vs_global_use { - mod has_foo { - pub fn foo() -> felt252 { - 'in module' - } - } - - macro define_foo { - () => { - fn foo() -> felt252 { - 'in macro' - } - }; - } - use has_foo::*; - define_foo!(); - - #[test] - fn test_unexposed_macro_not_found() { - assert_eq!(foo(), 'in module'); - } - } -} diff --git a/corelib/src/test/language_features/match_test.cairo b/corelib/src/test/language_features/match_test.cairo deleted file mode 100644 index eeb03ae71b..0000000000 --- a/corelib/src/test/language_features/match_test.cairo +++ /dev/null @@ -1,26 +0,0 @@ -#[test] -fn test_match_multienum_binding() { - if true { - match @@Some(@Some(@2)) { - Some(Some(x)) => { - assert_eq!(x, @@@@2); - return; - }, - _ => panic!("Expected Some(Some(2)), but got a different pattern"), - } - } - panic!("Match expression did not return - this should be unreachable"); -} - -#[test] -fn test_match_extern_multilevel() { - if true { - let x: Option>> = Some(Some(None)); - let b = BoxTrait::new(x); - match b.unbox() { - Some(Some(None)) => { return; }, - _ => panic!("Expected Some(Some(None)), but got a different pattern"), - } - } - panic!("Match expression did not return - this should be unreachable"); -} diff --git a/corelib/src/test/language_features/other_paths/a.cairo b/corelib/src/test/language_features/other_paths/a.cairo deleted file mode 100644 index 14e305e1fe..0000000000 --- a/corelib/src/test/language_features/other_paths/a.cairo +++ /dev/null @@ -1 +0,0 @@ -pub const VALUE: felt252 = 'a'; diff --git a/corelib/src/test/language_features/other_paths/b.cairo b/corelib/src/test/language_features/other_paths/b.cairo deleted file mode 100644 index 880de129b3..0000000000 --- a/corelib/src/test/language_features/other_paths/b.cairo +++ /dev/null @@ -1 +0,0 @@ -pub const VALUE: felt252 = 'b'; diff --git a/corelib/src/test/language_features/other_paths/c.cairo b/corelib/src/test/language_features/other_paths/c.cairo deleted file mode 100644 index 88cbd03f18..0000000000 --- a/corelib/src/test/language_features/other_paths/c.cairo +++ /dev/null @@ -1 +0,0 @@ -pub const VALUE: felt252 = 'c'; diff --git a/corelib/src/test/language_features/other_paths/define_c.cairo b/corelib/src/test/language_features/other_paths/define_c.cairo deleted file mode 100644 index 5de5a7c6a6..0000000000 --- a/corelib/src/test/language_features/other_paths/define_c.cairo +++ /dev/null @@ -1,4 +0,0 @@ -#[path("../other_paths/c.cairo")] -mod c; - -pub const VALUE: felt252 = c::VALUE; diff --git a/corelib/src/test/language_features/other_paths/inner/a.cairo b/corelib/src/test/language_features/other_paths/inner/a.cairo deleted file mode 100644 index 2391fc339f..0000000000 --- a/corelib/src/test/language_features/other_paths/inner/a.cairo +++ /dev/null @@ -1 +0,0 @@ -pub const VALUE: felt252 = 'inner/a'; diff --git a/corelib/src/test/language_features/other_paths/inner/b.cairo b/corelib/src/test/language_features/other_paths/inner/b.cairo deleted file mode 100644 index 0010a8bc7c..0000000000 --- a/corelib/src/test/language_features/other_paths/inner/b.cairo +++ /dev/null @@ -1 +0,0 @@ -pub const VALUE: felt252 = 'inner/b'; diff --git a/corelib/src/test/language_features/panics_test.cairo b/corelib/src/test/language_features/panics_test.cairo deleted file mode 100644 index 71fd4d919a..0000000000 --- a/corelib/src/test/language_features/panics_test.cairo +++ /dev/null @@ -1,156 +0,0 @@ -use crate::byte_array::BYTE_ARRAY_MAGIC; -use crate::{panic_with_felt252, panics}; - -#[test] -#[should_panic(expected: 'short_string')] -fn test_panic_with_short_string() { - panic_with_felt252('short_string'); -} - -#[test] -#[should_panic(expected: 1)] -fn test_panic_with_felt252() { - panic_with_felt252(1); -} - -#[test] -#[should_panic(expected: "")] -fn test_panic_with_byte_array_empty() { - let ba: ByteArray = Default::default(); - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: "error")] -fn test_panic_with_byte_array_short() { - let ba: ByteArray = "error"; - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: "long error with more than 31 characters")] -fn test_panic_with_byte_array_long() { - let ba: ByteArray = "long error with more than 31 characters"; - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: "long err\0r with more than 31 characters")] -fn test_panic_with_byte_array_null_in_full_word() { - let mut ba: ByteArray = "long err"; - ba.append_byte(0); - let ba2: ByteArray = "r with more than 31 characters"; - ba.append(@ba2); - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: "long error with more than 31 character\0s")] -fn test_panic_with_byte_array_null_in_pending() { - let mut ba: ByteArray = "long error with more than 31 character"; - ba.append_byte(0); - let ba2: ByteArray = "s"; - ba.append(@ba2); - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: "\0error")] -fn test_panic_with_byte_array_null_in_beginning() { - let mut ba: ByteArray = ""; - ba.append_byte(0); - let ba2: ByteArray = "error"; - ba.append(@ba2); - panics::panic_with_byte_array(@ba); -} - -#[test] -#[should_panic(expected: ("error", 11, "hello", 5, 'short_string'))] -fn test_panic_with_stacked_errors() { - let mut error = array![]; - let ba: ByteArray = "error"; - error.append(BYTE_ARRAY_MAGIC); - ba.serialize(ref error); - - error.append(11); - - let ba: ByteArray = "hello"; - error.append(BYTE_ARRAY_MAGIC); - ba.serialize(ref error); - - error.append(5); - error.append('short_string'); - - panic(error); -} - -#[test] -#[should_panic( - expected: ( - 0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3, // BYTE_ARRAY_MAGIC - 1, - 0x161616161616161616161616161616161616161616161616161616161616161, - 0, - 0, - ), -)] -fn test_panic_with_byte_array_invalid_full_word() { - // This is a serialized ByteArray, but the full word is an invalid short string (> 2^248). - let mut error = array![ - BYTE_ARRAY_MAGIC, 1, // A single full word. - 0x161616161616161616161616161616161616161616161616161616161616161, // The invalid full word. - 0, 0 // pending byte is empty. - ]; - panic(error); -} - -#[test] -#[should_panic( - expected: ( - 0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3, // BYTE_ARRAY_MAGIC - 0, - 'aa', - 1, - ), -)] -fn test_panic_with_byte_array_invalid_pending_word() { - // This is a serialized ByteArray, but the pending word length < the actual data in the pending - // word. - let mut error = array![ - BYTE_ARRAY_MAGIC, 0, // No full words. - 'aa', - 1 // pending word length. Smaller than the actual data in the pending word. - ]; - panic(error); -} - -#[test] -#[should_panic(expected: "")] -fn test_panic_macro_empty() { - panic!() -} - -#[test] -#[should_panic(expected: "basic")] -fn test_panic_macro_basic_string() { - panic!("basic") -} - -#[test] -#[should_panic(expected: "some_format(1)")] -fn test_panic_macro_with_input() { - panic!("some_format({})", 1) -} - - -#[test] -#[should_panic(expected: 'PanicDestruct')] -fn test_panic_destruct() { - panic_destruct_helper(1); -} - - -#[inline] -fn panic_destruct_helper>(n: T) { - panic_with_felt252('PanicDestruct') -} diff --git a/corelib/src/test/language_features/path_attr_test.cairo b/corelib/src/test/language_features/path_attr_test.cairo deleted file mode 100644 index 0fa9c9d1b8..0000000000 --- a/corelib/src/test/language_features/path_attr_test.cairo +++ /dev/null @@ -1,23 +0,0 @@ -#[path("other_paths/a.cairo")] -mod a; - -#[path("other_paths/b.cairo")] -mod b; - -#[path("other_paths/define_c.cairo")] -mod c; - -#[path("other_paths/inner/a.cairo")] -mod inner_a; - -#[path("other_paths/inner/b.cairo")] -mod inner_b; - -#[test] -fn test_access_all() { - assert_eq!(a::VALUE, 'a'); - assert_eq!(b::VALUE, 'b'); - assert_eq!(c::VALUE, 'c'); - assert_eq!(inner_a::VALUE, 'inner/a'); - assert_eq!(inner_b::VALUE, 'inner/b'); -} diff --git a/corelib/src/test/language_features/trait_test.cairo b/corelib/src/test/language_features/trait_test.cairo deleted file mode 100644 index 40415829ea..0000000000 --- a/corelib/src/test/language_features/trait_test.cairo +++ /dev/null @@ -1,17 +0,0 @@ -trait MyTrait { - fn foo(t: T) -> T { - t - } -} -impl MyImplU64 of MyTrait; -impl MyImplU32 of MyTrait { - fn foo(t: u32) -> u32 { - t + 1 - } -} - -#[test] -fn test_default_implementation_and_override() { - assert!(MyTrait::foo(5_u64) == 5); - assert!(MyTrait::foo(10_u32) == 11); -} diff --git a/corelib/src/test/language_features/while_test.cairo b/corelib/src/test/language_features/while_test.cairo deleted file mode 100644 index 18142cc1ee..0000000000 --- a/corelib/src/test/language_features/while_test.cairo +++ /dev/null @@ -1,67 +0,0 @@ -fn array_sum(mut arr: Array) -> felt252 { - let mut sum = 0; - while let Some(x) = arr.pop_front() { - sum += x; - } - sum -} - -#[test] -fn test_while_let() { - assert_eq!(array_sum(array![1, 2, 3, 4]), 10); - assert_eq!(array_sum(array![]), 0); -} - -#[test] -fn test_outer_loop_break() { - let mut i = 0; - while let true = i != 10 { - while true { - break; - } - i += 1; - } - assert_eq!(i, 10); -} - -#[test] -fn test_borrow_usage() { - let mut i = 0; - let arr = array![1, 2, 3, 4]; - while i != arr.len() { - i += 1; - } - assert_eq!(arr.len(), 4); -} - -#[derive(Drop)] -struct NonCopy { - x: felt252, -} - -fn assert_x_eq(a: @NonCopy, x: felt252) { - assert_eq!(a.x, x); -} - -#[test] -fn test_borrow_with_inner_change() { - let mut a = NonCopy { x: 0 }; - let mut i = 0; - while i != 5 { - a.x = i; - assert_x_eq(@a, i); - i += 1; - } -} - -#[test] -fn test_while_let_multilevel_enum() { - let mut x = Some(Some(5)); - let mut counter = 0; - while let Some(Some(y)) = x { - assert_eq!(y, 5); - x = Some(None); // Break the loop after one iteration - counter += 1; - } - assert_eq!(counter, 1); -} diff --git a/corelib/src/test/let_else_test.cairo b/corelib/src/test/let_else_test.cairo deleted file mode 100644 index 84ee2608b5..0000000000 --- a/corelib/src/test/let_else_test.cairo +++ /dev/null @@ -1,45 +0,0 @@ -#[test] -fn test_let_else_panic_return() { - let Some(x) = @Some(3) else { - panic!("Did not match expected variant.") - }; - assert_eq!(*x, 3); - let Some(_) = @None:: else { - return; - }; - panic!("Unexpectedly matches variant."); -} - -#[test] -fn test_let_else_continue() { - let v = array![Some(3), None, Some(5), Some(2), None]; - - let mut s: felt252 = 0; - - for x in v { - let Some(y) = x else { - s += 100; - continue; - }; - s += y; - } - - assert_eq!(s, 210); -} - -#[test] -fn test_let_else_break() { - let v = array![Some(6), Some(3), None, Some(5)]; - - let mut s: felt252 = 0; - - for x in v { - let Some(y) = x else { - s += 100; - break; - }; - s += y; - } - - assert_eq!(s, 109); -} diff --git a/corelib/src/test/math_test.cairo b/corelib/src/test/math_test.cairo deleted file mode 100644 index d04e592edc..0000000000 --- a/corelib/src/test/math_test.cairo +++ /dev/null @@ -1,157 +0,0 @@ -use crate::math; -use crate::option::OptionTrait; - -#[test] -fn test_egcd() { - let (g, s, t, sub_direction) = math::egcd::(68, 16); - assert(g == 4, 'g != 4'); - assert(s == 1, 's != 1'); - assert(t == 4, 't != 4'); - assert(sub_direction, 'sub_direction is wrong'); - assert(1 * 68 - 4 * 16 == 4, 'Sanity check failed'); - - let (g, s, t, sub_direction) = math::egcd::(240, 46); - assert(g == 2, 'g != 2'); - assert(s == 9, 's != 9'); - assert(t == 47, 't != 47'); - assert(!sub_direction, 'sub_direction is wrong'); - assert(47 * 46 - 9 * 240 == 2, 'Sanity check failed'); - - let (g, s, t, sub_direction) = math::egcd::(50, 17); - assert(g == 1, 'g != 1'); - assert(s == 1, 's != 1'); - assert(t == 3, 't != 3'); - assert(!sub_direction, 'sub_direction is wrong'); - assert(3 * 17 - 1 * 50 == 1, 'Sanity check failed'); - - let (g, s, t, sub_direction) = math::egcd::(5, 15); - assert(g == 5, 'g != 5'); - assert(s == 1, 's != 1'); - assert(t == 0, 't != 0'); - assert(sub_direction, 'sub_direction is wrong'); - assert(1 * 5 - 0 * 15 == 5, 'Sanity check failed'); - - let (g, s, t, sub_direction) = math::egcd::(1, 1); - assert(g == 1, 'g != 1'); - assert(s == 0, 's != 0'); - assert(t == 1, 't != 1'); - assert(!sub_direction, 'sub_direction is wrong'); - assert(1 * 1 - 0 * 1 == 1, 'Sanity check failed'); -} - -#[test] -fn test_inv_mod() { - assert(math::inv_mod(5, 24) == Some(5_u256), 'inv_mod(5, 24) != 5'); - assert(math::inv_mod(29, 24) == Some(5_u128), 'inv_mod(29, 24) != 5'); - assert(math::inv_mod(1, 24) == Some(1_u16), 'inv_mod(1, 24) != 1'); - assert(math::inv_mod(1, 5) == Some(1_u32), 'inv_mod(1, 5) != 1'); - assert(math::inv_mod(8, 24) == Option::::None, 'inv_mod(8, 24) != None'); - assert_eq!(math::inv_mod(1, 1), Option::::None); - assert_eq!(math::inv_mod(7, 1), Option::::None); -} - -#[test] -fn test_u256_div_mod_n() { - assert(math::u256_div_mod_n(6, 2, 7) == Some(3), '6 / 2 != 3 (7)'); - assert(math::u256_div_mod_n(5, 1, 7) == Some(5), '5 / 1 != 5 (7)'); - assert(math::u256_div_mod_n(1, 1, 7) == Some(1), '1 / 1 != 1 (7)'); - assert(math::u256_div_mod_n(7, 2, 13) == Some(10), '7 / 2 != 10 (13)'); - assert(math::u256_div_mod_n(0, 3, 13) == Some(0), '0 / 3 != 0 (13)'); - assert(math::u256_div_mod_n(4, 3, 6).is_none(), '4 / 3 == None (6)'); - assert(math::u256_div_mod_n(5, 4, 6).is_none(), '5 / 4 == None (6)'); - assert(math::u256_div_mod_n(2, 8, 4).is_none(), '2 / 8 == None (4)'); - assert( - math::u256_div_mod_n( - 0xfa855081cc80656250605b2ecd7958ba4f0aa6799053da0d68bf76f2484decc6, - 0xe8e94a59a951af1b4c8cbd45fb8d01c1dd946de2533e3ad18845f9dbb6d12f4f, - 0xa3db605888ac3cd19e70c5b52220ad693566b996ef078e907578fec7758dabc9, - ) == Some(0x8e70aea916ee4b782a0da9c18083ed9d867148a703615a2a88d0e7fddd4c900d), - 'Random large values 1', - ); - assert( - math::u256_div_mod_n( - 0x759426f1c0ba213b6378196b5091f5fa48f49f1d0cecfb00a7d59a51be35f609, - 0x57ff2c2e0900fce82331e396a71787a837783cca8145538eb32cb4b52104a3be, - 0xcb514e4d4672d8f1d952c0312afb5baae86121aa5817030d8439ce759295a029, - ) == Some(0x7c9d22b40f98075c0bfd674d546bc77d775dcf021d30b88afb099834dffa951b), - 'Random large values 2', - ); -} - -#[test] -fn test_u256_inv_mod() { - assert(math::u256_inv_mod(5, 24).unwrap().into() == 5_u256, 'inv_mod(5, 24) != 5'); - assert(math::u256_inv_mod(29, 24).unwrap().into() == 5_u256, 'inv_mod(29, 24) != 5'); - assert(math::u256_inv_mod(1, 24).unwrap().into() == 1_u256, 'inv_mod(1, 24) != 1'); - assert(math::u256_inv_mod(1, 5).unwrap().into() == 1_u256, 'inv_mod(1, 5) != 1'); - assert(math::u256_inv_mod(8, 24).is_none(), 'inv_mod(8, 24) != None'); - assert(math::u256_inv_mod(1, 1).is_none(), 'inv_mod(1, 1) != None'); - assert(math::u256_inv_mod(7, 1).is_none(), 'inv_mod(7, 1) != None'); - assert(math::u256_inv_mod(0, 1).is_none(), 'inv_mod(0, 1) != None'); - assert(math::u256_inv_mod(0, 7).is_none(), 'inv_mod(0, 7) != None'); - assert(math::u256_inv_mod(3, 6).is_none(), 'inv_mod(3, 6) != None'); - assert(math::u256_inv_mod(4, 6).is_none(), 'inv_mod(4, 6) != None'); - assert(math::u256_inv_mod(8, 4).is_none(), 'inv_mod(8, 4) != None'); - assert( - math::u256_inv_mod( - 0xea9195982bd472e30e5146ad7cb0acd954cbc75032a298ac73234b6b05e28cc1, - 0x4075f980fab77a3fde536dbaae600f5ea1540e01837dcec64c1f379613aa4d18, - ) - .is_none(), - 'Random 1', - ); - assert( - math::u256_inv_mod( - 0x85ef555d7a0aa34019c138defc40a1d3683dc1caa505bff286dd8069a28a2e4c, - 0xd71e5a5f4a4d1af45e703f9e13d1305ce149313037956247ad5edfe3e81d6353, - ) - .is_none(), - 'Random 2', - ); - let large_gcd = 0x63f7a7326f84cfca7738923db2b6d6c1b1b; - assert( - math::u256_inv_mod( - large_gcd * 0x51e28b744cc00edfb6bbbe6a9, - (large_gcd * 0xc09497df4aa02be7fd25f10d3).try_into().unwrap(), - ) - .is_none(), - 'gcd ~ 2**140', - ); - let very_large_gcd: NonZero<_> = - 0x74c5ef92be07ee4ad43ae8ca337390e4a5dfdbf4f1a5f09cdf412ab7ce343503; - assert(math::u256_inv_mod(very_large_gcd.into(), very_large_gcd).is_none(), 'gcd ~ 2**256'); -} - -#[test] -fn test_inv_mod_negatives() { - assert_eq!(math::inv_mod::(-3, 7), Some(2)); - assert_eq!(math::inv_mod::(4, 7), Some(2)); - assert_eq!(math::inv_mod::(-5, -11), Some(2)); - assert_eq!(math::inv_mod::(6, 11), Some(2)); - assert_eq!(math::inv_mod::(3, -7), Some(5)); - assert_eq!(math::inv_mod::(-4, 8), None); - assert_eq!(math::inv_mod::(6, -9), None); - assert_eq!(math::inv_mod::(-6, -9), None); - assert_eq!(math::inv_mod::(10, -15), None); - assert_eq!(math::inv_mod::(-1, 1), None); - assert_eq!(math::inv_mod::(-7, -1), None); -} - -#[test] -fn test_egcd_neg() { - assert_eq!(math::egcd::(14, -2), (2, 0, 1, true)); - assert_eq!(math::egcd::(14, -6), (2, 1, -2, true)); - assert_eq!(math::egcd::(-3, 7), (1, -2, 1, false)); - assert_eq!(math::egcd::(-5, -11), (1, 2, 1, true)); - assert_eq!(math::egcd::(3, -7), (1, -2, 1, true)); - // Test cases with 1 as argument - assert_eq!(math::egcd::(1, -5), (1, 1, 0, true)); - assert_eq!(math::egcd::(-1, 5), (1, 1, 0, false)); - assert_eq!(math::egcd::(-1, -5), (1, 1, 0, false)); - assert_eq!(math::egcd::(7, -1), (1, 0, 1, true)); - assert_eq!(math::egcd::(-7, 1), (1, 0, 1, false)); - assert_eq!(math::egcd::(-7, -1), (1, 0, 1, true)); - assert_eq!(math::egcd::(-1, -1), (1, 0, 1, true)); - assert_eq!(math::egcd::(-1, 1), (1, 0, 1, false)); - assert_eq!(math::egcd::(1, -1), (1, 0, 1, true)); -} diff --git a/corelib/src/test/nullable_test.cairo b/corelib/src/test/nullable_test.cairo deleted file mode 100644 index f0f2bb5cdb..0000000000 --- a/corelib/src/test/nullable_test.cairo +++ /dev/null @@ -1,37 +0,0 @@ -use crate::nullable::null; -use crate::test::test_utils::assert_eq; - -#[test] -fn test_nullable_felt252s() { - let x = 10; - let nullable_x = NullableTrait::new(x); - assert(!nullable_x.is_null(), 'nullable_x.is_null() true'); - assert_eq(@nullable_x.deref(), @x, '*&x != x'); - let y = 11; - let nullable_y = NullableTrait::new(y); - assert(!nullable_y.is_null(), 'nullable_y.is_null() true'); - assert_eq(@nullable_y.deref(), @y, '*&y != y'); - let null: Nullable = null(); - assert(null.is_null(), 'null.is_null() false'); -} - -// Testing `u256` as a test for objects of size larger than 1. -#[test] -fn test_nullable_u256() { - let x: u256 = 10; - let nullable_x = NullableTrait::new(x); - assert(!nullable_x.is_null(), 'nullable_x.is_null() true'); - assert_eq(@nullable_x.deref(), @x, '*&x != x'); - let y: u256 = 11; - let nullable_y = NullableTrait::new(y); - assert(!nullable_y.is_null(), 'nullable_y.is_null() true'); - assert_eq(@nullable_y.deref(), @y, '*&y != y'); - - assert_eq!(nullable_y.deref_or(10), 11); - assert_eq!(nullable_y.deref_or_else(|| 12), 11); - - let null: Nullable = null(); - assert(null.is_null(), 'null.is_null() false'); - assert_eq!(null.deref_or(5), 5); - assert_eq!(null.deref_or_else(|| 6), 6); -} diff --git a/corelib/src/test/num_test.cairo b/corelib/src/test/num_test.cairo deleted file mode 100644 index b89f6dc13c..0000000000 --- a/corelib/src/test/num_test.cairo +++ /dev/null @@ -1,516 +0,0 @@ -use crate::num::traits::{ - BitSize, Bounded, CheckedAdd, CheckedMul, CheckedSub, DivRem, OverflowingAdd, OverflowingMul, - OverflowingSub, Pow, SaturatingAdd, SaturatingMul, SaturatingSub, WrappingAdd, WrappingMul, - WrappingSub, -}; - - -#[test] -fn test_bit_size() { - assert!(BitSize::::bits() == 8); - assert!(BitSize::::bits() == 16); - assert!(BitSize::::bits() == 32); - assert!(BitSize::::bits() == 64); - assert!(BitSize::::bits() == 128); - assert!(BitSize::::bits() == 256); - assert!(BitSize::::bits() == 8); - assert!(BitSize::::bits() == 16); - assert!(BitSize::::bits() == 32); - assert!(BitSize::::bits() == 64); - assert!(BitSize::::bits() == 128); - assert!(BitSize::::bits() == 248); -} - -// Overflowing tests - -#[test] -fn tests_overflowing_add_unsigned_integers() { - assert_eq!(1_u8.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); - assert_eq!(1_u16.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); - assert_eq!(1_u32.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); - assert_eq!(1_u64.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); - assert_eq!(1_u128.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); - assert_eq!(1_u256.overflowing_add(2), (3, false)); - assert_eq!(Bounded::::MAX.overflowing_add(1), (0, true)); -} - -#[test] -fn test_overflowing_add_positive_signed_integers() { - assert!(1_i8.overflowing_add(2) == (3, false)); - assert!(Bounded::::MAX.overflowing_add(1) == (-0x80, true)); - assert!(1_i16.overflowing_add(2) == (3, false)); - assert!(Bounded::::MAX.overflowing_add(1) == (-0x8000, true)); - assert!(1_i32.overflowing_add(2) == (3, false)); - assert!(Bounded::::MAX.overflowing_add(1) == (-0x80000000, true)); - assert!(1_i64.overflowing_add(2) == (3, false)); - assert!(Bounded::::MAX.overflowing_add(1) == (-0x8000000000000000, true)); - assert!(1_i128.overflowing_add(2) == (3, false)); - assert!(Bounded::::MAX.overflowing_add(1) == (-0x80000000000000000000000000000000, true)); -} - -#[test] -fn test_overflowing_add_negative_signed_integers() { - assert!((-1_i8).overflowing_add(-2) == (-3, false)); - assert!(Bounded::::MIN.overflowing_add(-1) == (0x7f, true)); - assert!((-1_i16).overflowing_add(-2) == (-3, false)); - assert!(Bounded::::MIN.overflowing_add(-1) == (0x7fff, true)); - assert!((-1_i32).overflowing_add(-2) == (-3, false)); - assert!(Bounded::::MIN.overflowing_add(-1) == (0x7fffffff, true)); - assert!((-1_i64).overflowing_add(-2) == (-3, false)); - assert!(Bounded::::MIN.overflowing_add(-1) == (0x7fffffffffffffff, true)); - assert!((-1_i128).overflowing_add(-2) == (-3, false)); - assert!(Bounded::::MIN.overflowing_add(-1) == (0x7fffffffffffffffffffffffffffffff, true)); -} - -#[test] -fn test_overflowing_sub_unsigned_integers() { - assert_eq!(3_u8.overflowing_sub(2), (1, false)); - assert_eq!(0_u8.overflowing_sub(1), (Bounded::::MAX, true)); - assert_eq!(3_u16.overflowing_sub(2), (1, false)); - assert_eq!(0_u16.overflowing_sub(1), (Bounded::::MAX, true)); - assert_eq!(3_u32.overflowing_sub(2), (1, false)); - assert_eq!(0_u32.overflowing_sub(1), (Bounded::::MAX, true)); - assert_eq!(3_u64.overflowing_sub(2), (1, false)); - assert_eq!(0_u64.overflowing_sub(1), (Bounded::::MAX, true)); - assert_eq!(3_u128.overflowing_sub(2), (1, false)); - assert_eq!(0_u128.overflowing_sub(1), (Bounded::::MAX, true)); - assert_eq!(3_u256.overflowing_sub(2), (1, false)); - assert_eq!(0_u256.overflowing_sub(1), (Bounded::::MAX, true)); -} - -#[test] -fn test_overflowing_sub_positive_signed_integers() { - assert!(3_i8.overflowing_sub(2) == (1, false)); - assert!(Bounded::::MIN.overflowing_sub(1) == (Bounded::::MAX, true)); - assert!(3_i16.overflowing_sub(2) == (1, false)); - assert!(Bounded::::MIN.overflowing_sub(1) == (Bounded::::MAX, true)); - assert!(3_i32.overflowing_sub(2) == (1, false)); - assert!(Bounded::::MIN.overflowing_sub(1) == (Bounded::::MAX, true)); - assert!(3_i64.overflowing_sub(2) == (1, false)); - assert!(Bounded::::MIN.overflowing_sub(1) == (Bounded::::MAX, true)); - assert!(3_i128.overflowing_sub(2) == (1, false)); - assert!(Bounded::::MIN.overflowing_sub(1) == (Bounded::::MAX, true)); -} - -#[test] -fn test_overflowing_sub_negative_signed_integers() { - assert!((-3_i8).overflowing_sub(-2) == (-1, false)); - assert!(Bounded::::MAX.overflowing_sub(-1) == (Bounded::::MIN, true)); - assert!((-3_i16).overflowing_sub(-2) == (-1, false)); - assert!(Bounded::::MAX.overflowing_sub(-1) == (Bounded::::MIN, true)); - assert!((-3_i32).overflowing_sub(-2) == (-1, false)); - assert!(Bounded::::MAX.overflowing_sub(-1) == (Bounded::::MIN, true)); - assert!((-3_i64).overflowing_sub(-2) == (-1, false)); - assert!(Bounded::::MAX.overflowing_sub(-1) == (Bounded::::MIN, true)); - assert!((-3_i128).overflowing_sub(-2) == (-1, false)); - assert!(Bounded::::MAX.overflowing_sub(-1) == (Bounded::::MIN, true)); -} - -#[test] -fn test_overflowing_mul_unsigned_integers() { - assert_eq!(2_u8.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); - assert_eq!(2_u16.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); - assert_eq!(2_u32.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); - assert_eq!(2_u64.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); - assert_eq!(2_u128.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); - assert_eq!(2_u256.overflowing_mul(3), (6, false)); - assert_eq!(Bounded::::MAX.overflowing_mul(2), (Bounded::::MAX - 1, true)); -} - -// Wrapping tests - -#[test] -fn tests_wrapping_add_unsigned_integers() { - assert_eq!(1_u8.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); - assert_eq!(1_u16.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); - assert_eq!(1_u32.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); - assert_eq!(1_u64.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); - assert_eq!(1_u128.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); - assert_eq!(1_u256.wrapping_add(2), 3); - assert_eq!(Bounded::::MAX.wrapping_add(1), 0); -} - -#[test] -fn test_wrapping_add_positive_signed_integers() { - assert!(1_i8.wrapping_add(2) == 3); - assert!(Bounded::::MAX.wrapping_add(1) == -0x80); - assert!(1_i16.wrapping_add(2) == 3); - assert!(Bounded::::MAX.wrapping_add(1) == -0x8000); - assert!(1_i32.wrapping_add(2) == 3); - assert!(Bounded::::MAX.wrapping_add(1) == -0x80000000); - assert!(1_i64.wrapping_add(2) == 3); - assert!(Bounded::::MAX.wrapping_add(1) == -0x8000000000000000); - assert!(1_i128.wrapping_add(2) == 3); - assert!(Bounded::::MAX.wrapping_add(1) == -0x80000000000000000000000000000000); -} - -#[test] -fn test_wrapping_add_negative_signed_integers() { - assert!((-1_i8).wrapping_add(-2) == -3); - assert!(Bounded::::MIN.wrapping_add(-1) == 0x7f); - assert!((-1_i16).wrapping_add(-2) == -3); - assert!(Bounded::::MIN.wrapping_add(-1) == 0x7fff); - assert!((-1_i32).wrapping_add(-2) == -3); - assert!(Bounded::::MIN.wrapping_add(-1) == 0x7fffffff); - assert!((-1_i64).wrapping_add(-2) == -3); - assert!(Bounded::::MIN.wrapping_add(-1) == 0x7fffffffffffffff); - assert!((-1_i128).wrapping_add(-2) == -3); - assert!(Bounded::::MIN.wrapping_add(-1) == 0x7fffffffffffffffffffffffffffffff); -} - -#[test] -fn test_wrapping_sub_unsigned_integers() { - assert_eq!(3_u8.wrapping_sub(2), 1); - assert_eq!(0_u8.wrapping_sub(1), Bounded::::MAX); - assert_eq!(3_u16.wrapping_sub(2), 1); - assert_eq!(0_u16.wrapping_sub(1), Bounded::::MAX); - assert_eq!(3_u32.wrapping_sub(2), 1); - assert_eq!(0_u32.wrapping_sub(1), Bounded::::MAX); - assert_eq!(3_u64.wrapping_sub(2), 1); - assert_eq!(0_u64.wrapping_sub(1), Bounded::::MAX); - assert_eq!(3_u128.wrapping_sub(2), 1); - assert_eq!(0_u128.wrapping_sub(1), Bounded::::MAX); - assert_eq!(3_u256.wrapping_sub(2), 1); - assert_eq!(0_u256.wrapping_sub(1), Bounded::::MAX); -} - -#[test] -fn test_wrapping_sub_positive_signed_integers() { - assert!(3_i8.wrapping_sub(2) == 1); - assert!(Bounded::::MIN.wrapping_sub(1) == Bounded::::MAX); - assert!(3_i16.wrapping_sub(2) == 1); - assert!(Bounded::::MIN.wrapping_sub(1) == Bounded::::MAX); - assert!(3_i32.wrapping_sub(2) == 1); - assert!(Bounded::::MIN.wrapping_sub(1) == Bounded::::MAX); - assert!(3_i64.wrapping_sub(2) == 1); - assert!(Bounded::::MIN.wrapping_sub(1) == Bounded::::MAX); - assert!(3_i128.wrapping_sub(2) == 1); - assert!(Bounded::::MIN.wrapping_sub(1) == Bounded::::MAX); -} - -#[test] -fn test_wrapping_sub_negative_signed_integers() { - assert!((-3_i8).wrapping_sub(-2) == -1); - assert!(Bounded::::MAX.wrapping_sub(-1) == Bounded::::MIN); - assert!((-3_i16).wrapping_sub(-2) == -1); - assert!(Bounded::::MAX.wrapping_sub(-1) == Bounded::::MIN); - assert!((-3_i32).wrapping_sub(-2) == -1); - assert!(Bounded::::MAX.wrapping_sub(-1) == Bounded::::MIN); - assert!((-3_i64).wrapping_sub(-2) == -1); - assert!(Bounded::::MAX.wrapping_sub(-1) == Bounded::::MIN); - assert!((-3_i128).wrapping_sub(-2) == -1); - assert!(Bounded::::MAX.wrapping_sub(-1) == Bounded::::MIN); -} - -#[test] -fn test_wrapping_mul_unsigned_integers() { - assert_eq!(2_u8.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); - assert_eq!(2_u16.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); - assert_eq!(2_u32.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); - assert_eq!(2_u64.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); - assert_eq!(2_u128.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); - assert_eq!(2_u256.wrapping_mul(3), 6); - assert_eq!(Bounded::::MAX.wrapping_mul(2), Bounded::::MAX - 1); -} - -// Checked tests -#[test] -fn test_checked_add_unsigned_integers() { - assert_eq!(1_u8.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_u16.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_u32.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_u64.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_u128.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_u256.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); -} - -#[test] -fn test_checked_add_positive_signed_integers() { - assert_eq!(1_i8.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_i16.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_i32.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_i64.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); - assert_eq!(1_i128.checked_add(2), Some(3)); - assert!(Bounded::::MAX.checked_add(1).is_none()); -} - -#[test] -fn test_checked_add_negative_signed_integers() { - assert_eq!((-1_i8).checked_add(-2), Some(-3)); - assert!(Bounded::::MIN.checked_add(-1).is_none()); - assert_eq!((-1_i16).checked_add(-2), Some(-3)); - assert!(Bounded::::MIN.checked_add(-1).is_none()); - assert_eq!((-1_i32).checked_add(-2), Some(-3)); - assert!(Bounded::::MIN.checked_add(-1).is_none()); - assert_eq!((-1_i64).checked_add(-2), Some(-3)); - assert!(Bounded::::MIN.checked_add(-1).is_none()); - assert_eq!((-1_i128).checked_add(-2), Some(-3)); - assert!(Bounded::::MIN.checked_add(-1).is_none()); -} - -#[test] -fn test_checked_sub_unsigned_integers() { - assert_eq!(3_u8.checked_sub(2), Some(1)); - assert!(0_u8.checked_sub(1).is_none()); - assert_eq!(3_u16.checked_sub(2), Some(1)); - assert!(0_u16.checked_sub(1).is_none()); - assert_eq!(3_u32.checked_sub(2), Some(1)); - assert!(0_u32.checked_sub(1).is_none()); - assert_eq!(3_u64.checked_sub(2), Some(1)); - assert!(0_u64.checked_sub(1).is_none()); - assert_eq!(3_u128.checked_sub(2), Some(1)); - assert!(0_u128.checked_sub(1).is_none()); - assert_eq!(3_u256.checked_sub(2), Some(1)); - assert!(0_u256.checked_sub(1).is_none()); -} - -#[test] -fn test_checked_sub_positive_signed_integers() { - assert_eq!(3_i8.checked_sub(2), Some(1)); - assert!(Bounded::::MIN.checked_sub(1).is_none()); - assert_eq!(3_i16.checked_sub(2), Some(1)); - assert!(Bounded::::MIN.checked_sub(1).is_none()); - assert_eq!(3_i32.checked_sub(2), Some(1)); - assert!(Bounded::::MIN.checked_sub(1).is_none()); - assert_eq!(3_i64.checked_sub(2), Some(1)); - assert!(Bounded::::MIN.checked_sub(1).is_none()); - assert_eq!(3_i128.checked_sub(2), Some(1)); - assert!(Bounded::::MIN.checked_sub(1).is_none()); -} - -#[test] -fn test_checked_sub_negative_signed_integers() { - assert_eq!((-3_i8).checked_sub(-2), Some(-1)); - assert!(Bounded::::MAX.checked_sub(-1).is_none()); - assert_eq!((-3_i16).checked_sub(-2), Some(-1)); - assert!(Bounded::::MAX.checked_sub(-1).is_none()); - assert_eq!((-3_i32).checked_sub(-2), Some(-1)); - assert!(Bounded::::MAX.checked_sub(-1).is_none()); - assert_eq!((-3_i64).checked_sub(-2), Some(-1)); - assert!(Bounded::::MAX.checked_sub(-1).is_none()); - assert_eq!((-3_i128).checked_sub(-2), Some(-1)); - assert!(Bounded::::MAX.checked_sub(-1).is_none()); -} - -#[test] -fn test_checked_mul_unsigned_integers() { - assert_eq!(2_u8.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); - assert_eq!(2_u16.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); - assert_eq!(2_u32.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); - assert_eq!(2_u64.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); - assert_eq!(2_u128.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); - assert_eq!(2_u256.checked_mul(3), Some(6)); - assert!(Bounded::::MAX.checked_mul(2).is_none()); -} - -#[test] -fn test_saturating_add_unsigned_integers() { - assert_eq!(1_u8.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_u16.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_u32.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_u64.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_u128.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_u256.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); -} - -#[test] -fn test_saturating_add_signed_integers() { - assert_eq!(1_i8.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_i16.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_i32.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_i64.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); - assert_eq!(1_i128.saturating_add(2), 3); - assert_eq!(Bounded::::MAX.saturating_add(1), Bounded::::MAX); -} - -#[test] -fn test_saturating_add_signed_negative_integers() { - assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); - assert_eq!((-1_i8).saturating_add(-2), -3); - assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); - assert_eq!((-1_i16).saturating_add(-2), -3); - assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); - assert_eq!((-1_i32).saturating_add(-2), -3); - assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); - assert_eq!((-1_i64).saturating_add(-2), -3); - assert_eq!(Bounded::::MIN.saturating_add(-1), Bounded::::MIN); - assert_eq!((-1_i128).saturating_add(-2), -3); -} - -#[test] -fn test_saturating_sub_unsigned_integers() { - assert_eq!(3_u8.saturating_sub(2), 1); - assert_eq!(0_u8.saturating_sub(1), 0); - assert_eq!(3_u16.saturating_sub(2), 1); - assert_eq!(0_u16.saturating_sub(1), 0); - assert_eq!(3_u32.saturating_sub(2), 1); - assert_eq!(0_u32.saturating_sub(1), 0); - assert_eq!(3_u64.saturating_sub(2), 1); - assert_eq!(0_u64.saturating_sub(1), 0); - assert_eq!(3_u128.saturating_sub(2), 1); - assert_eq!(0_u128.saturating_sub(1), 0); - assert_eq!(3_u256.saturating_sub(2), 1); - assert_eq!(0_u256.saturating_sub(1), 0); -} - -#[test] -fn test_saturating_sub_signed_integers() { - assert_eq!(3_i8.saturating_sub(2), 1); - assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); - assert_eq!(3_i16.saturating_sub(2), 1); - assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); - assert_eq!(3_i32.saturating_sub(2), 1); - assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); - assert_eq!(3_i64.saturating_sub(2), 1); - assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); - assert_eq!(3_i128.saturating_sub(2), 1); - assert_eq!(Bounded::::MIN.saturating_sub(1), Bounded::::MIN); -} - -#[test] -fn test_saturating_sub_signed_negative_integers() { - assert_eq!(1_i8.saturating_sub(-2), 3); - assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); - assert_eq!(1_i16.saturating_sub(-2), 3); - assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); - assert_eq!(1_i32.saturating_sub(-2), 3); - assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); - assert_eq!(1_i64.saturating_sub(-2), 3); - assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); - assert_eq!(1_i128.saturating_sub(-2), 3); - assert_eq!(Bounded::::MAX.saturating_sub(-1), Bounded::::MAX); -} - -#[test] -fn test_saturating_mul_unsigned_integers() { - assert_eq!(2_u8.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); - assert_eq!(2_u16.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); - assert_eq!(2_u32.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); - assert_eq!(2_u64.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); - assert_eq!(2_u128.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); - assert_eq!(2_u256.saturating_mul(3), 6); - assert_eq!(Bounded::::MAX.saturating_mul(2), Bounded::::MAX); -} - -#[test] -fn test_pow() { - assert_eq!((-2_i8).pow(0), 1); - assert_eq!((-2_i8).pow(1), -2); - assert_eq!((-2_i8).pow(2), 4); - assert_eq!((-2_i8).pow(3), -8); - assert_eq!((-2_i8).pow(4), 16); - assert_eq!((-2_i8).pow(5), -32); - assert_eq!((-2_i8).pow(6), 64); - - assert_eq!(0.pow(0), 1); - assert_eq!(0.pow(1), 0); - assert_eq!(0.pow(2), 0); - - assert_eq!(2.pow(0), 0b1); - assert_eq!(2.pow(1), 0b10); - assert_eq!(2.pow(2), 0b100); - assert_eq!(2.pow(3), 0b1000); - assert_eq!(2.pow(4), 0b10000); - assert_eq!(2.pow(5), 0b100000); - assert_eq!(2.pow(6), 0b1000000); - assert_eq!(2.pow(7), 0b10000000); - assert_eq!(2.pow(8), 0b100000000); - assert_eq!(2.pow(9), 0b1000000000); - assert_eq!(2.pow(10), 0b10000000000); -} - - -#[test] -fn test_divrem() { - assert_eq!(DivRem::::div_rem(27, 4), (6, 3)); - assert_eq!(DivRem::::div_rem(20, 6), (3, 2)); - assert_eq!(DivRem::::div_rem(5, 9), (0, 5)); - assert_eq!(DivRem::::div_rem(0xfffb, 0x10), (0x0fff, 0xb)); - assert_eq!(DivRem::::div_rem(0x1234_5678, 1), (0x1234_5678, 0)); - assert_eq!(DivRem::::div_rem(0, 17), (0, 0)); - assert_eq!(DivRem::::div_rem(123_456, 123_456), (1, 0)); - assert_eq!( - DivRem::::div_rem(core::num::traits::Bounded::::MAX, 10), - (34028236692093846346337460743176821145_u128, 5), - ); - assert_eq!(DivRem::::div_rem(1000, 33), (30, 10)); - assert_eq!(DivRem::::div_rem(123, 10), (12, 3)); -} - - -#[test] -fn test_divrem_legacy() { - assert_eq!(crate::traits::DivRem::div_rem(27_u32, 4), (6, 3)); - assert_eq!(crate::traits::DivRem::div_rem(0x12_u8, 1), (0x12, 0)); - assert_eq!(crate::traits::DivRem::div_rem(5_u16, 7), (0, 5)); - assert_eq!(crate::traits::DivRem::div_rem(1_000_000_u64, 1_000), (1_000, 0)); - assert_eq!( - crate::traits::DivRem::div_rem( - Bounded::::MAX, Bounded::::MAX.try_into().unwrap(), - ), - (1, 0), - ); - assert_eq!(crate::traits::DivRem::div_rem(20, 6), (3_u256, 2_u256)); -} - -/// One-off impl for the above test. -impl U256ByU128DivRem of DivRem { - type Quotient = u256; - type Remainder = u128; - - fn div_rem(self: u256, other: NonZero) -> (u256, u128) { - let other_u128: u128 = other.into(); - let other: u256 = other_u128.into(); - (self / other, (self % other).low) - } -} diff --git a/corelib/src/test/option_test.cairo b/corelib/src/test/option_test.cairo deleted file mode 100644 index 81e1622ec3..0000000000 --- a/corelib/src/test/option_test.cairo +++ /dev/null @@ -1,306 +0,0 @@ -#[test] -fn test_option_some_expect() { - assert!(Some(42).expect('') == 42); -} - -#[test] -#[should_panic(expected: ('err msg',))] -fn test_option_none_expect() { - Option::::None.expect('err msg'); -} - -#[test] -fn test_option_some_unwrap() { - assert!(Some(42).unwrap() == 42); -} - -#[test] -#[should_panic(expected: ('Option::unwrap failed.',))] -fn test_option_none_unwrap() { - Option::::None.unwrap(); -} - -#[test] -fn test_option_some_unwrap_or() { - assert!(Some(42).unwrap_or(0) == 42); -} - -#[test] -fn test_option_none_unwrap_or() { - assert!(None.unwrap_or(0) == 0); -} - -#[test] -fn test_option_some_unwrap_or_default() { - assert!(Some(42).unwrap_or_default() == 42); -} - -#[test] -fn test_option_none_unwrap_or_default() { - assert!(None.unwrap_or_default() == 0); -} - -#[test] -fn test_option_some_unwrap_or_else() { - assert!(Some(42).unwrap_or_else(|| 0) == 42); -} - -#[test] -fn test_option_none_unwrap_or_else() { - assert!(None.unwrap_or_else(|| 0) == 0); -} - -#[test] -fn test_option_some_is_some() { - assert!(Some(42).is_some()); -} - -#[test] -fn test_option_none_is_some() { - assert!(!Option::::None.is_some()); -} - -#[test] -fn test_option_some_is_some_and() { - assert_eq!(Some(2_u8).is_some_and(|x| x > 1), true); - assert_eq!(Some(0_u8).is_some_and(|x| x > 1), false); -} - -#[test] -fn test_option_none_is_some_and() { - let option: Option = None; - assert_eq!(option.is_some_and(|x| x > 1), false); -} - -#[test] -fn test_option_some_is_none() { - assert!(!Some(42).is_none()); -} - -#[test] -fn test_option_none_is_none() { - assert!(Option::::None.is_none()); -} - -#[test] -fn test_option_some_ok_or() { - assert_eq!(Some('foo').ok_or(0), Ok('foo')); -} - -#[test] -fn test_option_none_ok_or() { - let option: Option = None; - assert_eq!(option.ok_or(0), Err(0)); -} - -#[test] -fn test_option_some_ok_or_else() { - assert_eq!(Some('foo').ok_or_else(|| 0), Ok('foo')); -} - -#[test] -fn test_option_none_ok_or_else() { - let option: Option = None; - assert_eq!(option.ok_or_else(|| 0), Err(0)); -} - -#[test] -fn test_option_and() { - let x = Some(2); - let y: Option = None; - assert_eq!(x.and(y), None); - - let x: Option = None; - let y: Option = Some("foo"); - assert_eq!(x.and(y), None); - - let x = Some(2); - let y: Option = Some("foo"); - assert_eq!(x.and(y), Some("foo")); - - let x: Option = None; - let y: Option = None; - assert_eq!(x.and(y), None); -} - -#[test] -fn test_option_and_then() { - let checked_mul = core::num::traits::CheckedMul::checked_mul(2_u32, 2_u32); - let option: Option = checked_mul.and_then(|v| Some(format!("{}", v))); - assert_eq!(option, Some("4")); - - let checked_mul = core::num::traits::CheckedMul::checked_mul(65536_u32, 65536_u32); - let option: Option = checked_mul.and_then(|v| Some(format!("{}", v))); - assert_eq!(option, None); // overflowed! - - let option: Option = Option::::None.and_then(|v| Some(format!("{}", v))); - assert_eq!(option, None); -} - -#[test] -fn test_option_or() { - let x = Some(2); - let y = None; - assert_eq!(x.or(y), Some(2)); - - let x = None; - let y = Some(100); - assert_eq!(x.or(y), Some(100)); - - let x = Some(2); - let y = Some(100); - assert_eq!(x.or(y), Some(2)); - - let x: Option = None; - let y = None; - assert_eq!(x.or(y), None); -} - -#[test] -fn test_option_or_else() { - let nobody = || Option::::None; - let vikings = || Option::::Some("vikings"); - - assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians")); - assert_eq!(None.or_else(vikings), Some("vikings")); - assert_eq!(None.or_else(nobody), None); -} - -#[test] -fn test_option_xor() { - let x = Some(2); - let y: Option = None; - assert_eq!(x.xor(y), Some(2)); - - let x: Option = None; - let y = Some(2); - assert_eq!(x.xor(y), Some(2)); - - let x = Some(2); - let y = Some(2); - assert_eq!(x.xor(y), None); - - let x: Option = None; - let y: Option = None; - assert_eq!(x.xor(y), None); -} - -#[test] -fn test_option_some_is_none_or() { - assert_eq!(Some(2_u8).is_none_or(|x| x > 1), true); - assert_eq!(Some(0_u8).is_none_or(|x| x > 1), false); -} - -#[test] -fn test_option_none_is_none_or() { - let option: Option = None; - assert_eq!(option.is_none_or(|x| x > 1), true); -} - -#[derive(Drop)] -struct NonCopy {} - -#[test] -fn test_default_for_option() { - assert!(Default::>::default().is_none()); - assert!(Default::>::default().is_none()); -} - -#[test] -fn test_option_some_map() { - let maybe_some_string: Option = Some("Hello, World!"); - let maybe_some_len = maybe_some_string.map(|s| s.len()); - assert!(maybe_some_len == Some(13)); -} - -#[test] -fn test_option_none_map() { - let x: Option = None; - assert!(x.map(|s: ByteArray| s.len()) == None); -} - -#[test] -fn test_option_some_map_or() { - assert_eq!(Some("foo").map_or(42, |v: ByteArray| v.len()), 3); -} - -#[test] -fn test_option_none_map_or() { - let x: Option = None; - assert_eq!(x.map_or(42, |v: ByteArray| v.len()), 42); -} - -#[test] -fn test_option_some_map_or_else() { - let k = 21; - let x = Some("foo"); - assert_eq!(x.map_or_else(|| 2 * k, |v: ByteArray| v.len()), 3); -} - -#[test] -fn test_option_none_map_or_else() { - let k = 21; - let x: Option = None; - assert_eq!(x.map_or_else(|| 2 * k, |v: ByteArray| v.len()), 42); -} - -#[test] -fn test_option_some_into_iter() { - let x: Option = Some(5); - let mut x_iter = x.into_iter(); - assert!(x_iter.next() == Some(5)); - assert!(x_iter.next() == None); -} - -#[test] -fn test_option_none_into_iter() { - let x: Option = None; - let mut x_iter = x.into_iter(); - assert!(x_iter.next() == None); -} - -#[test] -fn test_option_take() { - let mut x = Some(2); - let y = x.take(); - assert_eq!(x, None); - assert_eq!(y, Some(2)); - - let mut x: Option = None; - let y = x.take(); - assert_eq!(x, None); - assert_eq!(y, None); -} - -#[test] -fn test_option_filter() { - let is_even = |x: @u32| -> bool { - *x % 2 == 0 - }; - - assert!(None.filter(is_even) == None); - assert!(Some(3).filter(is_even) == None); - assert!(Some(4).filter(is_even) == Some(4)); -} - -#[test] -fn test_option_flatten() { - let x: Option> = Some(Some(6)); - assert_eq!(Some(6), x.flatten()); - - let x: Option> = Some(None); - assert_eq!(None, x.flatten()); - - let x: Option> = None; - assert_eq!(None, x.flatten()); - - let x: Option>> = Some(Some(Some(6))); - assert_eq!(Some(Some(6)), x.flatten()); - assert_eq!(Some(6), x.flatten().flatten()); -} - -#[test] -fn test_option_into() { - let o: Option = 67_u8.into(); - assert_eq!(Some(67), o); -} diff --git a/corelib/src/test/plugins_test.cairo b/corelib/src/test/plugins_test.cairo deleted file mode 100644 index f8d2fa0d44..0000000000 --- a/corelib/src/test/plugins_test.cairo +++ /dev/null @@ -1,150 +0,0 @@ -use crate::test::test_utils::assert_eq; - -#[derive(Copy, Debug, Drop, Serde, PartialEq)] -enum EnumForSerde { - A, - B: u32, - C: u64, -} - -#[derive(Drop, Debug, Default, PartialEq)] -struct StructForDefault { - a: felt252, - b: u256, - c: bool, -} - -#[derive(Drop, Debug, Default, PartialEq)] -enum EnumForDefault { - A: felt252, - B: u256, - #[default] - C: StructForDefault, -} - -#[test] -fn test_derive_serde_enum() { - let a = EnumForSerde::A; - let b = EnumForSerde::B(1); - let c = EnumForSerde::C(2); - let mut output = Default::default(); - a.serialize(ref output); - a.serialize(ref output); - c.serialize(ref output); - b.serialize(ref output); - a.serialize(ref output); - let mut serialized = output.span(); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @a, - 'expected a', - ); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @a, - 'expected a', - ); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @c, - 'expected c', - ); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @b, - 'expected b', - ); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @a, - 'expected a', - ); - assert(serialized.is_empty(), 'expected empty'); -} - -#[test] -fn test_derive_default_struct() { - assert_eq!(Default::default(), StructForDefault { a: 0, b: 0, c: false }); -} - -#[test] -fn test_derive_default_enum() { - assert_eq!(Default::default(), EnumForDefault::C(StructForDefault { a: 0, b: 0, c: false })); -} - -#[derive(Copy, Debug, Drop, Serde, PartialEq)] -enum LongEnum5 { - A, - B, - C, - D, - E, -} -#[derive(Copy, Debug, Drop, Serde, PartialEq)] -enum longEnum10 { - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, -} -#[derive(Copy, Debug, Drop, Serde, PartialEq)] -enum longEnum15 { - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, -} - - -#[test] -fn test_long_enum5_deserialize() { - let x = LongEnum5::E; - let mut output = Default::default(); - x.serialize(ref output); - let mut serialized = output.span(); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), @x, 'expected E', - ); -} -#[test] -fn test_long_enum10_deserialize() { - let x = longEnum10::J; - let mut output = Default::default(); - x.serialize(ref output); - let mut serialized = output.span(); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @x, - 'expected J', - ); -} -#[test] -fn test_long_enum15_deserialize() { - let x = longEnum15::O; - let mut output = Default::default(); - x.serialize(ref output); - let mut serialized = output.span(); - assert_eq( - @Serde::::deserialize(ref serialized).expect('failed to read'), - @x, - 'expected O', - ); -} - diff --git a/corelib/src/test/print_test.cairo b/corelib/src/test/print_test.cairo deleted file mode 100644 index f5bcb7200d..0000000000 --- a/corelib/src/test/print_test.cairo +++ /dev/null @@ -1,126 +0,0 @@ -use crate::byte_array::BYTE_ARRAY_MAGIC; -use crate::debug::{PrintTrait, print_byte_array_as_string}; - -#[ignore] -#[test] -fn test_prints() { - // Valid short string. - 'hello'.print(); - - // felt252 - 1.print(); - - // Valid string with < 31 characters (no full words). - let x: ByteArray = "short, but string"; - print_byte_array_as_string(@x); - - // Valid string with > 31 characters (with a full word). - let x: ByteArray = "This is a long string with more than 31 characters."; - print_byte_array_as_string(@x); - - // Valid string as an array. - let x = array![ - BYTE_ARRAY_MAGIC, 1, // A single full word. - 'This is a long string with more', - ' than 31 characters.', - 20 // pending word length. Bigger than the actual data in the pending word. - ]; - x.print(); - - // Only magic. - let x = array![BYTE_ARRAY_MAGIC]; - x.print(); - - // num_full_words > usize. - let x = array![BYTE_ARRAY_MAGIC, 0x100000000]; - x.print(); - - // Not enough data after num_full_words. - let x = array![BYTE_ARRAY_MAGIC, 0]; - x.print(); - - // Not enough full words. - let x = array![BYTE_ARRAY_MAGIC, 1, 0, 0]; - x.print(); - - // Too much data in full word. - let x = array![ - BYTE_ARRAY_MAGIC, 1, // A single full word. - 0x161616161616161616161616161616161616161616161616161616161616161, // The invalid full word. - 0, 0 // pending byte is empty. - ]; - x.print(); - - // num_pending_bytes > usize. - let x = array![BYTE_ARRAY_MAGIC, 0, 0, 0x100000000]; - x.print(); - - // "Not enough" data in pending_word (nulls in the beginning). - let x = array![ - BYTE_ARRAY_MAGIC, 0, // No full words. - 'a', - 2 // pending word length. Bigger than the actual data in the pending word. - ]; - x.print(); - - // Too much data in pending_word. - let x = array![ - BYTE_ARRAY_MAGIC, 0, // No full words. - 'aa', - 1 // pending word length. Smaller than the actual data in the pending word. - ]; - x.print(); - - // Valid string with Null. - let mut x: ByteArray = "Hello"; - x.append_byte(0); // '\0' - let suffix: ByteArray = "world"; - x.append(@suffix); - print_byte_array_as_string(@x); - - // Valid string with a non-printable character. - let mut x: ByteArray = "Hello"; - x.append_byte(0x11); // Non-printable character. - let suffix: ByteArray = "world"; - x.append(@suffix); - print_byte_array_as_string(@x); - - // Valid string with a newline. - let mut x: ByteArray = "Hello"; - x.append_byte(0xA); // '\n' - let suffix: ByteArray = "world"; - x.append(@suffix); - print_byte_array_as_string(@x); - - // Multiple values: (felt, string, short_string, felt) - let x = array![0x9999, BYTE_ARRAY_MAGIC, 0, 'hello', 5, 'world', 0x8888]; - x.print(); -} - -#[ignore] -#[test] -fn test_print_macro() { - // With a ByteArray. - let ba: ByteArray = "hello"; - print!("{}", ba); - - // With a felt252. - print!("{}", 97_felt252); - - // With an integer. - print!("{}", 97_usize); -} - -#[ignore] -#[test] -fn test_println_macro() { - // With a ByteArray. - let ba: ByteArray = "hello"; - println!("{}", ba); - - // With a felt252. - println!("{}", 97_felt252); - - // With an integer. - println!("{}", 97_usize); -} diff --git a/corelib/src/test/qm31_test.cairo b/corelib/src/test/qm31_test.cairo deleted file mode 100644 index ef64d5c51b..0000000000 --- a/corelib/src/test/qm31_test.cairo +++ /dev/null @@ -1,67 +0,0 @@ -use core::qm31::{QM31Trait, m31, qm31, qm31_const}; - -#[test] -fn test_qm31_add_and_sub() { - let a = qm31_const::<0x544b2fba, 0x673cff77, 0x60713d44, 0x499602d2>(); - let b = qm31_const::<0x499602d2, 0x544b2fba, 0x673cff77, 0x60713d44>(); - let c = qm31_const::<0x1de1328d, 0x3b882f32, 0x47ae3cbc, 0x2a074017>(); - assert!(a + b == c); - assert!(b + a == c); - assert!(c - a == b); - assert!(c - b == a); -} - -#[test] -fn test_qm31_mul_and_div() { - let a = qm31_const::<0x544b2fba, 0x673cff77, 0x60713d44, 0x499602d2>(); - let b = qm31_const::<0x4b18de99, 0x55f6fb62, 0x6e2290d9, 0x7cd851b9>(); - let c = qm31_const::<0x38810ab4, 0x5a0fd30a, 0x2527b81e, 0x4b1ed1cd>(); - assert!(a * b == c); - assert!(b * a == c); - assert!(c / a == b); - assert!(c / b == a); -} - -#[test] -fn test_qm31_inverse() { - let one = qm31_const::<1, 0, 0, 0>(); - let a = qm31_const::<0x4b18de99, 0x55f6fb62, 0x6e2290d9, 0x7cd851b9>(); - assert!((one / a) * a == one); - let a = qm31_const::<1, 2, 3, 4>(); - assert!((one / a) * a == one); - let a = qm31_const::<0x6849959f, 0x31bf5a51, 0x730c2120, 0x7b0430a5>(); - assert!((one / a) * a == one); -} - -#[test] -fn test_pack() { - assert!(QM31Trait::new(1, 2, 3, 4) == qm31_const::<1, 2, 3, 4>()); - assert!(QM31Trait::new(2, 3, 4, 1) == qm31_const::<2, 3, 4, 1>()); - assert!(QM31Trait::new(3, 4, 1, 2) == qm31_const::<3, 4, 1, 2>()); - assert!(QM31Trait::new(4, 1, 2, 3) == qm31_const::<4, 1, 2, 3>()); -} - -#[test] -fn test_unpack() { - assert_eq!(qm31_const::<1, 2, 3, 4>().unpack(), [1, 2, 3, 4]); - assert_eq!(qm31_const::<2, 3, 4, 1>().unpack(), [2, 3, 4, 1]); - assert_eq!(qm31_const::<3, 4, 1, 2>().unpack(), [3, 4, 1, 2]); - assert_eq!(qm31_const::<4, 1, 2, 3>().unpack(), [4, 1, 2, 3]); -} - -#[test] -fn test_m31_into_qm31() { - assert_eq!(Into::::into(1).unpack(), [1, 0, 0, 0]); - assert_eq!(Into::::into(2).unpack(), [2, 0, 0, 0]); - assert_eq!(Into::::into(3).unpack(), [3, 0, 0, 0]); - assert_eq!(Into::::into(4).unpack(), [4, 0, 0, 0]); -} -use core::qm31::m31_ops; - -#[test] -fn test_m31_ops() { - assert_eq!(m31_ops::add(0x544b2fba, 0x4b18de99), 0x1f640e54); - assert_eq!(m31_ops::sub(0x4b18de99, 0x544b2fba), 0x76cdaede); - assert_eq!(m31_ops::mul(0x544b2fba, 0x4b18de99), 0x3d3740d1); - assert_eq!(m31_ops::div(0x544b2fba, 0x4b18de99), 0x4b887296); -} diff --git a/corelib/src/test/range_test.cairo b/corelib/src/test/range_test.cairo deleted file mode 100644 index 14cfa06310..0000000000 --- a/corelib/src/test/range_test.cairo +++ /dev/null @@ -1,66 +0,0 @@ -use core::ops::{RangeInclusiveTrait, RangeTrait}; - -#[test] -fn test_range_is_empty() { - assert!(!(3_u8..5_u8).is_empty()); - assert!((3_u8..3_u8).is_empty()); - assert!((3_u8..2_u8).is_empty()); -} - -#[test] -fn test_range_contains() { - assert!(!(3_u8..5).contains(@2)); - assert!((3_u8..5).contains(@3)); - assert!((3_u8..5).contains(@4)); - assert!(!(3_u8..5).contains(@5)); - - assert!(!(3_u8..3).contains(@3)); - assert!(!(3_u8..2).contains(@3)); -} - -#[test] -fn test_range_format() { - assert!(format!("{:?}", 1..5) == "1..5"); -} - -#[test] -fn test_range_inclusive_iterator() { - let mut iter = (1_usize..=3).into_iter(); - assert!(iter.next() == Some(1)); - assert!(iter.next() == Some(2)); - assert!(iter.next() == Some(3)); - assert!(iter.next() == None); -} - -#[test] -fn test_range_inclusive_iterator_range_end() { - let mut iter = (253_u8..=255).into_iter(); - assert!(iter.next() == Some(253)); - assert!(iter.next() == Some(254)); - assert!(iter.next() == Some(255)); - assert!(iter.next() == None); -} - -#[test] -fn test_range_inclusive_empty_ranges() { - let mut iter = (255_u8..=125).into_iter(); - assert!(iter.next() == None); - let mut iter = (255_u8..=0).into_iter(); - assert!(iter.next() == None); -} - -#[test] -fn test_range_inclusive_contains() { - assert!(!(3_u8..=5).contains(@2)); - assert!((3_u8..=5).contains(@3)); - assert!((3_u8..=5).contains(@4)); - assert!((3_u8..=5).contains(@5)); - assert!(!(3_u8..=5).contains(@6)); -} - -#[test] -fn test_range_inclusive_is_empty() { - assert!(!(3_u8..=5).is_empty()); - assert!(!(3_u8..=3).is_empty()); - assert!((3_u8..=2).is_empty()); -} diff --git a/corelib/src/test/result_test.cairo b/corelib/src/test/result_test.cairo deleted file mode 100644 index ee89e36fef..0000000000 --- a/corelib/src/test/result_test.cairo +++ /dev/null @@ -1,328 +0,0 @@ -use crate::result::{Result, ResultTraitImpl}; - -#[test] -fn test_result_ok_expect() { - let result: Result = Ok(42); - assert(result.expect('') == 42, 'result_ok_expect'); -} - -#[test] -#[should_panic(expected: ('err msg',))] -fn test_result_err_expect() { - let result: Result = Err('no'); - result.expect('err msg'); -} - -#[test] -fn test_result_ok_unwrap() { - let result: Result = Ok(42); - assert(result.unwrap() == 42, 'result_ok_unwrap'); -} - -#[test] -#[should_panic(expected: ('Result::unwrap failed.',))] -fn test_result_err_unwrap() { - let result: Result = Err('no'); - result.unwrap(); -} - -#[test] -fn test_result_ok_unwrap_or() { - let result: Result = Ok(42); - assert(result.unwrap_or(0) == 42, 'result_ok_unwrap_or'); -} - -#[test] -fn test_result_err_unwrap_or() { - let result: Result = Err('no'); - assert(result.unwrap_or(0) == 0, 'result_err_unwrap_or'); -} - -#[test] -fn test_result_ok_unwrap_or_default() { - let result: Result = Ok(42); - assert(result.unwrap_or_default() == 42, 'result_ok_unwrap_or_default'); -} - -#[test] -fn test_result_err_unwrap_or_default() { - let result: Result = Err('no'); - assert(result.unwrap_or_default() == 0, 'result_err_unwrap_or_default'); -} - -#[test] -fn test_result_ok_unwrap_or_else() { - assert!(Ok(2).unwrap_or_else(|e: ByteArray| e.len()) == 2); -} - -#[test] -fn test_result_err_unwrap_or_else() { - assert!(Err("foo").unwrap_or_else(|e: ByteArray| e.len()) == 3); -} - -#[test] -fn test_result_ok_and_err() { - let x: Result = Ok(2); - let y: Result = Err("late error"); - assert!(x.and(y) == Err("late error")); -} - -#[test] -fn test_result_err_and_ok() { - let x: Result = Err("early error"); - let y: Result = Ok("foo"); - assert!(x.and(y) == Err("early error")); -} - -#[test] -fn test_result_err_and_err() { - let x: Result = Err("not a 2"); - let y: Result = Err("late error"); - assert!(x.and(y) == Err("not a 2")); -} - -#[test] -fn test_result_and_ok_and_ok() { - let x: Result = Ok(2); - let y: Result = Ok("different result type"); - assert!(x.and(y) == Ok("different result type")); -} - -#[test] -fn test_result_err_and_then() { - let checked_mul = core::num::traits::CheckedMul::checked_mul(65536_u32, 65536_u32) - .ok_or("overflowed"); - let res: Result = checked_mul.and_then(|v| Ok(format!("{}", v))); - assert!(res == Err("overflowed")); -} - -#[test] -fn test_result_ok_and_then_err() { - let x: Result = Result::::Ok(2) - .and_then(|_x| Err("late error")); - assert!(x == Err("late error")); -} - -#[test] -fn test_result_ok_and_then_ok() { - let checked_mul = core::num::traits::CheckedMul::checked_mul(4_u32, 4_u32).ok_or("overflowed"); - let res: Result = checked_mul.and_then(|v| Ok(format!("{}", v))); - assert!(res == Ok("16")); -} - -#[test] -fn test_result_or_ok_and_err() { - let x: Result = Ok(2); - let y: Result = Err("late error"); - assert!(x.or(y) == Ok(2)); -} - -#[test] -fn test_result_or_err_and_ok() { - let x: Result = Err("early error"); - let y: Result = Ok(2); - assert!(x.or(y) == Ok(2)); -} - -#[test] -fn test_result_or_err_and_err() { - let x: Result = Err("not a 2"); - let y: Result = Err("late error"); - assert!(x.or(y) == Err("late error")); -} - -#[test] -fn test_result_or_ok_and_ok() { - let x: Result = Ok(2); - let y: Result = Ok(100); - assert!(x.or(y) == Ok(2)); -} - -#[test] -fn test_result_err_or_else_err() { - let y: Result = Result::::Err("bad input") - .or_else(|_e| Err("not 42")); - assert!(y == Err("not 42")); -} - -#[test] -fn test_result_err_or_else_ok() { - let x: Result = Result::::Err("bad input").or_else(|_e| Ok(42)); - assert!(x == Ok(42)); -} - -#[test] -fn test_result_ok_or_else() { - let z: Result = Result::::Ok(100).or_else(|_e| Ok(42)); - assert!(z == Ok(100)); -} - - -#[test] -#[should_panic(expected: ('err msg',))] -fn test_result_ok_expect_err() { - let result: Result = Ok(42); - result.expect_err('err msg'); -} - -#[test] -fn test_result_err_expect_err() { - let result: Result = Err('no'); - assert(result.expect_err('') == 'no', 'result_err_expect_err'); -} - -#[test] -#[should_panic(expected: ('Result::unwrap_err failed.',))] -fn test_result_ok_unwrap_err() { - let result: Result = Ok(42); - result.unwrap_err(); -} - -#[test] -fn test_result_err_unwrap_err() { - let result: Result = Err('no'); - assert(result.unwrap_err() == 'no', 'result_err_unwrap_err'); -} - -#[test] -fn test_result_ok_is_ok() { - let result: Result = Ok(42); - assert(result.is_ok(), 'result_ok_is_ok'); -} - -#[test] -fn test_result_err_is_ok() { - let result: Result = Err('no'); - assert(!result.is_ok(), 'result_err_is_ok'); -} - -#[test] -fn test_result_ok_is_err() { - let result: Result = Ok(42); - assert(!result.is_err(), 'result_ok_is_err'); -} - -#[test] -fn test_result_err_is_err() { - let result: Result = Err('no'); - assert(result.is_err(), 'result_err_is_err'); -} - -#[test] -fn test_result_ok_into_is_err() { - let result: Result = Ok(42); - assert(!result.into_is_err(), 'result_ok_into_is_err'); -} - -#[test] -fn test_result_err_into_is_err() { - let result: Result = Err('no'); - assert(result.into_is_err(), 'result_err_into_is_err'); -} - -#[test] -fn test_result_ok_into_is_ok() { - let result: Result = Ok(42); - assert(result.into_is_ok(), 'result_ok_into_is_ok'); -} - -#[test] -fn test_result_err_into_is_ok() { - let result: Result = Err('no'); - assert(!result.into_is_ok(), 'result_err_into_is_ok'); -} - -#[test] -fn test_result_ok_ok_should_return_ok_value() { - let x: Result = Ok(2); - assert_eq!(x.ok(), Some(2)); -} - -#[test] -fn test_result_err_ok_should_return_none() { - let x: Result = Err("Nothing here"); - assert!(x.ok().is_none()); -} - -#[test] -fn test_result_err_err_should_return_error_value() { - let x: Result = Err("Nothing here"); - assert_eq!(x.err(), Some("Nothing here")); -} - -#[test] -fn test_result_ok_err_should_return_none() { - let x: Result = Ok(2); - assert!(x.err().is_none()); -} - -#[test] -fn test_result_ok_map() { - let x: Result = Ok(1); - assert!(x.map(|i| i * 2) == Ok(2)); -} - -#[test] -fn test_result_err_map() { - let x: Result = Err("error"); - assert!(x.map(|i| i * 2) == Err("error")); -} - -#[test] -fn test_result_ok_map_or() { - let x: Result = Ok("foo"); - assert!(x.map_or(42, |v: ByteArray| v.len()) == 3); -} - -#[test] -fn test_result_err_map_or() { - let x: Result = Err("bar"); - assert!(x.map_or(42, |v: ByteArray| v.len()) == 42); -} - -#[test] -fn test_result_ok_map_or_else() { - let k = 21; - let x: Result = Ok("foo"); - assert!(x.map_or_else(|_e: ByteArray| k * 2, |v: ByteArray| v.len()) == 3); -} - -#[test] -fn test_result_err_map_or_else() { - let k = 21; - let x: Result<_, ByteArray> = Err("bar"); - assert!(x.map_or_else(|_e| k * 2, |v: ByteArray| v.len()) == 42); -} - -#[test] -fn test_result_ok_map_err() { - let stringify = |x: u32| -> ByteArray { - format!("error code: {}", x) - }; - let x: Result = Ok(2); - assert!(x.map_err(stringify) == Result::::Ok(2)); -} - -#[test] -fn test_result_err_map_err() { - let stringify = |x: u32| -> ByteArray { - format!("error code: {}", x) - }; - let x: Result = Err(13); - assert!(x.map_err(stringify) == Err("error code: 13")); -} - -#[test] -fn test_result_ok_iter_next() { - let x: Result = Ok(5); - let mut x_iter = x.into_iter(); - assert!(x_iter.next() == Some(5)); - assert!(x_iter.next() == None); -} - -#[test] -fn test_result_err_iter_next() { - let x: Result = Err("nothing!"); - let mut x_iter = x.into_iter(); - assert!(x_iter.next() == None); -} diff --git a/corelib/src/test/secp256k1_test.cairo b/corelib/src/test/secp256k1_test.cairo deleted file mode 100644 index c26a20271b..0000000000 --- a/corelib/src/test/secp256k1_test.cairo +++ /dev/null @@ -1,172 +0,0 @@ -use starknet::eth_address::U256IntoEthAddress; -use starknet::eth_signature::verify_eth_signature; -use starknet::secp256_trait::{ - Secp256PointTrait, Signature, is_valid_signature, recover_public_key, signature_from_vrs, -}; -use starknet::secp256k1::{Secp256k1Impl, Secp256k1Point}; -use starknet::{EthAddress, SyscallResultTrait}; -use crate::serde::Serde; - -#[test] -fn test_secp256k1_point_serde() { - let (x, y): (u256, u256) = ( - 0xa9a02d48081294b9bb0d8740d70d3607feb20876964d432846d9b9100b91eefd, - 0x18b410b5523a1431024a6ab766c89fa5d062744c75e49efb9925bf8025a7c09e, - ); - let mut serialized_coordinates = array![]; - (x, y).serialize(ref serialized_coordinates); - let mut serialized_coordinates = serialized_coordinates.span(); - let point = Serde::::deserialize(ref serialized_coordinates).unwrap(); - - let mut actual_coordinates = array![]; - point.serialize(ref actual_coordinates); - - assert_eq!( - (@x.low.into(), @x.high.into(), @y.low.into(), @y.high.into()), - ( - actual_coordinates.at(0), - actual_coordinates.at(1), - actual_coordinates.at(2), - actual_coordinates.at(3), - ), - ); -} - -#[test] -fn test_secp256k1_recover_public_key() { - let y_parity = true; - let (msg_hash, signature, expected_public_key_x, expected_public_key_y, _) = - get_message_and_signature( - :y_parity, - ); - let public_key = recover_public_key::(msg_hash, signature).unwrap(); - let (x, y) = public_key.get_coordinates().unwrap_syscall(); - assert(expected_public_key_x == x, 'recover failed 1'); - assert(expected_public_key_y == y, 'recover failed 2'); - - let y_parity = false; - let (msg_hash, signature, expected_public_key_x, expected_public_key_y, _) = - get_message_and_signature( - :y_parity, - ); - let public_key = recover_public_key::(msg_hash, signature).unwrap(); - let (x, y) = public_key.get_coordinates().unwrap_syscall(); - assert(expected_public_key_x == x, 'recover failed 3'); - assert(expected_public_key_y == y, 'recover failed 4'); -} - -#[test] -fn test_signature_from_vrs() { - let v = 27; - let r = 1; - let s = 2; - let signature = signature_from_vrs(v, r, s); - - assert(signature == Signature { r, s, y_parity: false }, 'Wrong result'); -} - -/// Returns a golden valid message hash and its signature, for testing. -fn get_message_and_signature(y_parity: bool) -> (u256, Signature, u256, u256, EthAddress) { - let msg_hash = 0xe888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3e934f78d7a71dd85; - let r = 0x4c8e4fbc1fbb1dece52185e532812c4f7a5f81cf3ee10044320a0d03b62d3e9a; - let s = 0x4ac5e5c0c0e8a4871583cc131f35fb49c2b7f60e6a8b84965830658f08f7410c; - - let (public_key_x, public_key_y) = if y_parity { - ( - 0xa9a02d48081294b9bb0d8740d70d3607feb20876964d432846d9b9100b91eefd, - 0x18b410b5523a1431024a6ab766c89fa5d062744c75e49efb9925bf8025a7c09e, - ) - } else { - ( - 0x57a910a2a58ef7d57f452e1f6ea7ee0080789091de946b0ca6e5c6af2c8ff5c8, - 0x249d233d0d21f35db55ce852edbd340d31e92ea4d591886149ca5d89911331ac, - ) - }; - let eth_address = 0x767410c1bb448978bd42b984d7de5970bcaf5c43_u256.into(); - - (msg_hash, Signature { r, s, y_parity }, public_key_x, public_key_y, eth_address) -} - -#[test] -fn test_verify_eth_signature() { - let y_parity = true; - let (msg_hash, signature, _expected_public_key_x, _expected_public_key_y, eth_address) = - get_message_and_signature( - :y_parity, - ); - verify_eth_signature(:msg_hash, :signature, :eth_address); -} - -#[test] -#[should_panic(expected: ('Invalid signature',))] -fn test_verify_eth_signature_wrong_eth_address() { - let y_parity = true; - let (msg_hash, signature, _expected_public_key_x, _expected_public_key_y, eth_address) = - get_message_and_signature( - :y_parity, - ); - let eth_address = (eth_address.into() + 1).try_into().unwrap(); - verify_eth_signature(:msg_hash, :signature, :eth_address); -} - -#[test] -#[should_panic(expected: ('Signature out of range',))] -fn test_verify_eth_signature_overflowing_signature_r() { - let y_parity = true; - let (msg_hash, mut signature, _expected_public_key_x, _expected_public_key_y, eth_address) = - get_message_and_signature( - :y_parity, - ); - signature.r = Secp256k1Impl::get_curve_size() + 1; - verify_eth_signature(:msg_hash, :signature, :eth_address); -} - -#[test] -#[should_panic(expected: ('Signature out of range',))] -fn test_verify_eth_signature_overflowing_signature_s() { - let y_parity = true; - let (msg_hash, mut signature, _expected_public_key_x, _expected_public_key_y, eth_address) = - get_message_and_signature( - :y_parity, - ); - signature.s = Secp256k1Impl::get_curve_size() + 1; - verify_eth_signature(:msg_hash, :signature, :eth_address); -} - -#[test] -#[should_panic(expected: 'Public key recovery failed')] -fn test_verify_eth_signature_invalid_signature() { - let (msg_hash, mut signature, _, _, eth_address) = get_message_and_signature(y_parity: true); - signature.r = 5; // invalid r (no point on curve with x=5) - verify_eth_signature(:msg_hash, :signature, :eth_address); -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature() { - let (msg_hash, signature, public_key_x, public_key_y, _) = get_message_and_signature(false); - - let public_key = Secp256k1Impl::secp256_ec_new_syscall(public_key_x, public_key_y) - .unwrap_syscall() - .unwrap(); - - let is_valid = is_valid_signature::< - Secp256k1Point, - >(msg_hash, signature.r, signature.s, public_key); - assert(is_valid, 'Signature should be valid'); -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature_invalid_signature() { - let (msg_hash, signature, public_key_x, public_key_y, _) = get_message_and_signature(false); - - let public_key = Secp256k1Impl::secp256_ec_new_syscall(public_key_x, public_key_y) - .unwrap_syscall() - .unwrap(); - - let is_valid = is_valid_signature::< - Secp256k1Point, - >(msg_hash, signature.r + 1, signature.s, public_key); - assert(!is_valid, 'Signature should be invalid'); -} diff --git a/corelib/src/test/secp256r1_test.cairo b/corelib/src/test/secp256r1_test.cairo deleted file mode 100644 index db0a520d47..0000000000 --- a/corelib/src/test/secp256r1_test.cairo +++ /dev/null @@ -1,118 +0,0 @@ -use starknet::SyscallResultTrait; -use starknet::secp256_trait::{Secp256PointTrait, Signature, is_valid_signature, recover_public_key}; -use starknet::secp256r1::{Secp256r1Impl, Secp256r1Point}; -use crate::option::OptionTrait; -use crate::test::test_utils::assert_eq; - -#[test] -fn test_secp256r1_point_serde() { - let (x, y): (u256, u256) = ( - 0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5, - 0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d, - ); - let mut serialized_coordinates = array![]; - (x, y).serialize(ref serialized_coordinates); - let mut serialized_coordinates = serialized_coordinates.span(); - let point = Serde::::deserialize(ref serialized_coordinates).unwrap(); - - let mut actual_coordinates = array![]; - point.serialize(ref actual_coordinates); - - assert_eq!( - (@x.low.into(), @x.high.into(), @y.low.into(), @y.high.into()), - ( - actual_coordinates.at(0), - actual_coordinates.at(1), - actual_coordinates.at(2), - actual_coordinates.at(3), - ), - ); -} - -#[test] -fn test_secp256r1_recover_public_key() { - let (msg_hash, signature, expected_public_key_x, expected_public_key_y, _) = - get_message_and_signature(); - let public_key = recover_public_key::(msg_hash, signature).unwrap(); - let (x, y) = public_key.get_coordinates().unwrap_syscall(); - assert(expected_public_key_x == x, 'recover failed 1'); - assert(expected_public_key_y == y, 'recover failed 2'); -} - - -/// Returns a golden valid message hash and its signature, for testing. -fn get_message_and_signature() -> (u256, Signature, u256, u256, Secp256r1Point) { - // msg = "" - // public key: (0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5, - // 0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d) - let msg_hash = 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; - let r = 0xb292a619339f6e567a305c951c0dcbcc42d16e47f219f9e98e76e09d8770b34a; - let s = 0x177e60492c5a8242f76f07bfe3661bde59ec2a17ce5bd2dab2abebdf89a62e2; - - let (public_key_x, public_key_y) = ( - 0x04aaec73635726f213fb8a9e64da3b8632e41495a944d0045b522eba7240fad5, - 0x0087d9315798aaa3a5ba01775787ced05eaaf7b4e09fc81d6d1aa546e8365d525d, - ); - - let public_key = Secp256r1Impl::secp256_ec_new_syscall(public_key_x, public_key_y) - .unwrap_syscall() - .unwrap(); - - (msg_hash, Signature { r, s, y_parity: true }, public_key_x, public_key_y, public_key) -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature() { - let (msg_hash, signature, _, _, public_key) = get_message_and_signature(); - let is_valid = is_valid_signature::< - Secp256r1Point, - >(msg_hash, signature.r, signature.s, public_key); - assert(is_valid, 'Signature should be valid'); -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature_invalid_signature() { - let (msg_hash, signature, _, _, public_key) = get_message_and_signature(); - let is_valid = is_valid_signature::< - Secp256r1Point, - >(msg_hash, signature.r + 1, signature.s, public_key); - assert(!is_valid, 'Signature should be invalid'); -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature_overflowing_signature_r() { - let (msg_hash, mut signature, _, _, public_key) = get_message_and_signature(); - let is_valid = is_valid_signature::< - Secp256r1Point, - >(msg_hash, Secp256r1Impl::get_curve_size() + 1, signature.s, public_key); - assert(!is_valid, 'Signature out of range'); -} - -#[test] -#[available_gas(100000000)] -fn test_verify_signature_overflowing_signature_s() { - let (msg_hash, mut signature, _, _, public_key) = get_message_and_signature(); - let is_valid = is_valid_signature::< - Secp256r1Point, - >(msg_hash, signature.r, Secp256r1Impl::get_curve_size() + 1, public_key); - assert(!is_valid, 'Signature out of range'); -} - - -#[test] -fn test_recover_public_key_y_even() { - let x: u256 = 0x502a43ce77c6f5c736a82f847fa95f8c2d483fe223b12b91047d83258a958b0f; - let _y: u256 = 0xdb0a2e6710c71ba80afeb3abdf69d306ce729c7704f4ddf2eaaf0b76209fe1b0; - let r: u256 = 0x7380df4a623c5c2259a5e5f5b225d7265a9e24b3a13c101d1afddcf29e3cf8b2; - let s: u256 = 0x0d131afacdd17a4ea1b544bb3ade677ff8accbe7830e15b9c225e6031155946a; - let y_parity = false; - let message_hash: u256 = 0x28c7fff9aef4847a82cd64280434712a5b49205831b60eea6e70614077e672eb; - let recovered = recover_public_key::(message_hash, Signature { r, s, y_parity }) - .unwrap(); - let (recovered_x, _recovered_y) = recovered.get_coordinates().unwrap_syscall(); - - assert_eq(@recovered_x, @x, 'Signature is not valid'); -} diff --git a/corelib/src/test/sha256_test.cairo b/corelib/src/test/sha256_test.cairo deleted file mode 100644 index 0f860b5333..0000000000 --- a/corelib/src/test/sha256_test.cairo +++ /dev/null @@ -1,172 +0,0 @@ -use crate::sha256::compute_sha256_byte_array; - -#[test] -fn test_sha256_byte_array() { - assert_eq!( - sha256_as_u256("a"), 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb, - ); - assert_eq!( - sha256_as_u256("aa"), 0x961b6dd3ede3cb8ecbaacbd68de040cd78eb2ed5889130cceb4c49268ea4d506, - ); - assert_eq!( - sha256_as_u256("aaa"), 0x9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0, - ); - assert_eq!( - sha256_as_u256("aaaa"), 0x61be55a8e2f6b4e172338bddf184d6dbee29c98853e0a0485ecee7f27b9af0b4, - ); - // test length 0 - assert_eq!( - sha256_as_u256(""), 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, - ); - // test length 1 - assert_eq!( - sha256_as_u256("x"), 0x2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881, - ); - // test length 7 - assert_eq!( - sha256_as_u256("xffidcw"), - 0x692ca8f4448048d3eee81365d91f9220c4c446d123bf9dcd82a6e4d0dfd0940a, - ); - // test length 8 - assert_eq!( - sha256_as_u256("szhgvskg"), - 0xbea98c851b81bb113b5b8fbb7add06a8aaae36555b63bbf3abe393b8b35260bd, - ); - // test length 9 - assert_eq!( - sha256_as_u256("nokwxzwsl"), - 0x063dc8cf320d4dd4403c2e22b7255ab21898c97e4a131d26e1fc0589f7e9cbc4, - ); - // test length 15 - assert_eq!( - sha256_as_u256("bhmvtgdkhgajqaf"), - 0xaffa8850bb7b05ac9e948fda305bfe39a15057a0269225ae8c2eeeb3c46e8fe8, - ); - // test length 16 - assert_eq!( - sha256_as_u256("qxwwcxzjiibvkqky"), - 0xef1b40920adc9bd453103e171e79776be73f53288dd22baeb087f664e300d1e2, - ); - // test length 17 - assert_eq!( - sha256_as_u256("ipjjkvuojtcinvvnu"), - 0x5419df507a08e45a805ae8dcdcfe544fbdfb955e71b65b048f46b4961aebf06c, - ); - // test length 23 - assert_eq!( - sha256_as_u256("ygjbndjbjqfqwrywlpggahh"), - 0xb717c1690433f7e07809147d740c2061ce62ca12ac1e458bb2c9c7b4e720e1e2, - ); - // test length 24 - assert_eq!( - sha256_as_u256("tqeruqfqlvrsxhjjzyfiuyni"), - 0xb4706bbfe2551f3838df517953f1f2e4cbd869c020fc2a6a78bd6dce26b2996d, - ); - // test length 25 - assert_eq!( - sha256_as_u256("oppudxpkzsspqtmopvdhicyhc"), - 0xd81c9f032105f08d7411af404b9c40ba773e9fb5109ec43d742ab2b124b0985f, - ); - // test length 31 - assert_eq!( - sha256_as_u256("iehpuxzsxzffqyhqxsnsybpygdscgrf"), - 0x0814d4d5d16c637c0c32b9cbe4831284027ea275f4363c7a0c2006eefcaf6a95, - ); - // test length 32 - assert_eq!( - sha256_as_u256("dwdnlgtqkicjpyonhxtzqmxxqsjiwuov"), - 0x41e8c2ec97ab4c2ca0ea63a4d457d184f9daeeecfc67369fb485657227ee4055, - ); - // test length 33 - assert_eq!( - sha256_as_u256("owhqocwxqapkjjryeveiuvyomnzgptexp"), - 0x7ca52baf871a67553eae8e1b7e319a4186f41a31bea6a8b13553986b5494304d, - ); - // test length 39 - assert_eq!( - sha256_as_u256("jhgdvhubfsgmvqaiehclbhxtkerusriurmepeyz"), - 0x7ca8143c46fb792674f225441b7471b7f545571517478bce80e7e0c9cdbefff8, - ); - // test length 40 - assert_eq!( - sha256_as_u256("pbzqxiqewdfzvelghpjclwwhkocssdmknssasdap"), - 0xdeff2a399ce47b6289bd6c051341403e195b4a68c299729414d13bcdef3eaee3, - ); - // test length 41 - assert_eq!( - sha256_as_u256("twxzmlfepsjutlpmlpsetkfvixlttvegfdxeefcda"), - 0xebd7f16ac58ae7cc6fa5469c229b896f2a76440d394e0717ff1c49cc777dd81b, - ); - // test length 47 - assert_eq!( - sha256_as_u256("ahdlyumrwxiwumrvkscepnxtptzsdkzhlfpuhypdoeqcqql"), - 0x31db2dea1937ece94652015558e98da557a1c6cf1841cd25e3e0748818a75f1c, - ); - // test length 48 - assert_eq!( - sha256_as_u256("kmjeneddmhlcsyokduzjovbynzatmmqoekslfwiqbcoaudgd"), - 0x0b9cda0453fa1adbe558a18f7af8c72090891471ac3b09faa1ddf942d223c73b, - ); - // test length 49 - assert_eq!( - sha256_as_u256("vyqcddnljnjajyilmafspxnwgxlgwulpkdgvpaweitfgjcgue"), - 0x1ea01ee2976b0361f8a24346c0f26911a98597a9ab2ebbd293fe7cfad72e6a7a, - ); - // test length 55 - assert_eq!( - sha256_as_u256("wugdolcxgjgjugcibpydicnpjkeygkowbkqvsqhnydknzpiguhcwaxt"), - 0xb3fffae87e85a7d9085d04210e29a3dfc27469c61e60a957ad0c87db71c8cb79, - ); - // test length 56 - assert_eq!( - sha256_as_u256("sdkxocmqvmljrezvkkfnylvjoklmpeyimvtnhtkheylolizwtqulbluf"), - 0x5c2b04d3b63a9fd04afe1137a00f1c642a962933e20ef1d4e4729fd1cadb01a6, - ); - // test length 57 - assert_eq!( - sha256_as_u256("msrqhpytgzqnavnazvhswjwifxwvkiapcetishwuagxultoimyfzoself"), - 0x55bc8a6602d12fc6d5354ad9964e2d13ca9e3ede3e2e788c4c928d75b175a7ca, - ); - // test length 63 - assert_eq!( - sha256_as_u256("xtoesagtsybcibtwsqxqltbdiygasnozjniwqnjakjogmcvdpujpprgcdmtuyvn"), - 0x7f70e2a9a8854f0634b57721b48fa5f95185b2ca1099d9e093088e416245da06, - ); - // test length 64 - assert_eq!( - sha256_as_u256("fjxootkrqqljdfdvwwxjhndsqshphzaoehyyibqulmtihoutvofsekymjwczelit"), - 0x58c09482981dffd40109b7c14c82418ac1841395e9bbf106d53b0f228b37a464, - ); - // test length 65 - assert_eq!( - sha256_as_u256("phtpnnjkxyinhxkwklyvxxrmhzaenpkauucubsubwcjucuyauxahxvylffqiqezbd"), - 0x9cba0ff0b0a2ec07208b46ef0a89a27bbbfe23fd24d8b9939a603c2f47bac1b0, - ); - // test length 71 - assert_eq!( - sha256_as_u256("gjgdfsbmbbyhbuujhwlsvobhsfooaogvzxeixzpccpzogkkkkxuorhtaaemyojknipfdewb"), - 0x7d3bc3e84c1a82e4ea1e16a5150f73657a4d54f1ee127bd963f6ecf160c6d3bb, - ); - // test length 72 - assert_eq!( - sha256_as_u256("kbziqjtltnzicqhvcgiqfbvamdhddiqzyqucuzbualvrajlcaslsvubilzfwvioysvdqypcp"), - 0xd1e18df0c2acc467e21cd7c7ea46c239bfdf3b75cc55addd255eee751daf5d54, - ); - // test length 73 - assert_eq!( - sha256_as_u256("ugombvhpwrkpgvqdwjpopdbqvmldlupczklkdevzkhsjzfylgrkotaoltbnxtoqdhposxtuaz"), - 0xe64839141b5b17df5f84c7fb5561723f6050cf0bc52c81082a50f2de99e4a617, - ); -} - -/// computes the sha256 of the input and returns it as a u256. -fn sha256_as_u256(input: ByteArray) -> u256 { - let hash_result = compute_sha256_byte_array(@input); - let mut value: u256 = 0; - for word in hash_result.span() { - value *= 0x100000000; - value = value + (*word).into(); - } - value -} - diff --git a/corelib/src/test/test_utils.cairo b/corelib/src/test/test_utils.cairo deleted file mode 100644 index cd808a1e4b..0000000000 --- a/corelib/src/test/test_utils.cairo +++ /dev/null @@ -1,29 +0,0 @@ -#[inline] -pub fn assert_eq>(a: @T, b: @T, err_code: felt252) { - assert(a == b, err_code); -} - -#[inline] -pub fn assert_ne>(a: @T, b: @T, err_code: felt252) { - assert(a != b, err_code); -} - -#[inline] -pub fn assert_le>(a: T, b: T, err_code: felt252) { - assert(a <= b, err_code); -} - -#[inline] -pub fn assert_lt>(a: T, b: T, err_code: felt252) { - assert(a < b, err_code); -} - -#[inline] -pub fn assert_ge>(a: T, b: T, err_code: felt252) { - assert(a >= b, err_code); -} - -#[inline] -pub fn assert_gt>(a: T, b: T, err_code: felt252) { - assert(a > b, err_code); -} diff --git a/corelib/src/test/testing_test.cairo b/corelib/src/test/testing_test.cairo deleted file mode 100644 index 995bf39325..0000000000 --- a/corelib/src/test/testing_test.cairo +++ /dev/null @@ -1,176 +0,0 @@ -use crate::test::test_utils::assert_gt; - -#[test] -#[should_panic(expected: ('panic_with_felt252()',))] -fn test_panic_with_felt252() { - // No semicolon here: Missing implementation for crate::traits::Drop:: - crate::panic_with_felt252('panic_with_felt252()') -} - -#[test] -#[should_panic(expected: 'assert(false)')] -fn test_assert_false() { - assert(false, 'assert(false)'); -} - -#[test] -fn test_assert_true() { - assert(true, 'assert(true)'); -} - -#[test] -#[should_panic(expected: "assert(false)")] -fn test_assert_macro_false() { - assert!(false, "assert(false)"); -} - -#[test] -fn test_assert_macro_true() { - assert!(true, "assert(true)"); -} - -#[test] -fn test_assert_ne_with_description() { - assert_ne!(1, 2, "Description"); -} - -#[test] -fn test_assert_ne_no_description() { - assert_ne!(1, 2); -} - -#[test] -fn test_assert_lt_with_description() { - assert_lt!(1_u8, 2_u8, "Description"); -} - -#[test] -fn test_assert_lt_no_description() { - assert_lt!(1_u8, 2_u8); -} - -#[test] -fn test_assert_le_with_description() { - assert_le!(1_u8, 2_u8, "Description"); - assert_le!(1_u8, 1_u8, "Description"); -} - -#[test] -fn test_assert_le_no_description() { - assert_le!(1_u8, 2_u8); - assert_le!(1_u8, 1_u8); -} - -#[test] -fn test_assert_gt_with_description() { - assert_gt!(2_u8, 1_u8, "Description"); -} - -#[test] -fn test_assert_gt_no_description() { - assert_gt!(2_u8, 1_u8); -} - -#[test] -fn test_assert_ge_with_description() { - assert_ge!(2_u8, 1_u8, "Description"); - assert_ge!(2_u8, 2_u8, "Description"); -} - -#[test] -fn test_assert_ge_no_description() { - assert_ge!(2_u8, 1_u8); - assert_ge!(2_u8, 2_u8); -} - -#[test] -#[should_panic(expected: "assertion failed: `false`.")] -fn test_assert_macro_no_input() { - assert!(false); -} - -#[test] -#[should_panic(expected: "assertion `1 == 2` failed: Description -1: 1 -2: 2")] -fn test_assert_eq_with_description() { - assert_eq!(1, 2, "Description"); -} - -#[test] -#[should_panic(expected: "assertion `1 == 2` failed: 1 != 2 -1: 1 -2: 2")] -fn test_assert_eq_with_formatted_description() { - assert_eq!(1, 2, "{} != {}", 1, 2); -} - -#[test] -#[should_panic(expected: "assertion `1 == 2` failed. -1: 1 -2: 2")] -fn test_assert_eq_no_description() { - assert_eq!(1, 2); -} - -#[test] -#[available_gas(static)] -fn test_get_available_gas_no_gas_supply() { - assert_eq!(crate::testing::get_available_gas(), 0) -} - -#[test] -#[available_gas(10000)] -fn test_get_available_gas_with_gas_supply() { - assert_gt(crate::testing::get_available_gas(), 5000, 'high amount of gas used') -} - -#[test] -fn test_assert_eq_path_requiring_inference() { - assert_eq!(Option::::None, None); -} - -#[inline(never)] -fn identity(t: T) -> T { - t -} - -#[test] -fn test_get_unspent_gas() { - let one = identity(1); - let two = identity(2); - let prev = crate::testing::get_unspent_gas(); - let _three = identity(one + two); - let after = crate::testing::get_unspent_gas(); - let expected_cost = 100 // `one + two`. - + 300 // `identity(...)`. - + 2600; // `get_unspent_gas()`. - assert_eq!(prev - after, expected_cost); -} - -#[derive(Drop, Debug, PartialEq)] -struct NoCopy { - value: u8, -} - -#[test] -fn test_assert_macros_and_non_copy() { - let a = NoCopy { value: 0 }; - let b = NoCopy { value: 1 }; - assert_eq!(a, a); - assert_ne!(a, b); - assert_eq!(b, b); - assert_ne!(b, a); - assert_eq!(a.value, a.value); - assert_ne!(a.value, b.value); - assert_eq!(b.value, b.value); - assert_ne!(b.value, a.value); - assert_eq!(a, a); - assert_ne!(a, b); - assert_eq!(b, b); - assert_ne!(b, a); - assert_eq!(a.value, a.value); - assert_ne!(a.value, b.value); - assert_eq!(b.value, b.value); - assert_ne!(b.value, a.value); -} diff --git a/corelib/src/test/to_byte_array_test.cairo b/corelib/src/test/to_byte_array_test.cairo deleted file mode 100644 index cc0e2bce6e..0000000000 --- a/corelib/src/test/to_byte_array_test.cairo +++ /dev/null @@ -1,249 +0,0 @@ -use crate::test::test_utils::assert_eq; -use crate::to_byte_array::{AppendFormattedToByteArray, FormatAsByteArray}; - -#[test] -fn test_to_string_hex() { - let hex_base: NonZero = 16_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(hex_base); - assert_eq(@serialized, @expected_string, 'Bad hex representation of 0'); - - let expected_string = "a"; - let serialized = 0xa_u8.format_as_byte_array(hex_base); - assert_eq(@serialized, @expected_string, 'Bad hex representation of 10'); - - let expected_string = "6f"; - let serialized = 0x6f_u8.format_as_byte_array(hex_base); - assert_eq(@serialized, @expected_string, 'Bad hex representation of 111'); - - let expected_string = "ff"; - let serialized = 0xff_u8.format_as_byte_array(hex_base); - assert_eq(@serialized, @expected_string, 'Bad hex representation of 255'); - - // Other uint types: - let expected_string = "6f"; - let serialized = 0x6f_u16.format_as_byte_array(base: 16_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 hex representation'); - let serialized = 0x6f_u32.format_as_byte_array(base: 16_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 hex representation'); - let serialized = 0x6f_u64.format_as_byte_array(base: 16_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 hex representation'); - let serialized = 0x6f_u128.format_as_byte_array(base: 16_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 hex representation'); - let serialized = 0x6f_u256.format_as_byte_array(base: 16_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 hex representation'); - let serialized = 0x6f_felt252.format_as_byte_array(base: 16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 hex representation'); -} -#[test] -fn test_to_string_dec() { - let dec_base: NonZero = 10_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(dec_base); - assert_eq(@serialized, @expected_string, 'Bad dec representation of 0'); - - let expected_string = "10"; - let serialized = 10_u8.format_as_byte_array(dec_base); - assert_eq(@serialized, @expected_string, 'Bad dec representation of 10'); - - let expected_string = "111"; - let serialized = 111_u8.format_as_byte_array(dec_base); - assert_eq(@serialized, @expected_string, 'Bad dec representation of 111'); - - let expected_string = "255"; - let serialized = 255_u8.format_as_byte_array(dec_base); - assert_eq(@serialized, @expected_string, 'Bad dec representation of 255'); - - // Other uint types: - let expected_string = "111"; - let serialized = 111_u16.format_as_byte_array(base: 10_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 dec representation'); - let serialized = 111_u32.format_as_byte_array(base: 10_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 dec representation'); - let serialized = 111_u64.format_as_byte_array(base: 10_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 dec representation'); - let serialized = 111_u128.format_as_byte_array(base: 10_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 dec representation'); - let serialized = 111_u256.format_as_byte_array(base: 10_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 dec representation'); - let serialized = 111_felt252.format_as_byte_array(base: 10.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 dec representation'); -} - -#[test] -fn test_to_string_oct() { - let oct_base: NonZero = 8_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(oct_base); - assert_eq(@serialized, @expected_string, 'Bad oct representation of 0'); - - let expected_string = "12"; - let serialized = 10_u8.format_as_byte_array(oct_base); - assert_eq(@serialized, @expected_string, 'Bad oct representation of 10'); - - let expected_string = "157"; - let serialized = 111_u8.format_as_byte_array(oct_base); - assert_eq(@serialized, @expected_string, 'Bad oct representation of 111'); - - let expected_string = "377"; - let serialized = 255_u8.format_as_byte_array(oct_base); - assert_eq(@serialized, @expected_string, 'Bad oct representation of 255'); - - // Other uint types: - let expected_string = "157"; - let serialized = 111_u16.format_as_byte_array(base: 8_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 oct representation'); - let serialized = 111_u32.format_as_byte_array(base: 8_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 oct representation'); - let serialized = 111_u64.format_as_byte_array(base: 8_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 oct representation'); - let serialized = 111_u128.format_as_byte_array(base: 8_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 oct representation'); - let serialized = 111_u256.format_as_byte_array(base: 8_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 oct representation'); - let serialized = 111_felt252.format_as_byte_array(base: 8.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 oct representation'); -} - -#[test] -fn test_to_string_bin() { - let bin_base: NonZero = 2_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(bin_base); - assert_eq(@serialized, @expected_string, 'Bad bin representation of 0'); - - let expected_string = "1010"; - let serialized = 10_u8.format_as_byte_array(bin_base); - assert_eq(@serialized, @expected_string, 'Bad bin representation of 10'); - - let expected_string = "1101111"; - let serialized = 111_u8.format_as_byte_array(bin_base); - assert_eq(@serialized, @expected_string, 'Bad bin representation of 111'); - - let expected_string = "11111111"; - let serialized = 255_u8.format_as_byte_array(bin_base); - assert_eq(@serialized, @expected_string, 'Bad bin representation of 255'); - - // Other uint types: - let expected_string = "1101111"; - let serialized = 111_u16.format_as_byte_array(base: 2_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 bin representation'); - let serialized = 111_u32.format_as_byte_array(base: 2_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 bin representation'); - let serialized = 111_u64.format_as_byte_array(base: 2_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 bin representation'); - let serialized = 111_u128.format_as_byte_array(base: 2_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 bin representation'); - let serialized = 111_u256.format_as_byte_array(base: 2_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 bin representation'); - let serialized = 111_felt252.format_as_byte_array(base: 2.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 bin representation'); -} - -#[test] -fn test_to_string_base7() { - let base7: NonZero = 7_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(base7); - assert_eq(@serialized, @expected_string, 'Bad b7 representation of 0'); - - let expected_string = "13"; - let serialized = 10_u8.format_as_byte_array(base7); - assert_eq(@serialized, @expected_string, 'Bad b7 representation of 10'); - - let expected_string = "216"; - let serialized = 111_u8.format_as_byte_array(base7); - assert_eq(@serialized, @expected_string, 'Bad b7 representation of 111'); - - let expected_string = "513"; - let serialized = 255_u8.format_as_byte_array(base7); - assert_eq(@serialized, @expected_string, 'Bad b7 representation of 255'); - - // Other uint types: - let expected_string = "216"; - let serialized = 111_u16.format_as_byte_array(base: 7_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 b7 representation'); - let serialized = 111_u32.format_as_byte_array(base: 7_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 b7 representation'); - let serialized = 111_u64.format_as_byte_array(base: 7_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 b7 representation'); - let serialized = 111_u128.format_as_byte_array(base: 7_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 b7 representation'); - let serialized = 111_u256.format_as_byte_array(base: 7_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 b7 representation'); - let serialized = 111_felt252.format_as_byte_array(base: 7.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 b7 representation'); -} - -#[test] -fn test_to_string_base36() { - let base36: NonZero = 36_u8.try_into().unwrap(); - - let expected_string = "0"; - let serialized = 0_u8.format_as_byte_array(base36); - assert_eq(@serialized, @expected_string, 'Bad b36 representation of 0'); - - let expected_string = "a"; - let serialized = 10_u8.format_as_byte_array(base36); - assert_eq(@serialized, @expected_string, 'Bad b36 representation of 10'); - - let expected_string = "3z"; - let serialized = 143_u8.format_as_byte_array(base36); - assert_eq(@serialized, @expected_string, 'Bad b36 representation of 143'); - - let expected_string = "73"; - let serialized = 255_u8.format_as_byte_array(base36); - assert_eq(@serialized, @expected_string, 'Bad b36 representation of 255'); - - // Other uint types: - let expected_string = "3z"; - let serialized = 143_u16.format_as_byte_array(base: 36_u16.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u16 b36 representation'); - let serialized = 143_u32.format_as_byte_array(base: 36_u32.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u32 b36 representation'); - let serialized = 143_u64.format_as_byte_array(base: 36_u64.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u64 b36 representation'); - let serialized = 143_u128.format_as_byte_array(base: 36_u128.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u128 b36 representation'); - let serialized = 143_u256.format_as_byte_array(base: 36_u256.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad u256 b36 representation'); - let serialized = 143_felt252.format_as_byte_array(base: 36.try_into().unwrap()); - assert_eq(@serialized, @expected_string, 'Bad felt252 b36 representation'); -} - -#[test] -fn test_append() { - let expected = "prefix_6f"; - let mut byte_array = "prefix_"; - 111_u8.append_formatted_to_byte_array(ref byte_array, base: 16_u8.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u8'); - - let mut byte_array = "prefix_"; - 111_u16.append_formatted_to_byte_array(ref byte_array, base: 16_u16.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u16'); - - let mut byte_array = "prefix_"; - 111_u32.append_formatted_to_byte_array(ref byte_array, base: 16_u32.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u32'); - - let mut byte_array = "prefix_"; - 111_u64.append_formatted_to_byte_array(ref byte_array, base: 16_u64.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u64'); - - let mut byte_array = "prefix_"; - 111_u128.append_formatted_to_byte_array(ref byte_array, base: 16_u128.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u128'); - - let mut byte_array = "prefix_"; - 111_u256.append_formatted_to_byte_array(ref byte_array, base: 16_u256.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append u256'); - - let mut byte_array = "prefix_"; - 111.append_formatted_to_byte_array(ref byte_array, base: 16.try_into().unwrap()); - assert_eq(@byte_array, @expected, 'Bad append felt252'); -} diff --git a/corelib/src/testing.cairo b/corelib/src/testing.cairo deleted file mode 100644 index 2a4ee484e2..0000000000 --- a/corelib/src/testing.cairo +++ /dev/null @@ -1,62 +0,0 @@ -//! Measurement of gas consumption for testing purpose. -//! -//! This module provides the `get_available_gas` function, useful for asserting the amount of gas -//! consumed by a particular operation or function call. -//! By calling `get_available_gas` before and after the operation, you can calculate the exact -//! amount of gas used. - -use crate::gas::GasBuiltin; - -/// Returns the amount of gas available in the `GasBuiltin`. -/// -/// Useful for asserting that a certain amount of gas was consumed. -/// Note: The actual gas consumption observed by calls to `get_available_gas` is only exact -/// immediately before calls to `withdraw_gas`. -/// -/// # Examples -/// -/// ``` -/// use core::testing::get_available_gas; -/// -/// fn gas_heavy_function() { -/// // ... some gas-intensive code -/// } -/// -/// fn test_gas_consumption() { -/// let gas_before = get_available_gas(); -/// // Making sure `gas_before` is exact. -/// core::gas::withdraw_gas().unwrap(); -/// -/// gas_heavy_function(); -/// -/// let gas_after = get_available_gas(); -/// // Making sure `gas_after` is exact -/// core::gas::withdraw_gas().unwrap(); -/// -/// assert!(gas_before - gas_after < 100_000); -/// } -/// ``` -pub extern fn get_available_gas() -> u128 implicits(GasBuiltin) nopanic; - -/// Returns the amount of gas available in the `GasBuiltin`, as well as the amount of gas unused in -/// the local wallet. -/// -/// Useful for asserting that a certain amount of gas was used. -/// Note: This function call costs exactly `2300` gas, so this may be ignored in calculations. -/// # Examples -/// -/// ``` -/// use core::testing::get_unspent_gas; -/// -/// fn gas_heavy_function() { -/// // ... some gas-intensive code -/// } -/// -/// fn test_gas_consumption() { -/// let gas_before = get_unspent_gas(); -/// gas_heavy_function(); -/// let gas_after = get_unspent_gas(); -/// assert!(gas_before - gas_after < 100_000); -/// } -/// ``` -pub extern fn get_unspent_gas() -> u128 implicits(GasBuiltin) nopanic; diff --git a/corelib/src/to_byte_array.cairo b/corelib/src/to_byte_array.cairo deleted file mode 100644 index b642547a1d..0000000000 --- a/corelib/src/to_byte_array.cairo +++ /dev/null @@ -1,191 +0,0 @@ -//! ASCII representation of numeric types for `ByteArray` manipulation. -//! -//! This module enables conversion of numeric values into their ASCII string representation, -//! with support for different numeric bases and efficient appending to existing `ByteArray`. -//! -//! # Examples -//! -//! Basic decimal formatting: -//! -//! ``` -//! use core::to_byte_array::{FormatAsByteArray, AppendFormattedToByteArray}; -//! -//! let value: u32 = 42; -//! let base: NonZero = 10; -//! -//! // Create a new formatted `ByteArray` -//! let formatted = value.format_as_byte_array(base); -//! assert!(formatted == "42"); -//! -//! // Append to an existing `ByteArray` -//! let mut buffer = "Value: "; -//! value.append_formatted_to_byte_array(ref buffer, base); -//! assert!(buffer == "Value: 42"); -//! ``` -//! -//! Custom base formatting: -//! -//! ``` -//! use core::to_byte_array::FormatAsByteArray; -//! let value: u32 = 255; -//! -//! // Hexadecimal representation -//! let hex = value.format_as_byte_array(16); -//! assert!(hex == "ff"); -//! -//! // Binary representation -//! let bin = value.format_as_byte_array(2); -//! assert!(bin == "11111111"); -//! ``` - -use crate::byte_array::ByteArrayTrait; -use crate::option::OptionTrait; -use crate::traits::{Into, TryInto}; -use crate::zeroable::Zeroable; - -/// A trait for appending the ASCII representation of a number to an existing `ByteArray`. -pub trait AppendFormattedToByteArray { - /// Appends the ASCII representation of the value to the provided `ByteArray`. - /// - /// # Examples - /// - /// ``` - /// use core::to_byte_array::AppendFormattedToByteArray; - /// - /// let mut buffer = "Count: "; - /// let num: u32 = 42; - /// num.append_formatted_to_byte_array(ref buffer, 10); - /// assert!(buffer == "Count: 42"); - /// ``` - fn append_formatted_to_byte_array(self: @T, ref byte_array: ByteArray, base: NonZero); -} - -/// A trait for formatting values into their ASCII string representation in a `ByteArray`. -pub trait FormatAsByteArray { - /// Returns a new `ByteArray` containing the ASCII representation of the value. - /// - /// # Examples - /// - /// ``` - /// use core::to_byte_array::FormatAsByteArray; - /// - /// let num: u32 = 42; - /// let formatted = num.format_as_byte_array(16); - /// assert!(formatted == "2a"); - /// ``` - fn format_as_byte_array(self: @T, base: NonZero) -> ByteArray; -} - -impl FormatAsByteArrayImpl> of FormatAsByteArray { - fn format_as_byte_array(self: @T, base: NonZero) -> ByteArray { - let mut byte_array = ""; - self.append_formatted_to_byte_array(ref byte_array, base); - byte_array - } -} - -impl U8AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u8, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl U16AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u16, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl U32AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u32, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl U64AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u64, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl U128AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u128, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl U256AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array(self: @u256, ref byte_array: ByteArray, base: NonZero) { - append_formatted_to_byte_array(self, ref byte_array, base); - } -} - -impl Felt252AppendFormattedToByteArray of AppendFormattedToByteArray { - fn append_formatted_to_byte_array( - self: @felt252, ref byte_array: ByteArray, base: NonZero, - ) { - let self_as_u256: u256 = (*self).into(); - let base: felt252 = base.into(); - let base: u256 = base.into(); - let base: NonZero = base.try_into().unwrap(); - self_as_u256.append_formatted_to_byte_array(ref byte_array, base); - } -} - -// TODO(yuval): once const generic parameters are supported, move base_nz to be a generic -// parameter. Same for the other bases. -// TODO(yuval): support signed integers. -// -// Formats a type that behaves like uint to its ASCII representation and appends the formatted -// result into the given `ByteArray`. -// `base` must be in the range [2, 36]. Otherwise, this function panics. -fn append_formatted_to_byte_array, +Copy, +DivRem, +TryInto, +Zeroable>( - mut value: @T, ref byte_array: ByteArray, base_nz: NonZero, -) { - let base: T = base_nz.into(); - let base: u8 = base.try_into().unwrap(); - assert(base > 1, 'base must be > 1'); - assert(base <= 36, 'base must be <= 36'); - - let mut reversed_digits = array![]; - - if base <= 10 { - loop { - let (new_value, digit) = DivRem::div_rem(*value, base_nz); - value = @new_value; - let digit_as_u8: u8 = digit.try_into().unwrap(); - reversed_digits.append(digit_as_u8 + '0'); - if (*value).is_zero() { - break; - } - } - } else { - loop { - let (new_value, digit) = DivRem::div_rem(*value, base_nz); - value = @new_value; - let digit_as_u8: u8 = digit.try_into().unwrap(); - reversed_digits.append(get_big_base_digit_representation(:digit_as_u8)); - if (*value).is_zero() { - break; - } - } - } - - let mut span = reversed_digits.span(); - loop { - match span.pop_back() { - Some(byte) => { byte_array.append_byte(*byte); }, - None => { break; }, - } - } -} - -/// Converts a digit (0-9, a-z) to its ASCII representation in a base > 10. -#[inline] -fn get_big_base_digit_representation(digit_as_u8: u8) -> u8 { - if digit_as_u8 < 10 { - digit_as_u8 + '0' - } else { - digit_as_u8 - 10 + 'a' - } -} diff --git a/corelib/src/traits.cairo b/corelib/src/traits.cairo deleted file mode 100644 index 53e7b4b92e..0000000000 --- a/corelib/src/traits.cairo +++ /dev/null @@ -1,1136 +0,0 @@ -//! Core traits for various operations. -//! -//! This module provides a collection of essential traits that define common behavior patterns -//! for Cairo types. -//! -//! # Main Categories -//! -//! ## Memory Management -//! - [`Copy`]: Enables value semantics for types -//! - [`Drop`]: Allows values to be safely discarded -//! - [`Destruct`]: Provides custom cleanup behavior for non-droppable types -//! - [`PanicDestruct`]: Handles destruction during panic scenarios -//! -//! ## Arithmetic Operations -//! - [`Add`], [`Sub`], [`Mul`], [`Div`], [`Rem`]: Standard arithmetic operators (`+`, `-`, `*`, -//! `/`, `%`) -//! - [`DivRem`]: Combined division and remainder operation -//! - [`Neg`]: Unary negation (`-`) -//! -//! ## Bitwise Operations -//! - [`BitAnd`], [`BitOr`], [`BitXor`]: Binary bitwise operations (`&`, `|`, `^`) -//! - [`BitNot`]: Unary bitwise complement (`~`) -//! -//! ## Comparison -//! - [`PartialEq`]: Equality comparison (`==`, `!=`) -//! - [`PartialOrd`]: Ordering comparison (`<`, `<=`, `>`, `>=`) -//! -//! ## Type Conversion -//! - [`Into`]: Infallible type conversion -//! - [`TryInto`]: Fallible type conversion -//! -//! ## Utility Traits -//! - [`Default`]: Creation of default values -//! - [`Felt252DictValue`]: Support for dictionary value types - -use crate::panics::Panic; - -/// A trait for copying values. -/// -/// By default, variables in Cairo have 'move semantics', meaning they are moved when used. -/// However, types implementing `Copy` have 'copy semantics', allowing the value to be -/// duplicated instead of moved. -/// -/// # Deriving -/// -/// This trait can be automatically derived using `#[derive(Copy)]`. Most basic types -/// implement `Copy` by default. -/// -/// # Examples -/// -/// Without `Copy` (move semantics): -/// -/// ``` -/// #[derive(Drop)] -/// struct Point { -/// x: u128, -/// y: u128, -/// } -/// -/// fn main() { -/// let p1 = Point { x: 5, y: 10 }; -/// foo(p1); -/// foo(p1); // error: Variable was previously moved. -/// } -/// -/// fn foo(p: Point) {} -/// ``` -/// -/// With `Copy` (copy semantics): -/// -/// ``` -/// #[derive(Copy, Drop)] -/// struct Point { -/// x: u128, -/// y: u128, -/// } -/// -/// fn main() { -/// let p1 = Point { x: 5, y: 10 }; -/// foo(p1); -/// foo(p1); // works: `p1` is copied when passed to `foo` -/// } -/// -/// fn foo(p: Point) {} -/// ``` -pub trait Copy; - -/// A trait for types that can be safely dropped. -/// -/// Types implementing `Drop` can be automatically discarded when they go out of scope. -/// The drop operation is a no-op - it simply indicates to the compiler that this type -/// can be safely discarded. -/// -/// # Deriving -/// -/// This trait can be automatically derived using `#[derive(Drop)]`. All basic types -/// implement `Drop` by default, except for `Felt252Dict`. -/// -/// # Examples -/// -/// Without `Drop`: -/// -/// ``` -/// struct Point { -/// x: u128, -/// y: u128, -/// } -/// -/// fn foo(p: Point) {} // Error: `p` cannot be dropped -/// ``` -/// -/// With `Drop`: -/// -/// ``` -/// #[derive(Drop)] -/// struct Point { -/// x: u128, -/// y: u128, -/// } -/// -/// fn foo(p: Point) {} // OK: `p` is dropped at the end of the function -/// ``` -pub trait Drop; - -impl SnapshotCopy of Copy<@T>; - -impl SnapshotDrop of Drop<@T>; - -// TODO(spapini): When associated types are supported, support the general trait Add. -/// The addition operator `+`. -/// -/// # Examples -/// -/// `Add`able types: -/// -/// ``` -/// assert!(1_u8 + 2_u8 == 3_u8); -/// ``` -/// -/// Implementing `Add` for a type: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Point { -/// x: u32, -/// y: u32, -/// } -/// -/// impl PointAdd of Add { -/// fn add(lhs: Point, rhs: Point) -> Point { -/// Point { -/// x: lhs.x + rhs.x, -/// y: lhs.y + rhs.y, -/// } -/// } -/// } -/// -/// let p1 = Point { x: 1, y: 0 }; -/// let p2 = Point { x: 2, y: 3 }; -/// let p3 = p1 + p2; -/// assert!(p3 == Point { x: 3, y: 3 }); -/// ``` -pub trait Add { - /// Performs the `+` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(12 + 1 == 13); - /// ``` - fn add(lhs: T, rhs: T) -> T; -} - -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::AddAssign`.", since: "2.7.0", -)] -pub trait AddEq { - fn add_eq(ref self: T, other: T); -} - -// TODO(spapini): When associated types are supported, support the general trait Sub. -/// The subtraction operator `-`. -/// -/// # Examples -/// -/// `Sub`tractable types: -/// -/// ``` -/// assert!(3_u8 - 2_u8 == 1_u8); -/// ``` -/// -/// Implementing `Sub` for a type: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Point { -/// x: u32, -/// y: u32, -/// } -/// -/// impl PointSub of Sub { -/// fn sub(lhs: Point, rhs: Point) -> Point { -/// Point { -/// x: lhs.x - rhs.x, -/// y: lhs.y - rhs.y, -/// } -/// } -/// } -/// -/// let p1 = Point { x: 2, y: 3 }; -/// let p2 = Point { x: 1, y: 0 }; -/// let p3 = p1 - p2; -/// assert!(p3 == Point { x: 1, y: 3 }); -/// ``` -pub trait Sub { - /// Performs the `-` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(12 - 1 == 11); - /// ``` - fn sub(lhs: T, rhs: T) -> T; -} - -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::SubAssign`.", since: "2.7.0", -)] -pub trait SubEq { - fn sub_eq(ref self: T, other: T); -} - -// TODO(spapini): When associated types are supported, support the general trait Mul. -/// The multiplication operator `*`. -/// -/// # Examples -/// -/// `Mul`tipliable types: -/// -/// ``` -/// assert!(3_u8 * 2_u8 == 6_u8); -/// ``` -/// -/// Implementing `Mul` for a type: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Point { -/// x: u32, -/// y: u32, -/// } -/// -/// impl PointMul of Mul { -/// fn mul(lhs: Point, rhs: Point) -> Point { -/// Point { -/// x: lhs.x * rhs.x, -/// y: lhs.y * rhs.y, -/// } -/// } -/// } -/// -/// let p1 = Point { x: 2, y: 3 }; -/// let p2 = Point { x: 1, y: 0 }; -/// let p3 = p1 * p2; -/// assert!(p3 == Point { x: 2, y: 0 }); -/// ``` -pub trait Mul { - /// Performs the `*` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(12 * 2 == 24); - /// ``` - fn mul(lhs: T, rhs: T) -> T; -} - -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::MulAssign`.", since: "2.7.0", -)] -pub trait MulEq { - fn mul_eq(ref self: T, other: T); -} - -// TODO(spapini): When associated types are supported, support the general trait Div. -/// The division operator `/`. -/// -/// Types implementing this trait support the division operation via the `/` operator. -/// -/// # Examples -/// -/// `Div`isible types: -/// -/// ``` -/// assert!(4_u8 / 2_u8 == 2_u8); -/// ``` -/// -/// Implementing `Div` for a type: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Point { -/// x: u32, -/// y: u32, -/// } -/// -/// impl PointDiv of Div { -/// fn div(lhs: Point, rhs: Point) -> Point { -/// Point { -/// x: lhs.x / rhs.x, -/// y: lhs.y / rhs.y, -/// } -/// } -/// } -/// -/// let p1 = Point { x: 2, y: 4 }; -/// let p2 = Point { x: 2, y: 2 }; -/// let p3 = p1 / p2; -/// assert!(p3 == Point { x: 1, y: 2 }); -/// ``` -pub trait Div { - /// Performs the `/` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(12 / 2 == 6); - /// ``` - fn div(lhs: T, rhs: T) -> T; -} - -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::DivAssign`.", since: "2.7.0", -)] -pub trait DivEq { - fn div_eq(ref self: T, other: T); -} - -// TODO(spapini): When associated types are supported, support the general trait Rem. -/// The remainder operator `%`. -/// -/// Types implementing this trait support the remainder operation via the `%` operator. -/// -/// # Examples -/// -/// ``` -/// assert!(3_u8 % 2_u8 == 1_u8); -/// ``` -pub trait Rem { - /// Performs the `%` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(12_u8 % 10_u8 == 2_u8); - /// ``` - fn rem(lhs: T, rhs: T) -> T; -} - -#[deprecated( - feature: "deprecated-op-assign-traits", note: "Use `core::ops::RemAssign`.", since: "2.7.0", -)] -pub trait RemEq { - fn rem_eq(ref self: T, other: T); -} - -/// Performs truncated division and remainder. -/// -/// This trait provides a way to efficiently compute both the quotient and remainder in a single -/// operation. The division truncates towards zero, matching the behavior of the `/` and `%` -/// operators. -/// -/// # Examples -/// -/// ``` -/// assert!(DivRem::div_rem(7_u32, 3) == (2, 1)); -/// ``` -pub trait DivRem { - /// Performs the `/` and the `%` operations, returning both the quotient and remainder. - /// - /// # Examples - /// - /// ``` - /// assert!(DivRem::div_rem(12_u32, 10) == (1, 2)); - /// ``` - fn div_rem(lhs: T, rhs: NonZero) -> (T, T); -} - -/// Trait for comparisons using the equality operator. -/// -/// Implementing this trait for types provides the `==` and `!=` operators for -/// those types. -/// -/// # Derivable -/// -/// This trait can be used with `#[derive]`. When `derive`d on structs, two -/// instances are equal if all fields are equal, and not equal if any fields -/// are not equal. When `derive`d on enums, two instances are equal if they -/// are the same variant and all fields are equal. -/// -/// # Implementing `PartialEq` -/// -/// An example in which two points are equal if their x and y coordinates are equal. -/// -/// ``` -/// #[derive(Copy, Drop)] -/// struct Point { -/// x: u32, -/// y: u32 -/// } -/// -/// impl PointEq of PartialEq { -/// fn eq(lhs: @Point, rhs: @Point) -> bool { -/// lhs.x == rhs.x && lhs.y == rhs.y -/// } -/// } -/// -/// let p1 = Point { x: 1, y: 2 }; -/// let p2 = Point { x: 1, y: 2 }; -/// assert!(p1 == p2); -/// assert!(!(p1 != p2)); -/// ``` -pub trait PartialEq { - /// Returns whether `lhs` and `rhs` equal, and is used by `==`. - /// - /// # Examples - /// - /// ``` - /// assert!(1 == 1); - /// ``` - fn eq(lhs: @T, rhs: @T) -> bool; - - /// Returns whether `lhs` and `rhs` are not equal, and is used by `!=`. - /// - /// # Examples - /// - /// ``` - /// assert!(0 != 1); - /// ``` - fn ne(lhs: @T, rhs: @T) -> bool { - !Self::eq(lhs, rhs) - } -} - -impl PartialEqSnap> of PartialEq<@T> { - fn eq(lhs: @@T, rhs: @@T) -> bool { - PartialEq::::eq(*lhs, *rhs) - } -} - -// TODO(spapini): When associated types are supported, support the general trait BitAnd. -/// The bitwise AND operator `&`. -/// -/// # Examples -/// -/// An implementation of `BitAnd` for a wrapper around `bool`. -/// -/// ``` -/// use core::traits::BitAnd; -/// -/// #[derive(Drop, PartialEq)] -/// struct Scalar { -/// inner: bool, -/// } -/// -/// impl BitAndScalar of BitAnd { -/// fn bitand(lhs: Scalar, rhs: Scalar) -> Scalar { -/// Scalar { inner: lhs.inner & rhs.inner } -/// } -/// } -/// -/// assert!(Scalar { inner: true } & Scalar { inner: true } == Scalar { inner: true }); -/// assert!(Scalar { inner: true } & Scalar { inner: false } == Scalar { inner: false }); -/// assert!(Scalar { inner: false } & Scalar { inner: true } == Scalar { inner: false }); -/// assert!(Scalar { inner: false } & Scalar { inner: false } == Scalar { inner: false }); -/// ``` -pub trait BitAnd { - /// Performs the `&` operation. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(true & false, false); - /// assert_eq!(5_u8 & 1_u8, 1); - /// assert_eq!(true & true, true); - /// assert_eq!(5_u8 & 2_u8, 0); - /// ``` - fn bitand(lhs: T, rhs: T) -> T; -} - -// TODO(spapini): When associated types are supported, support the general trait BitOr. -/// The bitwise OR operator `|`. -/// -/// # Examples -/// -/// An implementation of `BitOr` for a wrapper around `bool`. -/// -/// ``` -/// use core::traits::BitOr; -/// -/// #[derive(Drop, PartialEq)] -/// struct Scalar { -/// inner: bool, -/// } -/// -/// impl BitOrScalar of BitOr { -/// fn bitor(lhs: Scalar, rhs: Scalar) -> Scalar { -/// Scalar { inner: lhs.inner | rhs.inner } -/// } -/// } -/// -/// assert!(Scalar { inner: true } | Scalar { inner: true } == Scalar { inner: true }); -/// assert!(Scalar { inner: true } | Scalar { inner: false } == Scalar { inner: true }); -/// assert!(Scalar { inner: false } | Scalar { inner: true } == Scalar { inner: true }); -/// assert!(Scalar { inner: false } | Scalar { inner: false } == Scalar { inner: false }); -/// ``` -pub trait BitOr { - /// Performs the `|` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(1_u8 | 2_u8 == 3); - /// ``` - fn bitor(lhs: T, rhs: T) -> T; -} - -// TODO(spapini): When associated types are supported, support the general trait BitXor. -/// The bitwise XOR operator `^`. -/// -/// # Examples -/// -/// An implementation of `BitXor` for a wrapper around `bool`. -/// -/// ``` -/// use core::traits::BitXor; -/// -/// #[derive(Drop, PartialEq)] -/// struct Scalar { -/// inner: bool, -/// } -/// -/// impl BitXorScalar of BitXor { -/// fn bitxor(lhs: Scalar, rhs: Scalar) -> Scalar { -/// Scalar { inner: lhs.inner ^ rhs.inner } -/// } -/// } -/// -/// assert!(Scalar { inner: true } ^ Scalar { inner: true } == Scalar { inner: false }); -/// assert!(Scalar { inner: true } ^ Scalar { inner: false } == Scalar { inner: true }); -/// assert!(Scalar { inner: false } ^ Scalar { inner: true } == Scalar { inner: true }); -/// assert!(Scalar { inner: false } ^ Scalar { inner: false } == Scalar { inner: false }); -/// ``` -pub trait BitXor { - /// Performs the `^` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(1_u8 ^ 2_u8 == 3); - /// ``` - fn bitxor(lhs: T, rhs: T) -> T; -} - -/// The bitwise NOT operator `~`. -/// -/// # Examples -/// -/// An implementation of `BitNot` for a wrapper around `u8`. -/// -/// ``` -/// use core::traits::BitNot; -/// -/// #[derive(Drop, PartialEq)] -/// struct Wrapper { -/// u8: u8, -/// } -/// -/// impl BitNotWrapper of BitNot { -/// fn bitnot(a: Wrapper) -> Wrapper { -/// Wrapper { u8: ~a.u8 } -/// } -/// } -/// -/// assert!(~Wrapper { u8: 0 } == Wrapper { u8 : 255 }); -/// assert!(~Wrapper { u8: 1 } == Wrapper { u8 : 254 }); -/// ``` -pub trait BitNot { - /// Performs the `~` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(~1_u8 == 254); - /// ``` - fn bitnot(a: T) -> T; -} - -/// Trait for comparing types that form a [partial -/// order](https://en.wikipedia.org/wiki/Partial_order). -/// -/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and -/// `>=` operators, respectively. -/// -/// PartialOrd is not derivable, but can be implemented manually -/// -/// # Implementing `PartialOrd` -/// -/// Here's how to implement `PartialOrd` for a custom type. This example implements -/// comparison operations for a 2D point where points are compared based on their -/// squared Euclidean distance from the origin (0,0): -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Point { -/// x: u32, -/// y: u32, -/// } -/// -/// impl PointPartialOrd of PartialOrd { -/// fn lt(lhs: Point, rhs: Point) -> bool { -/// let lhs_dist = lhs.x * lhs.x + lhs.y * lhs.y; -/// let rhs_dist = rhs.x * rhs.x + rhs.y * rhs.y; -/// lhs_dist < rhs_dist -/// } -/// } -/// -/// let p1 = Point { x: 1, y: 1 }; // distance = 2 -/// let p2 = Point { x: 2, y: 2 }; // distance = 8 -/// -/// assert!(p1 < p2); -/// assert!(p1 <= p2); -/// assert!(p2 > p1); -/// assert!(p2 >= p1); -/// ``` -/// -/// Note that only the `lt` method needs to be implemented. The other comparison -/// operations (`le`, `gt`, `ge`) are automatically derived from `lt`. However, -/// you can override them for better performance if needed. -pub trait PartialOrd { - /// Tests less than (for `self` and `other`) and is used by the `<` operator. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(1 < 1, false); - /// assert_eq!(1 < 2, true); - /// assert_eq!(2 < 1, false); - /// ``` - fn lt(lhs: T, rhs: T) -> bool; - - /// Tests less than or equal to (for `self` and `other`) and is used by the - /// `<=` operator. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(1 <= 1, true); - /// assert_eq!(1 <= 2, true); - /// assert_eq!(2 <= 1, false); - /// ``` - fn ge(lhs: T, rhs: T) -> bool { - !Self::lt(lhs, rhs) - } - - /// Tests greater than (for `self` and `other`) and is used by the `>` - /// operator. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(1 > 1, false); - /// assert_eq!(1 > 2, false); - /// assert_eq!(2 > 1, true); - /// ``` - fn gt(lhs: T, rhs: T) -> bool { - Self::lt(rhs, lhs) - } - - /// Tests greater than or equal to (for `self` and `other`) and is used by - /// the `>=` operator. - /// - /// # Examples - /// - /// ``` - /// assert_eq!(1 >= 1, true); - /// assert_eq!(1 >= 2, false); - /// assert_eq!(2 >= 1, true); - /// ``` - fn le(lhs: T, rhs: T) -> bool { - Self::ge(rhs, lhs) - } -} - -impl PartialOrdSnap, +Copy> of PartialOrd<@T> { - fn le(lhs: @T, rhs: @T) -> bool { - PartialOrd::::le(*lhs, *rhs) - } - - fn ge(lhs: @T, rhs: @T) -> bool { - PartialOrd::::ge(*lhs, *rhs) - } - - fn lt(lhs: @T, rhs: @T) -> bool { - PartialOrd::::lt(*lhs, *rhs) - } - - fn gt(lhs: @T, rhs: @T) -> bool { - PartialOrd::::gt(*lhs, *rhs) - } -} - -/// A value-to-value conversion that consumes the input value. -/// -/// **Note: This trait must not fail**. If the conversion can fail, use [`TryInto`]. -/// -/// # Generic Implementations -/// -/// - [`Into`] is reflexive, which means that `Into` is implemented -/// -/// # Examples -/// -/// Converting from RGB components to a packed color value: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Color { -/// // Packed as 0x00RRGGBB -/// value: u32, -/// } -/// -/// impl RGBIntoColor of Into<(u8, u8, u8), Color> { -/// fn into(self: (u8, u8, u8)) -> Color { -/// let (r, g, b) = self; -/// let value = (r.into() * 0x10000_u32) + -/// (g.into() * 0x100_u32) + -/// b.into(); -/// Color { value } -/// } -/// } -/// -/// // Convert RGB(255, 128, 0) to 0x00FF8000 -/// let orange: Color = (255_u8, 128_u8, 0_u8).into(); -/// assert!(orange == Color { value: 0x00FF8000_u32 }); -/// ``` -pub trait Into { - /// Converts the input type T into the output type S. - /// - /// # Examples - /// - /// ``` - /// let a: u8 = 1; - /// let b: u16 = a.into(); - /// ``` - #[must_use] - fn into(self: T) -> S; -} - -impl TIntoT of Into { - fn into(self: T) -> T { - self - } -} - -/// Simple and safe type conversions that may fail in a controlled way under -/// some circumstances. -/// -/// This is useful when you are doing a type conversion that may trivially succeed but may also need -/// special handling. For example, there is no way to convert an [`i64`] into an [`i32`] using the -/// [`Into`] trait, because an [`i64`] may contain a value that an [`i32`] cannot represent and so -/// the conversion would lose data. This might be handled by truncating the [`i64`] to an [`i32`] -/// or by simply returning [`Bounded::::MAX`], or by some other method. The [`Into`] trait -/// is intended for perfect conversions, so the `TryInto` trait informs the programmer when a type -/// conversion could go bad and lets them decide how to handle it. -/// -/// # Generic Implementations -/// -/// - [`TryInto`] is reflexive, which means that `TryInto` is implemented -/// - [`TryInto`] is implemented for all types that implement [`Into`] -/// -/// # Examples -/// -/// Converting chess coordinates (like 'e4') into a validated position: -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// struct Position { -/// file: u8, // Column a-h (0-7) -/// rank: u8, // Row 1-8 (0-7) -/// } -/// -/// impl TupleTryIntoPosition of TryInto<(u8, u8), Position> { -/// fn try_into(self: (u8, u8)) -> Option { -/// let (file_char, rank) = self; -/// -/// // Validate rank is between 1 and 8 -/// if rank < 1 || rank > 8 { -/// return None; -/// } -/// -/// // Validate and convert file character (a-h) to number (0-7) -/// if file_char < 'a' || file_char > 'h' { -/// return None; -/// } -/// let file = file_char - 'a'; -/// -/// Some(Position { -/// file, -/// rank: rank - 1 // Convert 1-8 (chess notation) to 0-7 (internal index) -/// }) -/// } -/// } -/// -/// // Valid positions -/// let e4 = ('e', 4).try_into(); -/// assert!(e4 == Some(Position { file: 4, rank: 3 })); -/// -/// // Invalid positions -/// let invalid_file = ('x', 4).try_into(); -/// let invalid_rank = ('a', 9).try_into(); -/// assert!(invalid_file == None); -/// assert!(invalid_rank == None); -/// ``` -pub trait TryInto { - /// Attempts to convert the input type T into the output type S. - /// In the event of a conversion error, returns [`None`]. - /// - /// # Examples - /// - /// ``` - /// let a: Option = 1_u16.try_into(); - /// assert!(a == Some(1)); - /// let b: Option = 256_u16.try_into(); - /// assert!(b == None); - /// ``` - fn try_into(self: T) -> Option; -} - -impl TryIntoFromInto> of TryInto { - fn try_into(self: From) -> Option { - Some(self.into()) - } -} - -/// The unary negation operator `-`. -/// -/// # Examples -/// -/// An implementation of `Neg` for `Sign`, which allows the use of `-` to -/// negate its value. -/// -/// ``` -/// #[derive(Copy, Drop, PartialEq)] -/// enum Sign { -/// Negative, -/// Zero, -/// Positive, -/// } -/// -/// impl SignNeg of Neg { -/// fn neg(a: Sign) -> Sign { -/// match a { -/// Sign::Negative => Sign::Positive, -/// Sign::Zero => Sign::Zero, -/// Sign::Positive => Sign::Negative, -/// } -/// } -/// } -/// -/// // A negative positive is a negative -/// assert!(-Sign::Positive == Sign::Negative); -/// // A double negative is a positive -/// assert!(-Sign::Negative == Sign::Positive); -/// // Zero is its own negation -/// assert!(-Sign::Zero == Sign::Zero); -/// ``` -pub trait Neg { - /// Performs the unary `-` operation. - /// - /// # Examples - /// - /// ``` - /// let x: i8 = 1; - /// assert!(-x == -1); - /// ``` - fn neg(a: T) -> T; -} - -/// The unary logical negation operator `!`. -/// -/// # Examples -/// -/// An implementation of `Not` for `Answer`, which enables the use of `!` to -/// invert its value. -/// -/// ``` -/// #[derive(Drop, PartialEq)] -/// enum Answer { -/// Yes, -/// No, -/// } -/// -/// impl AnswerNot of Not { -/// fn not(a: Answer) -> Answer { -/// match a { -/// Answer::Yes => Answer::No, -/// Answer::No => Answer::Yes, -/// } -/// } -/// } -/// -/// assert!(!Answer::Yes == Answer::No); -/// assert!(!Answer::No == Answer::Yes); -/// ``` -pub trait Not { - /// Performs the unary `!` operation. - /// - /// # Examples - /// - /// ``` - /// assert!(!true == false); - /// assert!(!false == true); - /// ``` - fn not(a: T) -> T; -} - -// The following two traits are for implementing the `[]` operator. Only one should be implemented -// for each type. Both are not consuming of `self`, the first gets a snapshot of the object and -// the second gets a reference. -#[deprecated( - feature: "deprecated-index-traits", note: "Use `core::ops::index::IndexView`.", since: "2.7.0", -)] -pub trait IndexView { - fn index(self: @C, index: I) -> V; -} - -#[deprecated( - feature: "deprecated-index-traits", note: "Use `core::ops::index::Index`.", since: "2.7.0", -)] -pub trait Index { - fn index(ref self: C, index: I) -> V; -} - -/// A trait that allows for custom destruction behavior of a type. -/// -/// In Cairo, values must be explicitly handled - they cannot be silently dropped. -/// Types can only go out of scope in two ways: -/// 1. Implement `Drop` - for types that can be discarded trivially -/// 2. Implement `Destruct` - for types that need cleanup when destroyed. Typically, any type that -/// contains -/// a `Felt252Dict` must implement `Destruct`, as the `Felt252Dict` needs to be "squashed" when -/// going -/// out of scope to ensure a program is sound. -/// -/// Generally, `Destruct` does not need to be implemented manually. It can be derived from the -/// `Drop` and `Destruct` implementations of the type's fields. -/// -/// # Examples -/// -/// Here's a simple type that wraps a `Felt252Dict` and needs to be destructed: -/// -/// ``` -/// use core::dict::Felt252Dict; -/// -/// // A struct containing a Felt252Dict must implement Destruct -/// #[derive(Destruct, Default)] -/// struct ResourceManager { -/// resources: Felt252Dict, -/// count: u32, -/// } -/// -/// #[generate_trait] -/// impl ResourceManagerImpl of ResourceManagerTrait{ -/// fn add_resource(ref self: ResourceManager, resource_id: felt252, amount: u32){ -/// assert!(self.resources.get(resource_id) == 0, "Resource already exists"); -/// self.resources.insert(resource_id, amount); -/// self.count += amount; -/// } -/// } -/// -/// let mut manager = Default::default(); -/// -/// // Add some resources -/// manager.add_resource(1, 100); -/// -/// // When manager goes out of scope here, Destruct is automatically called, -/// // which ensures the dictionary is properly squashed -/// ``` -pub trait Destruct { - fn destruct(self: T) nopanic; -} - -// TODO(spapini): Remove this, it can lead to multiple impls and unwanted Destruct implementation. -impl DestructFromDrop> of Destruct { - #[inline] - fn destruct(self: T) nopanic {} -} - -/// A trait that allows for destruction of a value in case of a panic. -/// -/// This trait is automatically implemented from the `Destruct` implementation for a type. -pub trait PanicDestruct { - fn panic_destruct(self: T, ref panic: Panic) nopanic; -} - -pub(crate) impl PanicDestructForDestruct> of PanicDestruct { - #[inline] - fn panic_destruct(self: T, ref panic: Panic) nopanic { - Destruct::destruct(self); - } -} - -/// A trait for giving a type a useful default value. -/// -/// Cairo implements `Default` for various primitives types. -/// -/// # Derivable -/// -/// This trait can be used with `#[derive]` if all of the type's fields implement -/// `Default`. When `derive`d, it will use the default value for each field's type. -/// -/// ## `enum`s -/// -/// When using `#[derive(Default)]` on an `enum`, you need to choose which unit variant will be -/// default. You do this by placing the `#[default]` attribute on the variant. -/// -/// ``` -/// #[derive(Default)] -/// enum Kind { -/// #[default] -/// A, -/// B, -/// C, -/// } -/// ``` -/// -/// You can even use the `#[default]` attribute even on non-unit variants, provided that the -/// associated type implements `Default`. -/// -/// # How can I implement `Default`? -/// -/// Provide an implementation for the `default()` method that returns the value of -/// your type that should be the default: -/// -/// ``` -/// #[derive(Copy, Drop)] -/// enum Kind { -/// A, -/// B, -/// C, -/// } -/// -/// impl DefaultKind of Default { -/// fn default() -> Kind { Kind::A } -/// } -/// ``` -/// -/// # Examples -/// -/// #[derive(Drop, Default, PartialEq)] -/// struct SomeOptions { -/// foo: i32, -/// bar: u32, -/// } -/// -/// assert!(Default::default() == SomeOptions { foo: 0, bar: 0 }); -pub trait Default { - /// Returns the "default value" for a type. - /// - /// Default values are often some kind of initial value, identity value, or anything else that - /// may make sense as a default. - /// - /// # Examples - /// - /// ``` - /// let i: i8 = Default::default(); - /// let (x, y): (Option, u64) = Default::default(); - /// let (a, b, (c, d)): (i32, u32, (bool, bool)) = Default::default(); - /// ``` - #[must_use] - fn default() -> T; -} - -impl SnapshotDefault, +Drop> of Default<@T> { - #[inline] - fn default() -> @T { - @Default::default() - } -} - -/// A trait that must be implemented for any type that will be stored as a value in a `Felt252Dict`. -/// -/// When working with dictionaries in Cairo, we need a way to represent "empty" or "uninitialized" -/// slots. This trait provides a zero-like default value that is returned when accessing a key -/// that hasn't been explicitly set. -/// -/// # Why is this needed? -/// -/// The `Felt252Dict` implementation needs to handle cases where a key hasn't been assigned a value -/// yet. -/// Instead of using `Option` or similar constructs, it uses a zero-like value specific to each -/// type. -/// -/// This trait is __only__ implemented for primitive scalar types and `Nullable`. It cannot be -/// implemented manually. -/// Instead, if you want to use a custom type as a value in a dictionary, you can wrap your type in -/// a [`Nullable`], which implements `Felt252DictValue` for any wrapped type. -/// -/// # Examples -/// -/// ``` -/// use core::dict::Felt252Dict; -/// -/// #[derive(Copy, Drop, Default)] -/// struct Counter { -/// value: u32, -/// } -/// -/// // u8 already implements Felt252DictValue -/// let mut dict: Felt252Dict = Default::default(); -/// assert!(dict.get(123) == 0); -/// -/// // Counter is wrapped in a Nullable, as it doesn't implement Felt252DictValue -/// let mut counters: Felt252Dict> = Default::default(); -/// -/// // If the key is not set, `deref` would panic. `deref_or` returns the default value. -/// let maybe_counter: Nullable = counters.get(123); -/// assert!(maybe_counter.deref_or(Default::default()).value == 0); -/// ``` -pub trait Felt252DictValue { - /// Returns the default value for this type when used in a `Felt252Dict`. - /// This value should be logically equivalent to zero or an "empty" state. - #[must_use] - fn zero_default() -> T nopanic; -} - diff --git a/corelib/src/tuple.cairo b/corelib/src/tuple.cairo deleted file mode 100644 index 5244b20844..0000000000 --- a/corelib/src/tuple.cairo +++ /dev/null @@ -1,861 +0,0 @@ -use crate::metaprogramming::{IsTuple, SnapRemove, TupleExtendFront, TupleSnapForward, TupleSplit}; -impl IsTupleTupleSize0 of IsTuple<()>; -impl IsTupleTupleSize1 of IsTuple<(E0,)>; -impl IsTupleTupleSize2 of IsTuple<(E0, E1)>; -impl IsTupleTupleSize3 of IsTuple<(E0, E1, E2)>; -impl IsTupleTupleSize4 of IsTuple<(E0, E1, E2, E3)>; -impl IsTupleTupleSize5 of IsTuple<(E0, E1, E2, E3, E4)>; -impl IsTupleTupleSize6 of IsTuple<(E0, E1, E2, E3, E4, E5)>; -impl IsTupleTupleSize7 of IsTuple<(E0, E1, E2, E3, E4, E5, E6)>; -impl IsTupleTupleSize8 of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7)>; -impl IsTupleTupleSize9< - E0, E1, E2, E3, E4, E5, E6, E7, E8, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8)>; -impl IsTupleTupleSize10< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9)>; -impl IsTupleTupleSize11< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)>; -impl IsTupleTupleSize12< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11)>; -impl IsTupleTupleSize13< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12)>; -impl IsTupleTupleSize14< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13)>; -impl IsTupleTupleSize15< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14)>; -impl IsTupleTupleSize16< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, -> of IsTuple<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15)>; - -impl TupleSplitTupleSize1 of TupleSplit<(E0,)> { - type Head = E0; - type Rest = (); - fn split_head(self: (E0,)) -> (E0, ()) nopanic { - let (e0,) = self; - (e0, ()) - } - fn reconstruct(head: E0, rest: ()) -> (E0,) nopanic { - (head,) - } -} - -impl TupleSplitTupleSize2 of TupleSplit<(E0, E1)> { - type Head = E0; - type Rest = (E1,); - fn split_head(self: (E0, E1)) -> (E0, (E1,)) nopanic { - let (e0, e1) = self; - (e0, (e1,)) - } - fn reconstruct(head: E0, rest: (E1,)) -> (E0, E1) nopanic { - let (e1,) = rest; - (head, e1) - } -} - -impl TupleSplitTupleSize3 of TupleSplit<(E0, E1, E2)> { - type Head = E0; - type Rest = (E1, E2); - fn split_head(self: (E0, E1, E2)) -> (E0, (E1, E2)) nopanic { - let (e0, e1, e2) = self; - (e0, (e1, e2)) - } - fn reconstruct(head: E0, rest: (E1, E2)) -> (E0, E1, E2) nopanic { - let (e1, e2) = rest; - (head, e1, e2) - } -} - -impl TupleSplitTupleSize4 of TupleSplit<(E0, E1, E2, E3)> { - type Head = E0; - type Rest = (E1, E2, E3); - fn split_head(self: (E0, E1, E2, E3)) -> (E0, (E1, E2, E3)) nopanic { - let (e0, e1, e2, e3) = self; - (e0, (e1, e2, e3)) - } - fn reconstruct(head: E0, rest: (E1, E2, E3)) -> (E0, E1, E2, E3) nopanic { - let (e1, e2, e3) = rest; - (head, e1, e2, e3) - } -} - -impl TupleSplitTupleSize5 of TupleSplit<(E0, E1, E2, E3, E4)> { - type Head = E0; - type Rest = (E1, E2, E3, E4); - fn split_head(self: (E0, E1, E2, E3, E4)) -> (E0, (E1, E2, E3, E4)) nopanic { - let (e0, e1, e2, e3, e4) = self; - (e0, (e1, e2, e3, e4)) - } - fn reconstruct(head: E0, rest: (E1, E2, E3, E4)) -> (E0, E1, E2, E3, E4) nopanic { - let (e1, e2, e3, e4) = rest; - (head, e1, e2, e3, e4) - } -} - -impl TupleSplitTupleSize6 of TupleSplit<(E0, E1, E2, E3, E4, E5)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5); - fn split_head(self: (E0, E1, E2, E3, E4, E5)) -> (E0, (E1, E2, E3, E4, E5)) nopanic { - let (e0, e1, e2, e3, e4, e5) = self; - (e0, (e1, e2, e3, e4, e5)) - } - fn reconstruct(head: E0, rest: (E1, E2, E3, E4, E5)) -> (E0, E1, E2, E3, E4, E5) nopanic { - let (e1, e2, e3, e4, e5) = rest; - (head, e1, e2, e3, e4, e5) - } -} - -impl TupleSplitTupleSize7 of TupleSplit<(E0, E1, E2, E3, E4, E5, E6)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6); - fn split_head(self: (E0, E1, E2, E3, E4, E5, E6)) -> (E0, (E1, E2, E3, E4, E5, E6)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6) = self; - (e0, (e1, e2, e3, e4, e5, e6)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6), - ) -> (E0, E1, E2, E3, E4, E5, E6) nopanic { - let (e1, e2, e3, e4, e5, e6) = rest; - (head, e1, e2, e3, e4, e5, e6) - } -} - -impl TupleSplitTupleSize8< - E0, E1, E2, E3, E4, E5, E6, E7, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7) nopanic { - let (e1, e2, e3, e4, e5, e6, e7) = rest; - (head, e1, e2, e3, e4, e5, e6, e7) - } -} - -impl TupleSplitTupleSize9< - E0, E1, E2, E3, E4, E5, E6, E7, E8, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8) - } -} - -impl TupleSplitTupleSize10< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9) - } -} - -impl TupleSplitTupleSize11< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) - } -} - -impl TupleSplitTupleSize12< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) - } -} - -impl TupleSplitTupleSize13< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) - } -} - -impl TupleSplitTupleSize14< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) - } -} - -impl TupleSplitTupleSize15< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) - } -} - -impl TupleSplitTupleSize16< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, -> of TupleSplit<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15)> { - type Head = E0; - type Rest = (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15); - fn split_head( - self: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15), - ) -> (E0, (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15)) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15) = self; - (e0, (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15)) - } - fn reconstruct( - head: E0, rest: (E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15), - ) -> (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15) nopanic { - let (e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15) = rest; - (head, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15) - } -} - -impl TupleExtendFrontTupleSize0 of TupleExtendFront<(), E> { - type Result = (E,); - fn extend_front(value: (), element: E) -> (E,) nopanic { - (element,) - } -} - -impl TupleExtendFrontTupleSize1 of TupleExtendFront<(E0,), E> { - type Result = (E, E0); - fn extend_front(value: (E0,), element: E) -> (E, E0) nopanic { - let (e0,) = value; - (element, e0) - } -} - -impl TupleExtendFrontTupleSize2 of TupleExtendFront<(E0, E1), E> { - type Result = (E, E0, E1); - fn extend_front(value: (E0, E1), element: E) -> (E, E0, E1) nopanic { - let (e0, e1) = value; - (element, e0, e1) - } -} - -impl TupleExtendFrontTupleSize3 of TupleExtendFront<(E0, E1, E2), E> { - type Result = (E, E0, E1, E2); - fn extend_front(value: (E0, E1, E2), element: E) -> (E, E0, E1, E2) nopanic { - let (e0, e1, e2) = value; - (element, e0, e1, e2) - } -} - -impl TupleExtendFrontTupleSize4 of TupleExtendFront<(E0, E1, E2, E3), E> { - type Result = (E, E0, E1, E2, E3); - fn extend_front(value: (E0, E1, E2, E3), element: E) -> (E, E0, E1, E2, E3) nopanic { - let (e0, e1, e2, e3) = value; - (element, e0, e1, e2, e3) - } -} - -impl TupleExtendFrontTupleSize5< - E0, E1, E2, E3, E4, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4), E> { - type Result = (E, E0, E1, E2, E3, E4); - fn extend_front(value: (E0, E1, E2, E3, E4), element: E) -> (E, E0, E1, E2, E3, E4) nopanic { - let (e0, e1, e2, e3, e4) = value; - (element, e0, e1, e2, e3, e4) - } -} - -impl TupleExtendFrontTupleSize6< - E0, E1, E2, E3, E4, E5, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5), E> { - type Result = (E, E0, E1, E2, E3, E4, E5); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5) nopanic { - let (e0, e1, e2, e3, e4, e5) = value; - (element, e0, e1, e2, e3, e4, e5) - } -} - -impl TupleExtendFrontTupleSize7< - E0, E1, E2, E3, E4, E5, E6, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6) nopanic { - let (e0, e1, e2, e3, e4, e5, e6) = value; - (element, e0, e1, e2, e3, e4, e5, e6) - } -} - -impl TupleExtendFrontTupleSize8< - E0, E1, E2, E3, E4, E5, E6, E7, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7) - } -} - -impl TupleExtendFrontTupleSize9< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8) - } -} - -impl TupleExtendFrontTupleSize10< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) - } -} - -impl TupleExtendFrontTupleSize11< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) - } -} - -impl TupleExtendFrontTupleSize12< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) - } -} - -impl TupleExtendFrontTupleSize13< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) - } -} - -impl TupleExtendFrontTupleSize14< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) - } -} - -impl TupleExtendFrontTupleSize15< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E, -> of TupleExtendFront<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14), E> { - type Result = (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14); - fn extend_front( - value: (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14), element: E, - ) -> (E, E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) = value; - (element, e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) - } -} - -impl TupleSnapForwardTupleSize0 of TupleSnapForward<()> { - type SnapForward = (); - fn snap_forward(self: @()) -> () nopanic { - () - } -} - -impl TupleSnapForwardTupleSize1 of TupleSnapForward<(E0,)> { - type SnapForward = (@E0,); - fn snap_forward(self: @(E0,)) -> (@E0,) nopanic { - let (e0,) = self; - (e0,) - } -} - -impl TupleSnapForwardTupleSize2 of TupleSnapForward<(E0, E1)> { - type SnapForward = (@E0, @E1); - fn snap_forward(self: @(E0, E1)) -> (@E0, @E1) nopanic { - let (e0, e1) = self; - (e0, e1) - } -} - -impl TupleSnapForwardTupleSize3 of TupleSnapForward<(E0, E1, E2)> { - type SnapForward = (@E0, @E1, @E2); - fn snap_forward(self: @(E0, E1, E2)) -> (@E0, @E1, @E2) nopanic { - let (e0, e1, e2) = self; - (e0, e1, e2) - } -} - -impl TupleSnapForwardTupleSize4 of TupleSnapForward<(E0, E1, E2, E3)> { - type SnapForward = (@E0, @E1, @E2, @E3); - fn snap_forward(self: @(E0, E1, E2, E3)) -> (@E0, @E1, @E2, @E3) nopanic { - let (e0, e1, e2, e3) = self; - (e0, e1, e2, e3) - } -} - -impl TupleSnapForwardTupleSize5 of TupleSnapForward<(E0, E1, E2, E3, E4)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4); - fn snap_forward(self: @(E0, E1, E2, E3, E4)) -> (@E0, @E1, @E2, @E3, @E4) nopanic { - let (e0, e1, e2, e3, e4) = self; - (e0, e1, e2, e3, e4) - } -} - -impl TupleSnapForwardTupleSize6< - E0, E1, E2, E3, E4, E5, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5); - fn snap_forward(self: @(E0, E1, E2, E3, E4, E5)) -> (@E0, @E1, @E2, @E3, @E4, @E5) nopanic { - let (e0, e1, e2, e3, e4, e5) = self; - (e0, e1, e2, e3, e4, e5) - } -} - -impl TupleSnapForwardTupleSize7< - E0, E1, E2, E3, E4, E5, E6, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6) nopanic { - let (e0, e1, e2, e3, e4, e5, e6) = self; - (e0, e1, e2, e3, e4, e5, e6) - } -} - -impl TupleSnapForwardTupleSize8< - E0, E1, E2, E3, E4, E5, E6, E7, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7) = self; - (e0, e1, e2, e3, e4, e5, e6, e7) - } -} - -impl TupleSnapForwardTupleSize9< - E0, E1, E2, E3, E4, E5, E6, E7, E8, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8) - } -} - -impl TupleSnapForwardTupleSize10< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9) - } -} - -impl TupleSnapForwardTupleSize11< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10) - } -} - -impl TupleSnapForwardTupleSize12< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11) - } -} - -impl TupleSnapForwardTupleSize13< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12) - } -} - -impl TupleSnapForwardTupleSize14< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13)> { - type SnapForward = (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13) - } -} - -impl TupleSnapForwardTupleSize15< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14)> { - type SnapForward = ( - @E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13, @E14, - ); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14), - ) -> (@E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13, @E14) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14) - } -} - -impl TupleSnapForwardTupleSize16< - E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, -> of TupleSnapForward<(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15)> { - type SnapForward = ( - @E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13, @E14, @E15, - ); - fn snap_forward( - self: @(E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15), - ) -> ( - @E0, @E1, @E2, @E3, @E4, @E5, @E6, @E7, @E8, @E9, @E10, @E11, @E12, @E13, @E14, @E15, - ) nopanic { - let (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15) = self; - (e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15) - } -} - -impl SnapRemoveTupleBase of SnapRemove<()> { - type Result = (); -} - -impl SnapRemoveTupleNext< - T, - +IsTuple, - impl TS: TupleSplit, - impl HeadNoSnap: SnapRemove, - impl RestNoSnap: SnapRemove, - impl TEF: TupleExtendFront, -> of SnapRemove { - type Result = TEF::Result; -} - - -pub(crate) impl TupleSize0Copy of Copy<()>; -pub(crate) impl TupleSize0Drop of Drop<()>; -impl TupleNextDrop< - T, - impl TH: crate::metaprogramming::TupleSplit, - +crate::metaprogramming::IsTuple, - +Drop, - +Drop, -> of Drop; -impl TupleNextCopy< - T, - impl TH: crate::metaprogramming::TupleSplit, - +crate::metaprogramming::IsTuple, - +Copy, - +Copy, -> of Copy; - -pub impl TuplePartialEq< - T, - impl TSF: crate::metaprogramming::TupleSnapForward, - +TuplePartialEqHelper, -> of PartialEq { - fn eq(lhs: @T, rhs: @T) -> bool { - TuplePartialEqHelper::eq(TSF::snap_forward(lhs), TSF::snap_forward(rhs)) - } - fn ne(lhs: @T, rhs: @T) -> bool { - TuplePartialEqHelper::ne(TSF::snap_forward(lhs), TSF::snap_forward(rhs)) - } -} - -// A trait helper for implementing `PartialEq` for tuples. -pub(crate) trait TuplePartialEqHelper { - fn eq(lhs: T, rhs: T) -> bool; - fn ne(lhs: T, rhs: T) -> bool; -} - -impl TuplePartialEqHelperByPartialEq> of TuplePartialEqHelper<@T> { - fn eq(lhs: @T, rhs: @T) -> bool { - lhs == rhs - } - fn ne(lhs: @T, rhs: @T) -> bool { - lhs != rhs - } -} - -impl TuplePartialEqHelperBaseTuple of TuplePartialEqHelper<()> { - fn eq(lhs: (), rhs: ()) -> bool { - true - } - fn ne(lhs: (), rhs: ()) -> bool { - false - } -} - - -impl TuplePartialEqHelperNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - +TuplePartialEqHelper, - +TuplePartialEqHelper, - +Drop, -> of TuplePartialEqHelper { - fn eq(lhs: T, rhs: T) -> bool { - let (lhs_head, lhs_rest) = TS::split_head(lhs); - let (rhs_head, rhs_rest) = TS::split_head(rhs); - TuplePartialEqHelper::::eq(lhs_head, rhs_head) - && TuplePartialEqHelper::::eq(lhs_rest, rhs_rest) - } - fn ne(lhs: T, rhs: T) -> bool { - let (lhs_head, lhs_rest) = TS::split_head(lhs); - let (rhs_head, rhs_rest) = TS::split_head(rhs); - TuplePartialEqHelper::::ne(lhs_head, rhs_head) - || TuplePartialEqHelper::::ne(lhs_rest, rhs_rest) - } -} - -impl DefaultTupleBase of Default<()> { - fn default() -> () { - () - } -} - - -pub(crate) impl DefaultNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - +Default, - +Default, - +Drop, -> of Default { - fn default() -> T { - TS::reconstruct(Default::default(), Default::default()) - } -} - - -impl TupleNextDestruct< - T, - impl TH: crate::metaprogramming::TupleSplit, - +Destruct, - +Destruct, - -Drop, -> of Destruct { - fn destruct(self: T) nopanic { - let (_head, _rest) = TH::split_head(self); - } -} - - -// Implementation of `Serde` for tuple style structs. -pub(crate) impl SerdeTuple< - T, - impl TSF: crate::metaprogramming::TupleSnapForward, - impl Serialize: SerializeTuple, - impl Deserialize: DeserializeTuple, -> of Serde { - fn serialize(self: @T, ref output: Array) { - Serialize::serialize(TSF::snap_forward(self), ref output); - } - - fn deserialize(ref serialized: Span) -> Option { - Deserialize::deserialize(ref serialized) - } -} - -// Helper trait for serializing tuple style structs. -trait SerializeTuple { - fn serialize(value: T, ref output: Array); -} - -// Implementation of `SerializeTuple` for snapshots of types with `Serde` implementation. -impl SerdeBasedSerializeTuple> of SerializeTuple<@T> { - fn serialize(value: @T, ref output: Array) { - Serde::::serialize(value, ref output); - } -} - -// Helper trait for deserializing tuple style structs. -trait DeserializeTuple { - fn deserialize(ref serialized: Span) -> Option; -} - -// Base implementation of `SerializeTuple` for tuples. -impl SerializeTupleBaseTuple of SerializeTuple<()> { - fn serialize(value: (), ref output: Array) {} -} - -// Base implementation of `DeserializeTuple` for tuples. -impl DeserializeTupleBaseTuple of DeserializeTuple<()> { - fn deserialize(ref serialized: Span) -> Option<()> { - Some(()) - } -} - -// Base implementation of `SerializeTuple` for fixed sized arrays. -impl SerializeTupleBaseFixedSizedArray of SerializeTuple<[@T; 0]> { - fn serialize(value: [@T; 0], ref output: Array) {} -} - -// Base implementation of `DeserializeTuple` for fixed sized arrays. -impl DeserializeTupleBaseFixedSizedArray of DeserializeTuple<[T; 0]> { - fn deserialize(ref serialized: Span) -> Option<[T; 0]> { - Some([]) - } -} - -// Recursive implementation of `SerializeTuple` for tuple style structs. -impl SerializeTupleNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - +SerializeTuple, - +SerializeTuple, - +Drop, -> of SerializeTuple { - fn serialize(value: T, ref output: Array) { - let (head, rest) = TS::split_head(value); - SerializeTuple::::serialize(head, ref output); - SerializeTuple::::serialize(rest, ref output); - } -} - -// Recursive implementation of `DeserializeTuple` for tuple style structs. -impl DeserializeTupleNext< - T, - impl TS: crate::metaprogramming::TupleSplit, - +Serde, - +DeserializeTuple, - +Drop, -> of DeserializeTuple { - fn deserialize(ref serialized: Span) -> Option { - let head = Serde::::deserialize(ref serialized)?; - let rest = DeserializeTuple::::deserialize(ref serialized)?; - Some(TS::reconstruct(head, rest)) - } -} diff --git a/corelib/src/zeroable.cairo b/corelib/src/zeroable.cairo deleted file mode 100644 index 171cb714f2..0000000000 --- a/corelib/src/zeroable.cairo +++ /dev/null @@ -1,154 +0,0 @@ -//! Types and traits for handling non-zero values and zero checking operations. -//! -//! This module provides the [`NonZero`] wrapper type which guarantees that a value is never -//! zero. -//! The [`Zeroable`] trait is meant for internal use only. The public-facing equivalent is the -//! [`Zero`] trait. -//! -//! [`Zero`]: core::num::traits::zero::Zero - -/// A trait for types that have a concept of zero and can be compared to zero. -/// -/// This trait is useful for numeric types or any type that has an additive identity element. -pub(crate) trait Zeroable { - /// Returns the additive identity element of `self`, 0. - /// - /// This method should return a value that, when added to any other value of type `T`, - /// does not change that value. - /// - /// # Examples - /// - /// ``` - /// assert!(Zeroable::::zero() == 0); - /// ``` - #[must_use] - fn zero() -> T; - - /// Returns whether `self` is equal to 0, the additive identity element. - /// - /// # Examples - /// - /// ``` - /// assert!(0.is_zero()); - /// assert!(!5.is_zero()); - /// ``` - #[must_use] - fn is_zero(self: T) -> bool; - - /// Returns whether `self` is not equal to 0, the additive identity element. - /// - /// This method is the logical inverse of `is_zero()`. - /// - /// # Examples - /// - /// ``` - /// assert!(5.is_non_zero()); - /// assert!(!0.is_non_zero()); - /// ``` - #[must_use] - fn is_non_zero(self: T) -> bool; -} - -/// Provides an implementation of the `Zeroable` trait for types that implement `Zero`. -pub(crate) mod zero_based { - /// Implements `Zeroable` for any type that implements `Zero`, `Drop`, and `Copy`. - pub(crate) impl ZeroableImpl< - T, impl ZeroImpl: crate::num::traits::Zero, +Drop, +Copy, - > of super::Zeroable { - fn zero() -> T { - ZeroImpl::zero() - } - - #[inline] - fn is_zero(self: T) -> bool { - ZeroImpl::is_zero(@self) - } - - #[inline] - fn is_non_zero(self: T) -> bool { - ZeroImpl::is_non_zero(@self) - } - } -} - -pub(crate) impl Felt252Zeroable = zero_based::ZeroableImpl; - - -/// A wrapper type for non-zero values of type T. -/// -/// This type guarantees that the wrapped value is never zero. -pub extern type NonZero; - -impl NonZeroCopy of Copy>; -impl NonZeroDrop of Drop>; - -pub(crate) mod non_zero_neg { - pub impl Impl, +TryInto>> of Neg> { - fn neg(a: NonZero) -> NonZero { - // TODO(orizi): Optimize using bounded integers. - let value: T = a.into(); - let negated: T = -value; - negated.try_into().unwrap() - } - } -} - -impl NonZeroI8Neg = non_zero_neg::Impl; -impl NonZeroI16Neg = non_zero_neg::Impl; -impl NonZeroI32Neg = non_zero_neg::Impl; -impl NonZeroI64Neg = non_zero_neg::Impl; -impl NonZeroI128Neg = non_zero_neg::Impl; -impl NonZeroFelt252Neg = non_zero_neg::Impl; - -/// Represents the result of checking whether a value is zero. -pub(crate) enum IsZeroResult { - /// Indicates that the value is zero. - Zero, - /// Indicates that the value is non-zero, wrapping it in a `NonZero`. - NonZero: NonZero, -} - -/// Unwraps a `NonZero` to retrieve the underlying value of type `T`. -extern const fn unwrap_non_zero(a: NonZero) -> T nopanic; - -pub(crate) impl NonZeroIntoImpl of Into, T> { - const fn into(self: NonZero) -> T nopanic { - unwrap_non_zero(self) - } -} - -impl IsZeroResultIntoBool> of Into, bool> { - fn into(self: IsZeroResult) -> bool { - match self { - IsZeroResult::Zero => true, - IsZeroResult::NonZero(_) => false, - } - } -} - -impl NonZeroPartialEq, +Copy, +Drop> of PartialEq> { - #[inline] - fn eq(lhs: @NonZero, rhs: @NonZero) -> bool { - let lhs: T = (*lhs).into(); - let rhs: T = (*rhs).into(); - lhs == rhs - } - - #[inline] - fn ne(lhs: @NonZero, rhs: @NonZero) -> bool { - let lhs: T = (*lhs).into(); - let rhs: T = (*rhs).into(); - lhs != rhs - } -} - -impl NonZeroSerde, +Copy, +Drop, +TryInto>> of Serde> { - fn serialize(self: @NonZero, ref output: Array) { - let value: T = (*self).into(); - value.serialize(ref output); - } - - fn deserialize(ref serialized: Span) -> Option> { - Serde::::deserialize(ref serialized)?.try_into() - } -} diff --git a/scripts/check-corelib-version.sh b/scripts/check-corelib-version.sh index fcc9384477..b018bd60c0 100755 --- a/scripts/check-corelib-version.sh +++ b/scripts/check-corelib-version.sh @@ -5,8 +5,7 @@ _result=$(grep "version = \"$1\"" corelib/Scarb.toml) if [ $? -ne 0 ]; then - echo "corelib version mismatch, please run both:" - echo "- make pull-external-projects" - echo "- make deps" + echo "corelib version mismatch, please update the vendor/cairo submodule:" + echo "- git submodule update --init" exit 1 fi diff --git a/scripts/extract_e2e_sierra.py b/scripts/extract_e2e_sierra.py new file mode 100755 index 0000000000..d9ec33b452 --- /dev/null +++ b/scripts/extract_e2e_sierra.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +Extract sierra_code sections from cairo e2e test data files. + +Input: test_data/e2e_libfuncs_raw/ (files in //! > format) +Output: test_data/e2e_sierra/ (individual .sierra files) +""" + +import os +import re +import shutil +import sys + +SRC_DIR = "vendor/cairo/tests/e2e_test_data/libfuncs" +DST_DIR = "test_data/e2e_sierra" + + +def sanitize_name(name): + """Convert test name to a safe filename.""" + return re.sub(r"[^\w\-]", "_", name.strip()).strip("_") + + +def parse_test_cases(text): + """Parse //! > format into list of test-case dicts mapping section_key -> content.""" + cases = re.split(r"^//! > =+\s*$", text, flags=re.MULTILINE) + results = [] + for case in cases: + sections = {} + section_order = [] + current_section = None + lines = [] + for line in case.splitlines(): + m = re.match(r"^//! > (.+)$", line) + if m: + if current_section is not None: + sections[current_section] = "\n".join(lines).strip() + current_section = m.group(1).strip() + section_order.append(current_section) + lines = [] + else: + lines.append(line) + if current_section is not None: + sections[current_section] = "\n".join(lines).strip() + if sections: + sections["_order"] = section_order + results.append(sections) + return results + + +def main(): + if not os.path.isdir(SRC_DIR): + print( + f"Source directory {SRC_DIR} not found. " + "Run 'git submodule update --init' first." + ) + sys.exit(1) + + shutil.rmtree(DST_DIR, ignore_errors=True) + + count = 0 + for dirpath, _, filenames in sorted(os.walk(SRC_DIR)): + for filename in sorted(filenames): + filepath = os.path.join(dirpath, filename) + + with open(filepath, "r") as f: + content = f.read() + + # Preserve subdirectory structure (e.g. starknet/syscalls) + rel_dir = os.path.relpath(dirpath, SRC_DIR) + test_cases = parse_test_cases(content) + for case in test_cases: + sierra = case.get("sierra_code", "").strip() + if not sierra: + continue + + # The test name is the first section key (not a section called "test_name") + order = case.get("_order", []) + if not order: + continue + test_name = order[0] + + safe_name = sanitize_name(test_name) + if not safe_name: + continue + + out_dir = os.path.join(DST_DIR, rel_dir, filename) + os.makedirs(out_dir, exist_ok=True) + out_path = os.path.join(out_dir, f"{safe_name}.sierra") + + with open(out_path, "w") as f: + f.write(sierra + "\n") + count += 1 + + print(f"Extracted {count} sierra files into {DST_DIR}/") + + +if __name__ == "__main__": + main() diff --git a/scripts/pull_external_projects.py b/scripts/pull_external_projects.py deleted file mode 100644 index 22bfd28a6c..0000000000 --- a/scripts/pull_external_projects.py +++ /dev/null @@ -1,41 +0,0 @@ -import tempfile -import subprocess -import sys -import shutil -import os - -if len(sys.argv) < 2: - print("Expected Cairo branch or tag as first argument") - sys.exit(1) -ref = sys.argv[1] - -with tempfile.TemporaryDirectory() as root: - subprocess.run( - [ - "git", - "clone", - "https://github.com/starkware-libs/cairo", - "--branch", - ref, - root, - ], - check=True, - stdout=sys.stdout, - stderr=sys.stderr, - ) - - shutil.rmtree("corelib", ignore_errors=True) - shutil.copytree( - os.path.join(root, "corelib"), - "corelib", - ) - shutil.rmtree("test_data/tests_starknet/bug_samples", ignore_errors=True) - shutil.copytree( - os.path.join(root, "tests/bug_samples"), - "test_data/tests_starknet/bug_samples", - ) - shutil.rmtree("test_data/tests_starknet/cairo_level_tests", ignore_errors=True) - shutil.copytree( - os.path.join(root, "crates/cairo-lang-starknet/cairo_level_tests"), - "test_data/tests_starknet/cairo_level_tests", - ) diff --git a/src/libfuncs/circuit.rs b/src/libfuncs/circuit.rs index 3b6abe6e83..a459a45d7b 100644 --- a/src/libfuncs/circuit.rs +++ b/src/libfuncs/circuit.rs @@ -102,6 +102,8 @@ fn build_init_circuit_data<'ctx, 'this>( metadata: &mut MetadataStorage, info: &SignatureAndTypeConcreteLibfunc, ) -> Result<()> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); + let circuit_info = match registry.get_type(&info.ty)? { CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, _ => return Err(SierraAssertError::BadTypeInfo.into()), @@ -307,6 +309,8 @@ fn build_eval<'ctx, 'this>( metadata: &mut MetadataStorage, info: &SignatureAndTypeConcreteLibfunc, ) -> Result<()> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); + let circuit_info = match registry.get_type(&info.ty)? { CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, _ => return Err(SierraAssertError::BadTypeInfo.into()), @@ -1102,7 +1106,7 @@ mod test { use num_traits::{Num, One}; use starknet_types_core::felt::Felt; - fn u384(limbs: [&str; 4]) -> Value { + fn u384(limbs: [&'static str; 4]) -> Value { fn u96_range() -> Range { Range { lower: BigUint::from_str_radix("0", 16).unwrap().into(), @@ -1115,19 +1119,19 @@ mod test { Value::Struct { fields: vec![ Value::BoundedInt { - value: Felt::from_hex_unchecked(limbs[0]), + value: Felt::from_hex_unwrap(limbs[0]), range: u96_range(), }, Value::BoundedInt { - value: Felt::from_hex_unchecked(limbs[1]), + value: Felt::from_hex_unwrap(limbs[1]), range: u96_range(), }, Value::BoundedInt { - value: Felt::from_hex_unchecked(limbs[2]), + value: Felt::from_hex_unwrap(limbs[2]), range: u96_range(), }, Value::BoundedInt { - value: Felt::from_hex_unchecked(limbs[3]), + value: Felt::from_hex_unwrap(limbs[3]), range: u96_range(), }, ], diff --git a/src/runtime.rs b/src/runtime.rs index be34e766ec..1d698d48ff 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -14,7 +14,6 @@ use lazy_static::lazy_static; use num_bigint::BigInt; use num_traits::{ToPrimitive, Zero}; use rand::Rng; -use starknet_curve::curve_params::BETA; use starknet_types_core::{ curve::{AffinePoint, ProjectivePoint}, felt::Felt, @@ -36,6 +35,15 @@ use std::{ }; use std::{ops::Mul, vec::IntoIter}; +///Todo(TomerStarkware): use starknet_curve::curve_params::BETA when they update starknet_types_core +/// Beta constant of the Stark curve. +const BETA: Felt = Felt::from_raw([ + 88155977965380735, + 12360725113329547591, + 7432612994240712710, + 3863487492851900874, +]); + lazy_static! { pub static ref HALF_PRIME: Felt = Felt::from_dec_str( "1809251394333065606848661391547535052811553607665798349986546028067936010240" diff --git a/src/starknet_stub.rs b/src/starknet_stub.rs index 4fbdf20b0c..ad41493593 100644 --- a/src/starknet_stub.rs +++ b/src/starknet_stub.rs @@ -21,7 +21,6 @@ use crate::{ }; use ark_ec::short_weierstrass::{Affine, Projective, SWCurveConfig}; use ark_ff::{BigInt, PrimeField}; -use cairo_lang_runner::RunResultValue; use cairo_lang_sierra::ids::FunctionId; use cairo_lang_starknet::contract::ContractInfo; use cairo_lang_starknet_classes::casm_contract_class::ENTRY_POINT_COST; @@ -291,13 +290,8 @@ impl StubSyscallHandler { *gas_counter = remaining_gas; } - let starknet_result = read_contract_result(&concrete_result.return_value) - .expect("return value was not a starknet panic result"); - - match starknet_result { - RunResultValue::Success(felts) => Ok(felts), - RunResultValue::Panic(felts) => Err(felts), - } + read_contract_result(&concrete_result.return_value) + .expect("return value was not a starknet panic result") } /// Replaces the addresses in the context. @@ -328,10 +322,11 @@ impl StubSyscallHandler { } } -/// Creates a `RunResultValue` from a contract entrypoint result. +/// Reads a contract entrypoint result. /// /// The value should be of type `PanicResult<(Span,)>`. -fn read_contract_result(value: &Value) -> Result { +/// Returns `Ok(Ok(felts))` for success, `Ok(Err(felts))` for panic. +fn read_contract_result(value: &Value) -> Result, Vec>, Error> { let unexpected_value_error = Err(Error::UnexpectedValue(String::from( "PanicResult<(Span,)>", ))); @@ -378,7 +373,7 @@ fn read_contract_result(value: &Value) -> Result { else { return unexpected_value_error; }; - Ok(RunResultValue::Success(values)) + Ok(Ok(values)) } 1 => { // The value should be of type: Struct> @@ -408,7 +403,7 @@ fn read_contract_result(value: &Value) -> Result { else { return unexpected_value_error; }; - Ok(RunResultValue::Panic(values)) + Ok(Err(values)) } _ => unexpected_value_error, } @@ -488,12 +483,12 @@ impl StarknetSyscallHandler for &mut StubSyscallHandler { /// Max value for a contract address: 2**251 - 256. const CONTRACT_ADDRESS_BOUND: NonZeroFelt = - NonZeroFelt::from_felt_unchecked(Felt::from_hex_unchecked( + NonZeroFelt::from_felt_unchecked(Felt::from_hex_unwrap( "0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", )); /// Cairo string for "STARKNET_CONTRACT_ADDRESS" const CONTRACT_ADDRESS_PREFIX: Felt = - Felt::from_hex_unchecked("0x535441524b4e45545f434f4e54524143545f41444452455353"); + Felt::from_hex_unwrap("0x535441524b4e45545f434f4e54524143545f41444452455353"); let deployer_address = if deploy_from_zero { Felt::zero() @@ -578,7 +573,12 @@ impl StarknetSyscallHandler for &mut StubSyscallHandler { let Some(contract_info) = self.contracts_info.get(&class_hash).cloned() else { return Err(vec![Felt::from_bytes_be_slice(b"CLASS_HASH_NOT_DECLARED")]); }; - let Some(entry_point) = contract_info.externals.get(&function_selector) else { + let Some(entry_point) = contract_info + .externals + .iter() + .find(|(k, _)| k.to_bytes_le() == function_selector.to_bytes_le()) + .map(|(_, v)| v) + else { return Err(vec![ Felt::from_bytes_be_slice(b"ENTRYPOINT_NOT_FOUND"), Felt::from_bytes_be_slice(b"ENTRYPOINT_FAILED"), @@ -616,7 +616,12 @@ impl StarknetSyscallHandler for &mut StubSyscallHandler { .get(class_hash) .expect("Deployed contract not found in registry.") .clone(); - let Some(entry_point) = contract_info.externals.get(&entry_point_selector) else { + let Some(entry_point) = contract_info + .externals + .iter() + .find(|(k, _)| k.to_bytes_le() == entry_point_selector.to_bytes_le()) + .map(|(_, v)| v) + else { return Err(vec![ Felt::from_bytes_be_slice(b"ENTRYPOINT_NOT_FOUND"), Felt::from_bytes_be_slice(b"ENTRYPOINT_FAILED"), diff --git a/src/types/circuit.rs b/src/types/circuit.rs index 5cb6163349..b7dd985998 100644 --- a/src/types/circuit.rs +++ b/src/types/circuit.rs @@ -111,6 +111,8 @@ pub fn build_circuit_accumulator<'ctx>( metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module)); + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { return Err(SierraAssertError::BadTypeInfo.into()); }; @@ -211,6 +213,8 @@ pub fn build_circuit_data<'ctx>( metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module)); + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { return Err(SierraAssertError::BadTypeInfo.into()); }; @@ -302,6 +306,8 @@ pub fn build_circuit_outputs<'ctx>( metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, module)); + let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { return Err(SierraAssertError::BadTypeInfo.into()); }; diff --git a/src/utils/testing.rs b/src/utils/testing.rs index fb9098856c..c4cf16cb3b 100644 --- a/src/utils/testing.rs +++ b/src/utils/testing.rs @@ -266,7 +266,7 @@ pub fn run_program_assert_output( pub fn panic_byte_array(message: &str) -> Vec { // Prepend byte array magic, used to identify serialized `ByteArray` variables. // https://github.com/starkware-libs/cairo/tree/v2.12.3/corelib/src/byte_array.cairo#L64 - let mut array = vec![Felt::from_hex_unchecked( + let mut array = vec![Felt::from_hex_unwrap( "0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3", )]; diff --git a/test_data/tests_starknet/bug_samples b/test_data/tests_starknet/bug_samples new file mode 120000 index 0000000000..6959f3de42 --- /dev/null +++ b/test_data/tests_starknet/bug_samples @@ -0,0 +1 @@ +../../vendor/cairo/tests/bug_samples \ No newline at end of file diff --git a/test_data/tests_starknet/bug_samples/builtin_usage_before_unreachable.cairo b/test_data/tests_starknet/bug_samples/builtin_usage_before_unreachable.cairo deleted file mode 100644 index 1560f67355..0000000000 --- a/test_data/tests_starknet/bug_samples/builtin_usage_before_unreachable.cairo +++ /dev/null @@ -1,12 +0,0 @@ -#[derive(Drop)] -enum NeverWithDrop {} - -fn foo(x: Option, a: u32) { - match x { - Some(never_ty) => { - let _b: u16 = a.try_into().unwrap_or(0); - match never_ty {} - }, - None => {}, - } -} diff --git a/test_data/tests_starknet/bug_samples/cairo_project.toml b/test_data/tests_starknet/bug_samples/cairo_project.toml deleted file mode 100644 index 5004819485..0000000000 --- a/test_data/tests_starknet/bug_samples/cairo_project.toml +++ /dev/null @@ -1,10 +0,0 @@ -[crate_roots] -bug_samples = "." - -[config.global] -edition = "2023_10" - -[config.global.experimental_features] -associated_item_constraints = true -negative_impls = true -user_defined_inline_macros = true diff --git a/test_data/tests_starknet/bug_samples/ecdsa_completeness.cairo b/test_data/tests_starknet/bug_samples/ecdsa_completeness.cairo deleted file mode 100644 index d3fbaf3113..0000000000 --- a/test_data/tests_starknet/bug_samples/ecdsa_completeness.cairo +++ /dev/null @@ -1,13 +0,0 @@ -use core::ecdsa::check_ecdsa_signature; - -const message_hash: felt252 = 0x2d6479c0758efbb5aa07d35ed5454d728637fceab7ba544d3ea95403a5630a8; - -const pubkey: felt252 = 0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca; -const r: felt252 = 0x6ff7b413a8457ef90f326b5280600a4473fef49b5b1dcdfcd7f42ca7aa59c69; -const s: felt252 = 0x23a9747ed71abc5cb956c0df44ee8638b65b3e9407deade65de62247b8fd77; - - -#[test] -fn test_check_ecdsa_signature() { - check_ecdsa_signature(message_hash, pubkey, r, s); -} diff --git a/test_data/tests_starknet/bug_samples/generic_cycles.cairo b/test_data/tests_starknet/bug_samples/generic_cycles.cairo deleted file mode 100644 index 7cdd527409..0000000000 --- a/test_data/tests_starknet/bug_samples/generic_cycles.cairo +++ /dev/null @@ -1,6 +0,0 @@ -trait ATrait {} -trait ATrait2> {} - -struct B, +ATrait2> { - t: T, -} diff --git a/test_data/tests_starknet/bug_samples/inconsistent_gas.cairo b/test_data/tests_starknet/bug_samples/inconsistent_gas.cairo deleted file mode 100644 index c641d391dc..0000000000 --- a/test_data/tests_starknet/bug_samples/inconsistent_gas.cairo +++ /dev/null @@ -1,55 +0,0 @@ -#[starknet::contract] -mod test_contract { - use starknet::storage_access::{ - storage_address_from_base_and_offset, storage_base_address_from_felt252, - }; - use starknet::syscalls::emit_event_syscall; - use starknet::{ - ContractAddress, SyscallResultTrait, get_caller_address, storage_read_syscall, - storage_write_syscall, - }; - - #[storage] - struct Storage { - my_storage_var: felt252, - } - - #[external(v0)] - fn test(ref self: ContractState, ref arg: felt252, arg1: felt252, arg2: felt252) -> felt252 { - let x = self.my_storage_var.read(); - self.my_storage_var.write(x + 1); - x + 1 - } - - #[external(v0)] - fn test_storage_read(ref self: ContractState, address: felt252) -> felt252 { - let domain_address = 0_u32; // Only address_domain 0 is currently supported. - let storage_address = storage_address_from_base_and_offset( - storage_base_address_from_felt252(address), 0_u8, - ); - storage_read_syscall(domain_address, storage_address).unwrap_syscall() - } - - #[external(v0)] - fn test_storage_write(ref self: ContractState, address: felt252, value: felt252) { - let domain_address = 0_u32; // Only address_domain 0 is currently supported. - let storage_address = storage_address_from_base_and_offset( - storage_base_address_from_felt252(address), 0_u8, - ); - storage_write_syscall(domain_address, storage_address, value).unwrap_syscall(); - } - - #[external(v0)] - fn test_get_caller_address(ref self: ContractState) -> ContractAddress { - let caller_address = get_caller_address(); - caller_address - } - - #[external(v0)] - fn test_emit_event(ref self: ContractState, keys: Array, data: Array) { - emit_event_syscall(keys.span(), data.span()).unwrap_syscall(); - } - - #[external(v0)] - fn test_emit_simple_event(ref self: ContractState, arg0: felt252) {} -} diff --git a/test_data/tests_starknet/bug_samples/indirect_impl_alias.cairo b/test_data/tests_starknet/bug_samples/indirect_impl_alias.cairo deleted file mode 100644 index 2a98b4dc57..0000000000 --- a/test_data/tests_starknet/bug_samples/indirect_impl_alias.cairo +++ /dev/null @@ -1,25 +0,0 @@ -trait Trait1 { - fn func1(value: T); -} - -trait Trait2 { - fn func2(value: T); -} - -mod impls { - impl Impl1> of super::Trait1 { - fn func1(value: T) {} - } - pub impl ImplAlias1 = Impl1; - impl Impl2> of super::Trait2 { - fn func2(value: T) {} - } - pub impl ImplAlias2 = Impl2; -} -use impls::ImplAlias1; -impl Impl2 = impls::ImplAlias2; - -fn foo() { - Trait1::func1(0_felt252); - Trait2::func2(0_felt252); -} diff --git a/test_data/tests_starknet/bug_samples/issue2114.cairo b/test_data/tests_starknet/bug_samples/issue2114.cairo deleted file mode 100644 index b9a24c589a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2114.cairo +++ /dev/null @@ -1,4 +0,0 @@ -#[starknet::interface] -trait IProxy { - fn initialize(ref self: T, world_address: starknet::ContractAddress); -} diff --git a/test_data/tests_starknet/bug_samples/issue2147.cairo b/test_data/tests_starknet/bug_samples/issue2147.cairo deleted file mode 100644 index 15e030ad4d..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2147.cairo +++ /dev/null @@ -1,13 +0,0 @@ -use core::integer::u256_from_felt252; - -#[test] -fn test_bug_test() { - let a = 1; - let b = 2; - let mut c = 0; - if u256_from_felt252(a) < u256_from_felt252(b) { - c = core::pedersen::pedersen(a, b); - } else { - c = core::pedersen::pedersen(b, a); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue2152.cairo b/test_data/tests_starknet/bug_samples/issue2152.cairo deleted file mode 100644 index 375d983dbc..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2152.cairo +++ /dev/null @@ -1,17 +0,0 @@ -use core::integer::u256_from_felt252; - -#[test] -fn reproduce_bug() { - match core::gas::withdraw_gas_all(core::gas::get_builtin_costs()) { - Some(_) => {}, - None => { panic(array!['OOG']); }, - } - let a = 1; - let b = 2; - let mut c = 0; - if u256_from_felt252(a) < u256_from_felt252(b) { - c = core::pedersen::pedersen(a, b); - } else { - c = core::pedersen::pedersen(b, a); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue2171.cairo b/test_data/tests_starknet/bug_samples/issue2171.cairo deleted file mode 100644 index 5a92b0de9d..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2171.cairo +++ /dev/null @@ -1,16 +0,0 @@ -use core::test::test_utils::assert_eq; -use starknet::ContractAddress; - -#[test] -fn main() { - let contract_address = 0x1000.try_into().unwrap(); - foo(contract_address); -} - -fn foo(contract_address: ContractAddress) { - assert_eq( - @Into::::into(contract_address), - @Into::::into(contract_address), - 'Some message', - ); -} diff --git a/test_data/tests_starknet/bug_samples/issue2172.cairo b/test_data/tests_starknet/bug_samples/issue2172.cairo deleted file mode 100644 index 968efca40a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2172.cairo +++ /dev/null @@ -1,18 +0,0 @@ -#[derive(Drop)] -struct Node { - value: felt252, - left: Option>, - right: Option>, -} - -fn traverse(node: Node) { - let Node { value: _, left, right } = node; - match left { - Some(x) => traverse(x.unbox()), - None => {}, - } - match right { - Some(x) => traverse(x.unbox()), - None => {}, - } -} diff --git a/test_data/tests_starknet/bug_samples/issue2176.cairo b/test_data/tests_starknet/bug_samples/issue2176.cairo deleted file mode 100644 index 4209f0a651..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2176.cairo +++ /dev/null @@ -1,6 +0,0 @@ -#[test] -fn main() { - let mut a = ArrayTrait::::new(); - assert_eq!(a.len(), 0_usize); - assert_eq!(a.is_empty(), true); -} diff --git a/test_data/tests_starknet/bug_samples/issue2249.cairo b/test_data/tests_starknet/bug_samples/issue2249.cairo deleted file mode 100644 index d8fbe3bac2..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2249.cairo +++ /dev/null @@ -1,28 +0,0 @@ -#[derive(Drop)] -struct Node { - value: felt252, - left: Option>, -} - -#[test] -fn simple_test() { - let bst = Node { value: 12, left: None }; - - assert_eq!(bst.value, 12); - assert!(bst.left.is_none(), "left should be none"); -} - -#[derive(Copy, Drop)] -pub enum RecursiveType { - Simple: felt252, - Direct: Span, - ExtraHop: Span<(felt252, RecursiveType)>, -} - -#[inline(never)] -fn use_value(_value: RecursiveType) {} - -#[test] -fn other_test() { - use_value(RecursiveType::Simple(12)); -} diff --git a/test_data/tests_starknet/bug_samples/issue2480.cairo b/test_data/tests_starknet/bug_samples/issue2480.cairo deleted file mode 100644 index 889c0c0194..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2480.cairo +++ /dev/null @@ -1,80 +0,0 @@ -#[derive(Copy, Drop)] -struct A { - value: felt252, -} - -#[derive(Copy, Drop)] -struct B { - a: A, -} - - -#[test] -fn test_member_of_local_struct() { - let a = A { value: 12 }; - test_member_of_local_struct_inner(a); -} - -fn test_member_of_local_struct_inner(a: A) -> felt252 { - let value = a.value; - core::internal::revoke_ap_tracking(); - value -} - - -#[test] -fn member_of_temp_struct() -> felt252 { - let a = A { value: 12 }; - let x = a.value; - core::internal::revoke_ap_tracking(); - x -} - -fn get_value_a(a: A) -> felt252 { - a.value -} - - -#[test] -fn member_and_struct_of_temp_struct() -> felt252 { - let a = A { value: 12 }; - let x = a.value; - core::internal::revoke_ap_tracking(); - get_value_a(a) + x -} - - -#[test] -fn test_member_of_member_of_local_struct() { - let b = B { a: A { value: 12 } }; - test_member_of_member_of_local_struct_inner(b); -} - -fn test_member_of_member_of_local_struct_inner(b: B) -> felt252 { - let value = b.a.value; - core::internal::revoke_ap_tracking(); - value -} - - -#[test] -fn member_of_member_of_temp_struct() -> felt252 { - let b = B { a: A { value: 12 } }; - let x = b.a.value; - core::internal::revoke_ap_tracking(); - x -} - -fn get_value_b(b: B) -> felt252 { - b.a.value -} - - -#[test] -fn member_of_member_and_struct_of_temp_struct() -> felt252 { - let b = B { a: A { value: 12 } }; - let a = b.a; - let x = a.value; - core::internal::revoke_ap_tracking(); - get_value_a(a) + get_value_b(b) + x -} diff --git a/test_data/tests_starknet/bug_samples/issue2530.cairo b/test_data/tests_starknet/bug_samples/issue2530.cairo deleted file mode 100644 index efb012b338..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2530.cairo +++ /dev/null @@ -1,16 +0,0 @@ -#[derive(Drop)] -struct MyStruct { - value: felt252, - arr: Array, -} - -#[test] -fn main() { - let mut my_struct = MyStruct { value: 0, arr: Default::default() }; - let result = sub_three(my_struct.value); - my_struct.value = result; -} - -fn sub_three(value: felt252) -> felt252 { - value - 3 -} diff --git a/test_data/tests_starknet/bug_samples/issue2567.cairo b/test_data/tests_starknet/bug_samples/issue2567.cairo deleted file mode 100644 index 42b42b74a1..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2567.cairo +++ /dev/null @@ -1,11 +0,0 @@ -fn throw(err_code: felt252) -> core::never { - let mut data = array![]; - data.append(err_code); - panic(data) -} - -#[test] -#[should_panic] -fn main() -> felt252 { - match throw(1) {} -} diff --git a/test_data/tests_starknet/bug_samples/issue2612.cairo b/test_data/tests_starknet/bug_samples/issue2612.cairo deleted file mode 100644 index 747eef31b4..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2612.cairo +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -fn main() { - let _d: Felt252Dict = Default::default(); -} diff --git a/test_data/tests_starknet/bug_samples/issue2816.cairo b/test_data/tests_starknet/bug_samples/issue2816.cairo deleted file mode 100644 index 7ab753cd3a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2816.cairo +++ /dev/null @@ -1,27 +0,0 @@ -fn contains, +Drop, +Copy>( - ref self: Array, item: T, -) -> bool { - let mut index = 0_usize; - loop { - if index >= self.len() { - break false; - } else if *self[index] == item { - break true; - } else { - index = index + 1_usize; - } - } -} - -#[test] -fn test_contains() { - let mut arr: Array = array![1, 2, 3, 4]; - assert!(contains(ref arr, 1)); - assert!(contains(ref arr, 2)); - assert!(contains(ref arr, 3)); - assert!(contains(ref arr, 4)); - assert!(!contains(ref arr, 5)); - assert!(!contains(ref arr, 6)); - assert!(!contains(ref arr, 7)); - assert!(!contains(ref arr, 8)); -} diff --git a/test_data/tests_starknet/bug_samples/issue2819.cairo b/test_data/tests_starknet/bug_samples/issue2819.cairo deleted file mode 100644 index 2389c17730..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2819.cairo +++ /dev/null @@ -1,11 +0,0 @@ -fn foo(x: @u32) { - *x + 1; - if true { - *x + 2; - } -} - -#[test] -fn main() { - foo(@4); -} diff --git a/test_data/tests_starknet/bug_samples/issue2820.cairo b/test_data/tests_starknet/bug_samples/issue2820.cairo deleted file mode 100644 index 25dca8c43c..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2820.cairo +++ /dev/null @@ -1,12 +0,0 @@ -fn foo(ref item_index: usize, index: usize) -> usize { - if 5_usize < 7 { - item_index = index; - } - index -} - -#[test] -fn main() { - let mut x = 0; - foo(ref x, 0); -} diff --git a/test_data/tests_starknet/bug_samples/issue2932.cairo b/test_data/tests_starknet/bug_samples/issue2932.cairo deleted file mode 100644 index e9c8aff017..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2932.cairo +++ /dev/null @@ -1,11 +0,0 @@ -use core::test::test_utils::assert_ne; -use starknet::get_tx_info; - -fn foo(v: felt252) { - if v == 1 { - let _tx_info = get_tx_info().unbox(); - assert_ne(@v, @'EXECUTE_AFTER_UPGRADE', 'argent/forbidden-call'); - } else { - core::internal::revoke_ap_tracking(); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue2939.cairo b/test_data/tests_starknet/bug_samples/issue2939.cairo deleted file mode 100644 index f0fc24f406..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2939.cairo +++ /dev/null @@ -1,23 +0,0 @@ -fn foo() -> usize { - let mut x = 0_usize; - let mut y = 0_usize; - loop { - core::gas::withdraw_gas_all(core::gas::get_builtin_costs()).expect('Out of gas'); - if x == 10_usize { - break y; - } - - x += 1_usize; - - if x % 2_usize == 0_usize { - continue; - } - - y += 1_usize; - } -} - -#[test] -fn main() { - assert_eq!(foo(), 5_usize); -} diff --git a/test_data/tests_starknet/bug_samples/issue2961.cairo b/test_data/tests_starknet/bug_samples/issue2961.cairo deleted file mode 100644 index baf6def5d8..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2961.cairo +++ /dev/null @@ -1,32 +0,0 @@ -use core::test::test_utils::assert_eq; - -#[derive(Copy, PartialEq, Destruct, Serde)] -struct SimpleStruct { - a: felt252, -} - -#[test] -fn test_struct_serialization() { - let data = SimpleStruct { a: 1 }; - let mut raw_data = Default::default(); - data.serialize(ref raw_data); - let mut as_span = raw_data.span(); - let deserd = Serde::::deserialize(ref as_span).unwrap(); - assert_eq(@data, @deserd, 'Bad deserialization'); -} - -#[derive(Clone, PartialEq, Drop, Serde)] -enum SimpleEnum { - a: felt252, - b: felt252, -} - -#[test] -fn test_enum_serialization() { - let data = SimpleEnum::b(59); - let mut raw_data = Default::default(); - data.serialize(ref raw_data); - let mut as_span = raw_data.span(); - let deserd = Serde::::deserialize(ref as_span).unwrap(); - assert_eq(@data, @deserd, 'Bad deserialization'); -} diff --git a/test_data/tests_starknet/bug_samples/issue2964.cairo b/test_data/tests_starknet/bug_samples/issue2964.cairo deleted file mode 100644 index 2aec153da2..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2964.cairo +++ /dev/null @@ -1,27 +0,0 @@ -use core::test::test_utils::assert_eq; - -#[derive(Copy, Drop, Serde, PartialEq)] -struct SimpleStruct { - x: felt252, - y: felt252, -} - -#[derive(Copy, Clone, Destruct, Serde, PartialEq)] -struct GenericStruct { - x: T, - y: U, -} - -#[test] -fn main() { - // This assumes that Drop implies Destruct and Copy implies Clone - let mut a = GenericStruct { x: SimpleStruct { x: 1, y: 2 }, y: SimpleStruct { x: 1, y: 2 } }; - a.x.x = 34; - a.y.y = 5; - let mut serialized = Default::default(); - a.serialize(ref serialized); - let mut as_span = serialized.span(); - let deserialized = Serde::>::deserialize(ref as_span) - .unwrap(); - assert_eq(@a, @deserialized, 'Bad Serde'); -} diff --git a/test_data/tests_starknet/bug_samples/issue2995.cairo b/test_data/tests_starknet/bug_samples/issue2995.cairo deleted file mode 100644 index 16912131a1..0000000000 --- a/test_data/tests_starknet/bug_samples/issue2995.cairo +++ /dev/null @@ -1,8 +0,0 @@ -trait ATrait {} - -struct B { - t: T, - g: G, -} - -impl BCopy, +Copy> of Copy>; diff --git a/test_data/tests_starknet/bug_samples/issue3119.cairo b/test_data/tests_starknet/bug_samples/issue3119.cairo deleted file mode 100644 index 468094a1e7..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3119.cairo +++ /dev/null @@ -1,45 +0,0 @@ -fn index_of_min, +PartialOrd, +Drop, +Copy>( - mut span: Span, -) -> Option { - let mut current_index = 0; - let mut min_index = 0; - let mut min = match span.pop_front() { - Some(item) => *item, - None => { return None; }, - }; - loop { - match span.pop_front() { - Some(item) => { - if *item < min { - min = *item; - current_index = current_index + 1; - min_index = current_index; - } - }, - None => { break Some(min_index); }, - } - } -} - -#[test] -fn issue_3119() { - let _min_index = index_of_min(array![5_usize, 4, 1, 2, 3].span()); -} - -fn foo(mut y: felt252, mut z: felt252) { - if y == 1 { - return; - } - if y == 0 { - y = 1; - z = y; - } - foo(y, z); -} - -#[test] -fn simplified_3119() { - let mut z = 0; - let mut y = 0; - foo(z, y); -} diff --git a/test_data/tests_starknet/bug_samples/issue3130.cairo b/test_data/tests_starknet/bug_samples/issue3130.cairo deleted file mode 100644 index 2665fd06f4..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3130.cairo +++ /dev/null @@ -1,11 +0,0 @@ -#[feature("deprecated-consteval-int-macro")] -const a: felt252 = consteval_int!((4 + 2 * 3) * 256); -#[feature("deprecated-consteval-int-macro")] -const b: felt252 = consteval_int!(0xff & (24 + 5 * 2)); -#[feature("deprecated-consteval-int-macro")] -const c: felt252 = consteval_int!(-0xff & (24 + 5 * 2)); -#[feature("deprecated-consteval-int-macro")] -const d: felt252 = consteval_int!(0xff | (24 + 5 * 2)); - -#[test] -fn main() {} diff --git a/test_data/tests_starknet/bug_samples/issue3153.cairo b/test_data/tests_starknet/bug_samples/issue3153.cairo deleted file mode 100644 index ec926de205..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3153.cairo +++ /dev/null @@ -1,100 +0,0 @@ -use core::integer::u256_from_felt252; -use starknet::{ - StorageBaseAddress, Store, SyscallResult, storage_address_from_base_and_offset, - storage_read_syscall, storage_write_syscall, -}; - -impl U256TryIntoU64 of TryInto { - fn try_into(self: u256) -> Option { - let intermediate: Option = self.try_into(); - match intermediate { - Some(felt) => felt.try_into(), - None => None, - } - } -} - -const MASK_64: u256 = 0xFFFFFFFFFFFFFFFF; -const MASK_160: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - -const TWO_POW_160: u256 = 0x10000000000000000000000000000000000000000; - -#[derive(Copy, Drop, Serde)] -struct Proposal { - proposer: felt252, - last_updated_at: u64, -} - -/// Pack the proposal fields into a single felt252. -/// * `proposer` - The proposer of the proposal. -/// * `last_updated_at` - The last time the proposal was updated. -fn pack_proposal_fields(proposer: felt252, last_updated_at: u64) -> felt252 { - let mut packed = 0; - packed = packed | proposer.into(); - packed = packed | (u256_from_felt252(last_updated_at.into()) * TWO_POW_160); - - packed.try_into().unwrap() -} - -/// Unpack the proposal fields from a single felt252. -/// * `packed` - The packed proposal. -fn unpack_proposal_fields(packed: felt252) -> (felt252, u64) { - let packed = packed.into(); - - let proposer = (packed & MASK_160).try_into().unwrap(); - let last_updated_at: u64 = U256TryIntoU64::try_into(((packed / TWO_POW_160) & MASK_64)) - .unwrap(); - - (proposer, last_updated_at) -} - -impl ProposalStore of Store { - fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { - Self::read_at_offset(address_domain, base, 0) - } - - fn write(address_domain: u32, base: StorageBaseAddress, value: Proposal) -> SyscallResult<()> { - Self::write_at_offset(address_domain, base, 0, value) - } - fn read_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, - ) -> SyscallResult { - let (proposer, last_updated_at) = unpack_proposal_fields( - storage_read_syscall( - address_domain, storage_address_from_base_and_offset(base, offset), - )?, - ); - Ok(Proposal { proposer, last_updated_at }) - } - - fn write_at_offset( - address_domain: u32, base: StorageBaseAddress, offset: u8, value: Proposal, - ) -> SyscallResult<()> { - let packed = pack_proposal_fields(value.proposer, value.last_updated_at); - storage_write_syscall( - address_domain, storage_address_from_base_and_offset(base, offset), packed, - ) - } - - fn size() -> u8 { - 1 - } -} - -#[starknet::contract] -mod test_contract { - use starknet::storage::Map; - use super::Proposal; - #[storage] - struct Storage { - _proposals: Map, - _single_proposal: Proposal, - } - - #[external(v0)] - fn reproduce(ref self: ContractState) { - self._single_proposal.read(); - - self._proposals.write(1, Proposal { proposer: 0, last_updated_at: 0 }); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue3192.cairo b/test_data/tests_starknet/bug_samples/issue3192.cairo deleted file mode 100644 index 64b63e84b5..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3192.cairo +++ /dev/null @@ -1,4 +0,0 @@ -#[starknet::interface] -trait IContract { - fn foo(self: @TContractState, calldata: felt252); -} diff --git a/test_data/tests_starknet/bug_samples/issue3211.cairo b/test_data/tests_starknet/bug_samples/issue3211.cairo deleted file mode 100644 index eeabe5d561..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3211.cairo +++ /dev/null @@ -1,17 +0,0 @@ -impl U256TryIntoU64 of TryInto { - #[inline(always)] - fn try_into(self: u256) -> Option { - if (self.high == 0) { - self.low.try_into() - } else { - None - } - } -} - -#[test] -fn test_u256_tryinto_u64() { - let a = u256 { low: 64, high: 0 }; - let b: u64 = U256TryIntoU64::try_into(a).unwrap(); - assert_eq!(b, 64); -} diff --git a/test_data/tests_starknet/bug_samples/issue3345.cairo b/test_data/tests_starknet/bug_samples/issue3345.cairo deleted file mode 100644 index 8ed72bb163..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3345.cairo +++ /dev/null @@ -1,43 +0,0 @@ -#[derive(Copy, Drop, starknet::Store)] -struct Node { - left: u128, - right: u128, -} - -#[starknet::interface] -trait ITree { - fn sorted_list(ref self: TContractState, root: u128); -} - -#[starknet::contract] -mod example_failure { - use starknet::storage::Map; - use super::{ITree, Node}; - - #[storage] - struct Storage { - nodes: Map, - } - - #[generate_trait] - impl Impl of MyTrait { - fn append_in_order_nodes(self: @ContractState, ref list: Array<(u128, Node)>, at: u128) { - let node = self.nodes.read(at); - if (node.left != 0) { - self.append_in_order_nodes(ref list, node.left); - } - list.append((at, node)); - if (node.right != 0) { - self.append_in_order_nodes(ref list, node.right); - } - } - } - - #[abi(embed_v0)] - impl Tree of ITree { - fn sorted_list(ref self: ContractState, root: u128) { - let mut in_order: Array<(u128, Node)> = array![]; - self.append_in_order_nodes(ref in_order, root); - } - } -} diff --git a/test_data/tests_starknet/bug_samples/issue3658.cairo b/test_data/tests_starknet/bug_samples/issue3658.cairo deleted file mode 100644 index 0b3301fffd..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3658.cairo +++ /dev/null @@ -1,17 +0,0 @@ -#[derive(Drop)] -struct MyStruct { - copyable: u8, - non_copyable: Array, -} - -#[generate_trait] -impl MyStructImpl of MyStructTrait { - fn repro(ref self: MyStruct) { - let _copyable = self.copyable; - if true { - self.uses_self(); - } - } - - fn uses_self(ref self: MyStruct) {} -} diff --git a/test_data/tests_starknet/bug_samples/issue3863.cairo b/test_data/tests_starknet/bug_samples/issue3863.cairo deleted file mode 100644 index aa2ef5d36d..0000000000 --- a/test_data/tests_starknet/bug_samples/issue3863.cairo +++ /dev/null @@ -1,49 +0,0 @@ -/// The call context. -#[derive(Destruct)] -struct CallContext { - /// The bytecode to execute. - bytecode: Span, - /// The call data. - call_data: Span, - /// Amount of native token to transfer. - value: u256, -} - - -trait CallContextTrait { - fn new(bytecode: Span, call_data: Span, value: u256) -> CallContext; - fn bytecode(self: @CallContext) -> Span; - fn call_data(self: @CallContext) -> Span; - fn value(self: @CallContext) -> u256; -} - -impl CallContextImpl of CallContextTrait { - fn new(bytecode: Span, call_data: Span, value: u256) -> CallContext { - CallContext { bytecode, call_data, value } - } - fn bytecode(self: @CallContext) -> Span { - *self.bytecode - } - - fn call_data(self: @CallContext) -> Span { - *self.call_data - } - - fn value(self: @CallContext) -> u256 { - *self.value - } -} - -#[test] -fn test_call_context_new() { - // Given - let bytecode = array![1, 2, 3]; - let call_data = array![4, 5, 6]; - let value: u256 = 100; - // When - let call_context = CallContextTrait::new(bytecode.span(), call_data.span(), value); - // Then - assert!(call_context.bytecode() == bytecode.span(), "wrong bytecode"); - assert!(call_context.call_data() == call_data.span(), "wrong call data"); - assert!(call_context.value() == value, "wrong value"); -} diff --git a/test_data/tests_starknet/bug_samples/issue4007.cairo b/test_data/tests_starknet/bug_samples/issue4007.cairo deleted file mode 100644 index c3847e16f7..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4007.cairo +++ /dev/null @@ -1,10 +0,0 @@ -#[starknet::interface] -trait ISomeInterface { - fn some_lib_call(self: @TContractState); -} - -#[test] -#[should_panic(expected: ('CLASS_HASH_NOT_DECLARED',))] -fn call_not_declared() { - ISomeInterfaceLibraryDispatcher { class_hash: 32.try_into().unwrap() }.some_lib_call(); -} diff --git a/test_data/tests_starknet/bug_samples/issue4034.cairo b/test_data/tests_starknet/bug_samples/issue4034.cairo deleted file mode 100644 index 5b78834b8a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4034.cairo +++ /dev/null @@ -1,7 +0,0 @@ -#[test] -fn var_dropped_after_merge_remapping() { - let mut x: u32 = 0; - if (x == 0 && x != 1 && false) { - x = x + 1; - } -} diff --git a/test_data/tests_starknet/bug_samples/issue4036.cairo b/test_data/tests_starknet/bug_samples/issue4036.cairo deleted file mode 100644 index 9c21073dd4..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4036.cairo +++ /dev/null @@ -1,25 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -trait FirstInterface { - fn toto(self: @T, t: Array); - fn balance_of(self: @T); -} - - -#[starknet::contract] -mod toto { - #[storage] - struct Storage {} - use super::{FirstInterfaceDispatcher, FirstInterfaceDispatcherTrait}; - - #[external(v0)] - fn test_mint_and_unbox(self: @ContractState) { - const CONTRACT_ADDRESS: starknet::ContractAddress = 5_felt252.try_into().unwrap(); - let contract = FirstInterfaceDispatcher { contract_address: CONTRACT_ADDRESS }; - - contract.balance_of(); - contract.toto(array![contract.contract_address]); - contract.balance_of(); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue4038.cairo b/test_data/tests_starknet/bug_samples/issue4038.cairo deleted file mode 100644 index ffe3fb387e..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4038.cairo +++ /dev/null @@ -1,15 +0,0 @@ -#[inline(never)] -fn get_one() -> u32 { - 1 -} - -#[test] -fn ap_tracked_for_wrong_vars() { - let mut a: u32 = get_one(); - if (a == 1) { - core::internal::revoke_ap_tracking(); - } - if (a > 0 && a != 2) { - a += 1; - } -} diff --git a/test_data/tests_starknet/bug_samples/issue4075.cairo b/test_data/tests_starknet/bug_samples/issue4075.cairo deleted file mode 100644 index 800acc1936..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4075.cairo +++ /dev/null @@ -1,17 +0,0 @@ -#[derive(Copy, Drop, Serde)] -enum MemberType { - Simple: felt252, - Complex: Span, -} - -#[derive(Copy, Drop, Serde)] -struct Member { - name: felt252, - ty: MemberType, -} - -#[test] -fn sierra_type_dup() { - let mut arr = array![]; - MemberType::Simple('ty').serialize(ref arr); -} diff --git a/test_data/tests_starknet/bug_samples/issue4092.cairo b/test_data/tests_starknet/bug_samples/issue4092.cairo deleted file mode 100644 index 1f9967a85d..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4092.cairo +++ /dev/null @@ -1,28 +0,0 @@ -#[derive(Drop)] -struct Attribute { - name: ByteArray, - value: ByteArray, -} - -#[derive(Drop)] -struct Tag { - attrs: Option>, - children: Option>, - content: Option, -} - -fn build(tag: Tag) -> ByteArray { - let mut s = "<"; - - let mut _attrs = tag.attrs.unwrap(); - // let no_content = tag.children.is_none() && tag.content.is_none(); - let no_content = tag.children.is_none(); - let no_content = no_content && tag.content.is_none(); - - if no_content { - return s + " />"; - } else { - s += ">"; - } - s -} diff --git a/test_data/tests_starknet/bug_samples/issue4109.cairo b/test_data/tests_starknet/bug_samples/issue4109.cairo deleted file mode 100644 index d19d1734be..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4109.cairo +++ /dev/null @@ -1,25 +0,0 @@ -#[derive(Drop)] -struct Tag { - children: Option>, -} - -#[inline] -fn to_string(self: Tag) { - build(self); -} - -fn build(self: Tag) { - let Tag { children: opt_children } = self; - - let mut children = opt_children.unwrap(); - - to_string(children.pop_front().unwrap()); -} - - -#[test] -#[available_gas(1000000)] -#[should_panic(expected: ('Option::unwrap failed.',))] -fn test_build_empty() { - build(Tag { children: None }); -} diff --git a/test_data/tests_starknet/bug_samples/issue4314.cairo b/test_data/tests_starknet/bug_samples/issue4314.cairo deleted file mode 100644 index 8b610f4257..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4314.cairo +++ /dev/null @@ -1,21 +0,0 @@ -#[inline] -fn one() { - two(); -} - -#[inline(never)] -fn two() { - three(); -} - -#[inline(never)] -fn three() { - one(); -} - -#[test] -#[should_panic] -#[available_gas(10000)] -fn calls_inline_panic() { - one(); -} diff --git a/test_data/tests_starknet/bug_samples/issue4318.cairo b/test_data/tests_starknet/bug_samples/issue4318.cairo deleted file mode 100644 index 316a3da130..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4318.cairo +++ /dev/null @@ -1,18 +0,0 @@ -#[derive(Drop)] -struct Battle {} - -#[generate_trait] -impl BattleImpl of BattleTrait { - fn battle_loop(ref self: Battle) { - loop { - let mut entity: u32 = 5; - if !self.is_ally(entity) { - break; - } - } - } - - fn is_ally(ref self: Battle, entity_index: u32) -> bool { - return true; - } -} diff --git a/test_data/tests_starknet/bug_samples/issue4380.cairo b/test_data/tests_starknet/bug_samples/issue4380.cairo deleted file mode 100644 index b6d8e45607..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4380.cairo +++ /dev/null @@ -1,9 +0,0 @@ -fn get_value() -> Option { - Some(42) -} - -fn process_value() -> Result { - let value = get_value().ok_or('no value')?; - assert!(value < 69, "fail"); - Ok(value) -} diff --git a/test_data/tests_starknet/bug_samples/issue4897.cairo b/test_data/tests_starknet/bug_samples/issue4897.cairo deleted file mode 100644 index 2cddcbac8c..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4897.cairo +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg(missing_cfg)] -#[starknet::interface] -trait ITests { - fn set_value(ref self: TContractState, value: felt252); -} - - -#[starknet::contract] -mod MyContract { - #[storage] - struct Storage { - value: felt252, - } - - #[cfg(missing_cfg)] - #[abi(embed_v0)] - impl TestsImpl of super::ITests { - fn set_value(ref self: ContractState, value: felt252) { - self.value.write(value); - } - } -} diff --git a/test_data/tests_starknet/bug_samples/issue4937.cairo b/test_data/tests_starknet/bug_samples/issue4937.cairo deleted file mode 100644 index 3abee2c4c1..0000000000 --- a/test_data/tests_starknet/bug_samples/issue4937.cairo +++ /dev/null @@ -1,19 +0,0 @@ -#[test] -#[available_gas(static)] -#[should_panic(expected: 'Out of gas')] -fn test_never_loop() { - loop { - 1 + 1; - } -} - -#[test] -#[available_gas(static)] -#[should_panic(expected: 'Out of gas')] -fn test_never_rec() { - never_rec() -} - -fn never_rec() -> core::never { - never_rec() -} diff --git a/test_data/tests_starknet/bug_samples/issue5043.cairo b/test_data/tests_starknet/bug_samples/issue5043.cairo deleted file mode 100644 index 1a4e410637..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5043.cairo +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -fn array_of_u256s() { - let arr = array![1_u256, 2_u256, 3_u256]; - assert!(arr[0].low == @1); -} diff --git a/test_data/tests_starknet/bug_samples/issue5411.cairo b/test_data/tests_starknet/bug_samples/issue5411.cairo deleted file mode 100644 index 283208d4e8..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5411.cairo +++ /dev/null @@ -1,6 +0,0 @@ -use core::nullable::NullableTrait; - -#[test] -fn box_of_box() -> Nullable> { - NullableTrait::>::new(BoxTrait::new(16)) -} diff --git a/test_data/tests_starknet/bug_samples/issue5438.cairo b/test_data/tests_starknet/bug_samples/issue5438.cairo deleted file mode 100644 index 3b055bd2d9..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5438.cairo +++ /dev/null @@ -1,27 +0,0 @@ -#[inline(never)] -fn foo(mut x: i8, mut y: i8) -> i8 { - loop { - match x { - 0 => { - // A loop before continue - bug would cause the continue to call this loop. - while y < 100 { - y += 1; - } - x += 1; - }, - 1 => { - x -= 2; - continue; - }, - _ => { x -= 2; }, - } - if x < 0 { - break y; - } - } -} - -#[test] -fn loop_of_loop() -> i8 { - foo(10, 10) -} diff --git a/test_data/tests_starknet/bug_samples/issue5629.cairo b/test_data/tests_starknet/bug_samples/issue5629.cairo deleted file mode 100644 index b4c3d6b507..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5629.cairo +++ /dev/null @@ -1,15 +0,0 @@ -#[derive(Drop)] -struct NonCopy { - a: ByteArray, - b: ByteArray, -} - -fn foo(v: NonCopy) -> (NonCopy, ByteArray) { - let r = NonCopy { a: "4", ..v }; - (r, v.a) -} - -#[test] -fn test() { - foo(NonCopy { a: "a", b: "b" }); -} diff --git a/test_data/tests_starknet/bug_samples/issue5680.cairo b/test_data/tests_starknet/bug_samples/issue5680.cairo deleted file mode 100644 index e763c7df78..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5680.cairo +++ /dev/null @@ -1,21 +0,0 @@ -#[starknet::contract] -mod c1 { - use starknet::storage::Map; - - #[starknet::interface] - trait IMy { - fn a(self: @T); - } - - #[storage] - struct Storage { - v1: Map, - } - - #[abi(embed_v0)] - impl My of IMy { - fn a(self: @ContractState) { - let (_one, _two) = self.v1.read(0); - } - } -} diff --git a/test_data/tests_starknet/bug_samples/issue5764.cairo b/test_data/tests_starknet/bug_samples/issue5764.cairo deleted file mode 100644 index 808b8edc51..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5764.cairo +++ /dev/null @@ -1,9 +0,0 @@ -use starknet::SyscallResultTrait; - -#[test] -fn test_store_opt_and_result_at_offset() { - let base = starknet::storage_access::storage_base_address_const::<1000>(); - let v = (Some(1_u256), Result::<_, u128>::Ok(2_u8), Some(3_u64)); - starknet::Store::write(0, base, v).unwrap_syscall(); - assert_eq!(starknet::Store::read(0, base), Ok(v)); -} diff --git a/test_data/tests_starknet/bug_samples/issue5967.cairo b/test_data/tests_starknet/bug_samples/issue5967.cairo deleted file mode 100644 index 584b86e94f..0000000000 --- a/test_data/tests_starknet/bug_samples/issue5967.cairo +++ /dev/null @@ -1,23 +0,0 @@ -#[derive(Drop)] -pub enum Pattern { - Leaf, - Boxed: Box, -} - -pub fn boxed(pat: Pattern) -> Pattern { - return Pattern::Boxed(BoxTrait::new(pat)); -} - -pub fn boxed_leaf() -> Pattern { - boxed(Pattern::Leaf) -} - -#[inline(never)] -pub fn boxed_boxed_leaf() -> Pattern { - boxed(boxed_leaf()) -} - -#[test] -fn test() { - let _ = boxed_boxed_leaf(); -} diff --git a/test_data/tests_starknet/bug_samples/issue6580.cairo b/test_data/tests_starknet/bug_samples/issue6580.cairo deleted file mode 100644 index 8aa85fa5fa..0000000000 --- a/test_data/tests_starknet/bug_samples/issue6580.cairo +++ /dev/null @@ -1,21 +0,0 @@ -#[derive(Drop, Debug)] -struct SomeStruct { - num: felt252, -} - -#[test] -fn inner_index_access() { - let arr_of_bytearrays: Array = array!["str1", "str2", "str3"]; - let arr_of_arrays_of_nums: Array> = array![array![9], array![2], array![19, 20, 21]]; - let arr_of_arrays_of_structs: Array> = array![ - array![SomeStruct { num: 8 }], array![SomeStruct { num: 2 }], - array![SomeStruct { num: 9 }, SomeStruct { num: 10 }, SomeStruct { num: 11 }], - ]; - - let index_1 = 2_usize; - let index_2 = 2_usize; - - let _nested_item = arr_of_arrays_of_nums[index_1][index_2]; - let _char = arr_of_bytearrays[index_1][index_2]; - let _some_struct = arr_of_arrays_of_structs[index_1][index_2]; -} diff --git a/test_data/tests_starknet/bug_samples/issue6623.cairo b/test_data/tests_starknet/bug_samples/issue6623.cairo deleted file mode 100644 index 270cd9860e..0000000000 --- a/test_data/tests_starknet/bug_samples/issue6623.cairo +++ /dev/null @@ -1,12 +0,0 @@ -struct S { - a: u64, - b: u64, -} - -const X: S = S { b: 31, a: 252 }; - -#[test] -fn test_const() { - assert_eq!(X.a, 252); - assert_eq!(X.b, 31); -} diff --git a/test_data/tests_starknet/bug_samples/issue6755.cairo b/test_data/tests_starknet/bug_samples/issue6755.cairo deleted file mode 100644 index bdc4b63113..0000000000 --- a/test_data/tests_starknet/bug_samples/issue6755.cairo +++ /dev/null @@ -1,8 +0,0 @@ -#[test] -fn const_box_test() { - let value: Nullable = NullableTrait::new(10); - let null_value: Nullable = Default::default(); - let y = null_value.deref_or(1); - assert!(y == 1); - if value.is_null() {} else {} -} diff --git a/test_data/tests_starknet/bug_samples/issue6920.cairo b/test_data/tests_starknet/bug_samples/issue6920.cairo deleted file mode 100644 index ab01200d29..0000000000 --- a/test_data/tests_starknet/bug_samples/issue6920.cairo +++ /dev/null @@ -1,8 +0,0 @@ -#[test] -fn uninlined_closure_test() { - let uninlined_closure = || { - let a: felt252 = 256; - format!("wow such amazing calcs {a} wow such amazing calcs {a} wow such amazing calcs {a}"); - }; - let _ = uninlined_closure(); -} diff --git a/test_data/tests_starknet/bug_samples/issue6968.cairo b/test_data/tests_starknet/bug_samples/issue6968.cairo deleted file mode 100644 index a929214142..0000000000 --- a/test_data/tests_starknet/bug_samples/issue6968.cairo +++ /dev/null @@ -1,22 +0,0 @@ -extern fn array_snapshot_pop_front(ref arr: @Array) -> Option> nopanic; - -fn fn1() -> (@Array, felt252) { - let mut data: @Array = @array![0, 0x8c4fd0147, 0]; - let _ = array_snapshot_pop_front(ref data); - let elem = array_snapshot_pop_front(ref data); - - (data, *(elem.unwrap().deref())) -} - -fn fn2() -> (@Array, felt252) { - let mut data: @Array = @array![0, 0x8c4fd0147, 0]; - let _elem = array_snapshot_pop_front(ref data); - let elem = array_snapshot_pop_front(ref data); - - (data, *(elem.unwrap().deref())) -} - -#[test] -fn check_same() { - assert_eq!(fn1(), fn2()); -} diff --git a/test_data/tests_starknet/bug_samples/issue7031.cairo b/test_data/tests_starknet/bug_samples/issue7031.cairo deleted file mode 100644 index 4b432fcd1c..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7031.cairo +++ /dev/null @@ -1,25 +0,0 @@ -pub trait IteratorEx, +Destruct, +Drop> { - fn advance_by_( - ref self: T, n: usize, - ) -> Result< - (), NonZero, - > { - let mut res = Ok(()); - for i in 0..n { - if self.next().is_none() { - res = Err((n - i).try_into().unwrap()); - break; - } - } - res - } -} -impl IteratorExImpl, +Destruct, +Drop> of IteratorEx {} - -#[test] -fn test_advance_by() { - let mut iter = array![1_u8, 2, 3, 4].into_iter(); - assert_eq!(iter.advance_by_(2), Ok(())); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.advance_by_(0), Ok(())); -} diff --git a/test_data/tests_starknet/bug_samples/issue7038.cairo b/test_data/tests_starknet/bug_samples/issue7038.cairo deleted file mode 100644 index 1693a0786f..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7038.cairo +++ /dev/null @@ -1,5 +0,0 @@ -trait DefaultTraitImpl { - fn call, impl func: core::ops::FnOnce[Output: T], +Drop>(f: F) { - f(); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue7060.cairo b/test_data/tests_starknet/bug_samples/issue7060.cairo deleted file mode 100644 index fd52874b7d..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7060.cairo +++ /dev/null @@ -1,16 +0,0 @@ -pub trait WithAssociated { - type S; - fn foo<+Drop, +Drop>(self: T, s: Self::S) -> Self::S { - s - } -} - -impl Impl of WithAssociated { - type S = u8; -} - -#[test] -fn test_associated_type_usage() { - WithAssociated::foo(4, 5_u8); - 4.foo(5_u8); -} diff --git a/test_data/tests_starknet/bug_samples/issue7071.cairo b/test_data/tests_starknet/bug_samples/issue7071.cairo deleted file mode 100644 index f1911e5341..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7071.cairo +++ /dev/null @@ -1,17 +0,0 @@ -fn call_with, +core::ops::Fn[Output: usize]>(func: F) -> usize { - func(A { inner: array![] }) -} - - -#[derive(Drop)] -struct A { - inner: Array, -} - -fn main() { - let aclosure = |mut a: A| { - a.inner.append(3); - *a.inner[0] - }; - call_with(aclosure); -} diff --git a/test_data/tests_starknet/bug_samples/issue7083.cairo b/test_data/tests_starknet/bug_samples/issue7083.cairo deleted file mode 100644 index ab4f10fd0a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7083.cairo +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - let zero: ByteArray = "0"; - - let format_string = |acc: ByteArray, x: u8| { - format!("({acc} + {x})") - }; - - let result = format_string(zero, 1); - assert_eq!(result, "(0 + 1)"); -} diff --git a/test_data/tests_starknet/bug_samples/issue7095.cairo b/test_data/tests_starknet/bug_samples/issue7095.cairo deleted file mode 100644 index 3922fa7a29..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7095.cairo +++ /dev/null @@ -1,17 +0,0 @@ -trait MyTrait { - fn consume[Output: B], +Destruct>( - self: T, f: F, - ) -> B { - f(self) - } - fn user<+Destruct>(self: T) -> usize { - Self::consume(self, |_v| 1) - } -} - -impl MyImpl of MyTrait {} - -#[test] -fn test_call() { - MyTrait::::user(0); -} diff --git a/test_data/tests_starknet/bug_samples/issue7155.cairo b/test_data/tests_starknet/bug_samples/issue7155.cairo deleted file mode 100644 index 3f4c79e9b7..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7155.cairo +++ /dev/null @@ -1,13 +0,0 @@ -#[test] -fn test_enumerate_type_resolution() { - // TODO(orizi): Remove "_usize" from the next line. Currently doesn't work without it, due to - // `NumericLiteral` not auto supplying `Destruct` to a type implementing it. - for (k, v) in array![0, 1, 2_usize].into_iter().enumerate() { - assert_eq!(k, v); - } - - let mut iter = array![0, 1, 2].into_iter().enumerate(); - while let Option::Some((k, v)) = iter.next() { - assert_eq!(k, v); - } -} diff --git a/test_data/tests_starknet/bug_samples/issue7233.cairo b/test_data/tests_starknet/bug_samples/issue7233.cairo deleted file mode 100644 index 0ff6d8083a..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7233.cairo +++ /dev/null @@ -1,8 +0,0 @@ -#[test] -fn stack_overflow() { - let outer_var = 42; - let closure_annotated = |i: u32| -> u32 { - i + outer_var - }; - let _v = closure_annotated(1); -} diff --git a/test_data/tests_starknet/bug_samples/issue7234.cairo b/test_data/tests_starknet/bug_samples/issue7234.cairo deleted file mode 100644 index 97bf951ade..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7234.cairo +++ /dev/null @@ -1,33 +0,0 @@ -// A function which takes a closure as an argument and calls it. -// denotes that F is a "Generic type parameter" -fn apply, impl func: core::ops::FnOnce, +Drop>(f: F) { - // ^ TODO: Try changing this to `Fn`. - - f(); -} -#[test] -fn main() { - // A non-copy type. - let greeting: ByteArray = "hello"; - let farewell: ByteArray = "goodbye"; - - // Capture 2 variables: `greeting` by snapshot and - // `farewell` by value. - let diary = || { - // `greeting` is by snapshot: requires `Fn`. - let _ignore_greeting = format!("I said {greeting}."); - - // Using farewell by value requires `FnOnce`. - // Convert farewell to uppercase to demonstrate value capture through `into_iter` - let mut iter = farewell.into_iter(); - let uppercase: ByteArray = iter.map(|c| if c >= 'a' { - c - 32 - } else { - c - }).collect(); - let _ignore_farewell = format!("Then I screamed {uppercase}!"); - }; - - // Call the function which applies the closure. - apply(diary); -} diff --git a/test_data/tests_starknet/bug_samples/issue7544.cairo b/test_data/tests_starknet/bug_samples/issue7544.cairo deleted file mode 100644 index b61332a7ec..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7544.cairo +++ /dev/null @@ -1,12 +0,0 @@ -use core::circuit::u384; - -pub fn foo(a: u384, b: u384) -> u384 { - a -} - -#[test] -fn test_into_() { - let b = 1_u256.into(); - let a = 0_u256.into(); - let _r = foo(a, b); -} diff --git a/test_data/tests_starknet/bug_samples/issue7640.cairo b/test_data/tests_starknet/bug_samples/issue7640.cairo deleted file mode 100644 index b589dd0717..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7640.cairo +++ /dev/null @@ -1,19 +0,0 @@ -fn find_value_iterative(mut arr: Span, value: felt252) -> Option { - let mut result = None; - let mut index = 0; - - while let Some(array_value) = arr.pop_front() { - if (*array_value == value) { - return Some(index); - } - - index += 1; - } - - result -} - -#[test] -fn call_early_return() { - let _ = find_value_iterative([].span(), 0); -} diff --git a/test_data/tests_starknet/bug_samples/issue7961.cairo b/test_data/tests_starknet/bug_samples/issue7961.cairo deleted file mode 100644 index 4964823762..0000000000 --- a/test_data/tests_starknet/bug_samples/issue7961.cairo +++ /dev/null @@ -1,12 +0,0 @@ -fn outer[Output: u32], +Drop>(f: F) { - inner(|x| f(x)); // Capturing 'f' in closure causes the panic -} - -fn inner[Output: u32], +Drop>(f: F) { - f(42); -} - -#[test] -fn trigger_bug() { - outer(|x| x + 1); -} diff --git a/test_data/tests_starknet/bug_samples/issue8105.cairo b/test_data/tests_starknet/bug_samples/issue8105.cairo deleted file mode 100644 index 36cd5197fe..0000000000 --- a/test_data/tests_starknet/bug_samples/issue8105.cairo +++ /dev/null @@ -1,9 +0,0 @@ -#[test] -fn use_const_popped_value_test() -> bool { - let stack: Array = array![]; - let mut span = stack.span(); - let _ = span.pop_back(); - let actual = span.into(); - let expected = array![]; - expected == actual -} diff --git a/test_data/tests_starknet/bug_samples/lib.cairo b/test_data/tests_starknet/bug_samples/lib.cairo deleted file mode 100644 index b5039a9f2a..0000000000 --- a/test_data/tests_starknet/bug_samples/lib.cairo +++ /dev/null @@ -1,78 +0,0 @@ -mod builtin_usage_before_unreachable; -mod ecdsa_completeness; -mod generic_cycles; -mod inconsistent_gas; -mod indirect_impl_alias; -mod issue2114; -mod issue2147; -mod issue2152; -mod issue2171; -mod issue2172; -mod issue2176; -mod issue2249; -mod issue2480; -mod issue2530; -mod issue2567; -mod issue2612; -mod issue2816; -mod issue2819; -mod issue2820; -mod issue2932; -mod issue2939; -mod issue2961; -mod issue2964; -mod issue2995; -mod issue3119; -mod issue3130; -mod issue3153; -mod issue3192; -mod issue3211; -mod issue3345; -mod issue3658; -mod issue3863; -mod issue4007; -mod issue4034; -mod issue4036; -mod issue4038; -mod issue4075; -mod issue4092; -mod issue4109; -mod issue4314; -mod issue4318; -mod issue4380; -mod issue4897; -mod issue4937; -mod issue5043; -mod issue5411; -mod issue5438; -mod issue5629; -mod issue5680; -mod issue5764; -mod issue5967; -mod issue6580; -mod issue6623; -mod issue6755; -mod issue6920; -mod issue6968; -mod issue7031; -mod issue7038; -mod issue7060; -mod issue7071; -mod issue7083; -mod issue7095; -mod issue7155; -mod issue7233; -mod issue7234; -mod issue7544; -mod issue7640; -mod issue7961; -mod issue8105; -mod loop_break_in_match; -mod loop_only_change; -mod merge_const_member; -mod partial_param_local; -mod revoked_locals; -mod self_ref_non_derived; -mod specialization_cycle; -mod specialization_empty_generic; -mod zero_sized_locals; diff --git a/test_data/tests_starknet/bug_samples/loop_break_in_match.cairo b/test_data/tests_starknet/bug_samples/loop_break_in_match.cairo deleted file mode 100644 index 5efd4b8167..0000000000 --- a/test_data/tests_starknet/bug_samples/loop_break_in_match.cairo +++ /dev/null @@ -1,11 +0,0 @@ -#[test] -fn main() { - let mut a: Array = array!['a', 'b']; - - let _a = loop { - let _v: felt252 = match a.pop_front() { - Some(v) => { v }, - None => { break 'hi'; }, - }; - }; -} diff --git a/test_data/tests_starknet/bug_samples/loop_only_change.cairo b/test_data/tests_starknet/bug_samples/loop_only_change.cairo deleted file mode 100644 index c535af3e52..0000000000 --- a/test_data/tests_starknet/bug_samples/loop_only_change.cairo +++ /dev/null @@ -1,8 +0,0 @@ -#[test] -fn main() { - let mut x = 0_usize; - loop { - x = 5; - break (); - } -} diff --git a/test_data/tests_starknet/bug_samples/merge_const_member.cairo b/test_data/tests_starknet/bug_samples/merge_const_member.cairo deleted file mode 100644 index 0154fdac1b..0000000000 --- a/test_data/tests_starknet/bug_samples/merge_const_member.cairo +++ /dev/null @@ -1,44 +0,0 @@ -#[derive(Drop, Copy)] -enum Inner { - V1, - V2, -} - -#[derive(Drop, Copy)] -struct Struct { - inner: Inner, - rest: felt252, -} - -#[derive(Drop, Copy)] -enum Outer { - V1, - V2: (Inner, felt252), -} - -#[inline(never)] -fn revoke(input: felt252) { - core::internal::revoke_ap_tracking(); -} - -#[test] -fn const_with_snap() { - const outer: Outer = Outer::V1; - let mut x = 1; - match @outer { - Outer::V1 => { x += 1; }, - Outer::V2(( - inner, y, - )) => { - x += 2; - match inner { - Inner::V1 => { x += 3; }, - Inner::V2 => { x += 4; }, - } - x += *y; - }, - } - - revoke(x); -} - diff --git a/test_data/tests_starknet/bug_samples/partial_param_local.cairo b/test_data/tests_starknet/bug_samples/partial_param_local.cairo deleted file mode 100644 index ccf8f8e3c5..0000000000 --- a/test_data/tests_starknet/bug_samples/partial_param_local.cairo +++ /dev/null @@ -1,10 +0,0 @@ -struct strct { - x: felt252, -} - -#[test] -fn test_foo() -> felt252 { - let x = strct { x: 12 }.x; - core::internal::revoke_ap_tracking(); - x -} diff --git a/test_data/tests_starknet/bug_samples/revoked_locals.cairo b/test_data/tests_starknet/bug_samples/revoked_locals.cairo deleted file mode 100644 index 0339333556..0000000000 --- a/test_data/tests_starknet/bug_samples/revoked_locals.cairo +++ /dev/null @@ -1,15 +0,0 @@ -#[inline(never)] -fn use_v(v: NonZero) { - core::internal::revoke_ap_tracking(); -} - - -#[test] -fn test_revoked_local() { - let v: NonZero = match core::felt252_is_zero(16) { - core::zeroable::IsZeroResult::Zero => None, - core::zeroable::IsZeroResult::NonZero(x) => Some(x), - }.unwrap(); - use_v(v); - use_v(v); -} diff --git a/test_data/tests_starknet/bug_samples/self_ref_non_derived.cairo b/test_data/tests_starknet/bug_samples/self_ref_non_derived.cairo deleted file mode 100644 index 317f2ab000..0000000000 --- a/test_data/tests_starknet/bug_samples/self_ref_non_derived.cairo +++ /dev/null @@ -1,19 +0,0 @@ -#[test] -fn foo() -> E { - let e = E::A; - bar(@e); - e -} - -#[inline(never)] -fn bar(e: @E) nopanic { - match e { - E::R(_) => {}, - E::A => {}, - } -} - -enum E { - R: Box<@E>, - A, -} diff --git a/test_data/tests_starknet/bug_samples/specialization_cycle.cairo b/test_data/tests_starknet/bug_samples/specialization_cycle.cairo deleted file mode 100644 index 171783144c..0000000000 --- a/test_data/tests_starknet/bug_samples/specialization_cycle.cairo +++ /dev/null @@ -1,18 +0,0 @@ -// The decision whether to specialize bar triggers a cycle, the current workaround is not to -// specialize in this case. -pub fn foo(a: felt252) -> felt252 { - bar(a, 3) + bar(3, a) -} - - -pub fn bar(a: felt252, b: felt252) -> felt252 { - foo(a) + 1 -} - - -#[test] -#[available_gas(10000)] -#[should_panic(expected: 'Out of gas')] -fn call_foo() { - foo(8); -} diff --git a/test_data/tests_starknet/bug_samples/specialization_empty_generic.cairo b/test_data/tests_starknet/bug_samples/specialization_empty_generic.cairo deleted file mode 100644 index 91c0fe0a59..0000000000 --- a/test_data/tests_starknet/bug_samples/specialization_empty_generic.cairo +++ /dev/null @@ -1,19 +0,0 @@ -#[inline(never)] -pub fn drop_wrapper(t: Wrapper<()>) { - t.t -} - -fn specialized(a: felt252, t: Wrapper<()>) -> felt252 { - drop_wrapper(t); - a + 1 -} - -// The size of generic type `T` is not known. -struct Wrapper { - t: T, -} - -#[test] -fn call_specialized() { - specialized(8, Wrapper { t: () }); -} diff --git a/test_data/tests_starknet/bug_samples/zero_sized_locals.cairo b/test_data/tests_starknet/bug_samples/zero_sized_locals.cairo deleted file mode 100644 index d6745c6a46..0000000000 --- a/test_data/tests_starknet/bug_samples/zero_sized_locals.cairo +++ /dev/null @@ -1,22 +0,0 @@ -#[derive(Drop)] -struct ZeroSized {} - -#[inline(never)] -fn use_zero_sized(ref value: ZeroSized) -> felt252 { - 0 -} - -fn foo(ref value: ZeroSized, array_with_data: Array) { - if 1 == 0 { - use_zero_sized(ref value); - } - // Unknown ap change tracking, while not using `value`. - let mut data_span = array_with_data.span(); - let _a: Option>> = Serde::deserialize(ref data_span); -} - -#[test] -fn call_foo() { - let mut value = ZeroSized {}; - foo(ref value, array![0]); -} diff --git a/test_data/tests_starknet/cairo_level_tests b/test_data/tests_starknet/cairo_level_tests new file mode 120000 index 0000000000..b5ba50f7b0 --- /dev/null +++ b/test_data/tests_starknet/cairo_level_tests @@ -0,0 +1 @@ +../../vendor/cairo/crates/cairo-lang-starknet/cairo_level_tests \ No newline at end of file diff --git a/test_data/tests_starknet/cairo_level_tests/abi_dispatchers_tests.cairo b/test_data/tests_starknet/cairo_level_tests/abi_dispatchers_tests.cairo deleted file mode 100644 index 6a13155712..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/abi_dispatchers_tests.cairo +++ /dev/null @@ -1,121 +0,0 @@ -use starknet::account::Call; -use super::utils::serialized; - -#[starknet::interface] -trait IAnotherContract {} - -#[starknet::contract(account)] -mod test_contract { - use starknet::account::Call; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use starknet::{ClassHash, ContractAddress}; - use super::{IAnotherContractDispatcher, IAnotherContractLibraryDispatcher}; - - - #[storage] - struct Storage { - another: IAnotherContractDispatcher, - another_as_library: IAnotherContractLibraryDispatcher, - } - - #[external(v0)] - fn get_another_address(self: @ContractState) -> ContractAddress { - self.another.read().contract_address - } - - #[external(v0)] - fn set_another_address(ref self: ContractState, contract_address: ContractAddress) { - self.another.write(IAnotherContractDispatcher { contract_address }); - } - - #[external(v0)] - fn get_another_class_hash(self: @ContractState) -> ClassHash { - self.another_as_library.read().class_hash - } - - #[external(v0)] - fn set_another_class_hash(ref self: ContractState, class_hash: ClassHash) { - self.another_as_library.write(IAnotherContractLibraryDispatcher { class_hash }); - } - - #[external(v0)] - fn __validate__(ref self: ContractState, calls: Array) {} - #[external(v0)] - fn __execute__(ref self: ContractState, mut calls: Array) -> Array> { - array![] - } -} - -#[test] -fn test_dispatcher_serialization() { - const A: starknet::ContractAddress = 11_felt252.try_into().unwrap(); - test_contract::__external::set_another_address(serialized(A)); - assert_eq!(test_contract::__external::get_another_address(serialized(())), serialized(A)); -} - -#[test] -fn test_library_dispatcher_serialization() { - const A: starknet::ClassHash = 11_felt252.try_into().unwrap(); - test_contract::__external::set_another_class_hash(serialized(A)); - assert_eq!(test_contract::__external::get_another_class_hash(serialized(())), serialized(A)); -} - - -// Calls `withdraw_gas` and then returns the available gas. -// This is useful in a test as the `withdraw_gas` allows the gas wallet to be ~0 at the call site. -// Note that this function must be `inline(always)`. -#[inline(always)] -pub fn withdraw_and_get_available_gas() -> u128 { - core::gas::withdraw_gas().unwrap(); - core::testing::get_available_gas() -} - - -// Tests the serialization and deserialize of the arguments to `__validate__`. -#[test] -fn test_validate_gas_cost() { - const CONTRACT_ADDRESS: starknet::ContractAddress = 11_felt252.try_into().unwrap(); - let base_gas = withdraw_and_get_available_gas(); - let calls = [ - Call { - to: CONTRACT_ADDRESS, - selector: 0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c, - calldata: [ - 0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1, 0x4db5d32, 0x0, - ] - .span(), - }, - Call { - to: CONTRACT_ADDRESS, - selector: 0x2c0f7bf2d6cf5304c29171bf493feb222fef84bdaf17805a6574b0c2e8bcc87, - calldata: [ - 0x4db5d32, 0x0, 0x896ba264a31df2, 0x0, 0x2, - 0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8, - 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7, - 0x54767f773cc172172c3afc5265bd0a76089c24cdef409635d27ac1a1fa96ca8, 0x65586264, - ] - .span(), - }, - ] - .span(); - let post_call_building_gas = withdraw_and_get_available_gas(); - - let serialized_args = serialized(calls); - let post_serialization_gas = withdraw_and_get_available_gas(); - - test_contract::__external::__validate__(serialized_args); - let post_call_gas = withdraw_and_get_available_gas(); - - let call_building_gas_usage = base_gas - post_call_building_gas; - let serialization_gas_usage = post_call_building_gas - post_serialization_gas; - let entry_point_gas_usage = post_serialization_gas - post_call_gas; - assert!( - call_building_gas_usage == 3930 - && serialization_gas_usage == 27670 - && entry_point_gas_usage == 100530, - "Unexpected gas_usage: - call_building: `{call_building_gas_usage}`. - serialization: `{serialization_gas_usage}`. - entry_point: `{entry_point_gas_usage}`.", - ); -} diff --git a/test_data/tests_starknet/cairo_level_tests/cairo_project.toml b/test_data/tests_starknet/cairo_level_tests/cairo_project.toml deleted file mode 100644 index 66bbd2e7c8..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/cairo_project.toml +++ /dev/null @@ -1,5 +0,0 @@ -[crate_roots] -cairo_level_tests = "." - -[config.global] -edition = "2024_07" diff --git a/test_data/tests_starknet/cairo_level_tests/collections_test.cairo b/test_data/tests_starknet/cairo_level_tests/collections_test.cairo deleted file mode 100644 index d3c8c49c3e..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/collections_test.cairo +++ /dev/null @@ -1,128 +0,0 @@ -use starknet::storage::{ - IntoIterRange, MutableVecTrait, StoragePathEntry, StoragePointerReadAccess, - StoragePointerWriteAccess, -}; - -#[starknet::contract] -mod contract_with_map { - use starknet::storage::Map; - #[storage] - pub struct Storage { - pub simple: Map, - pub nested: Map>, - } -} - -#[starknet::contract] -mod contract_with_vec { - use starknet::storage::Vec; - #[storage] - pub struct Storage { - pub simple: Vec, - pub nested: Vec>, - } -} - -#[test] -fn test_simple_member_write_to_map() { - let mut map_contract_state = contract_with_map::contract_state_for_testing(); - let mut vec_contract_state = contract_with_vec::contract_state_for_testing(); - let vec_entry = vec_contract_state.simple.allocate(); - map_contract_state.simple.entry(0).write(1); - assert_eq!(vec_entry.read(), 1); -} - -#[test] -fn test_vec_iter() { - let mut mut_state = contract_with_vec::contract_state_for_testing(); - for i in 0..9_usize { - mut_state.simple.push(i); - } - - let state = @contract_with_vec::contract_state_for_testing(); - let mut i = 0; - for entry in state.simple.into_iter_full_range() { - assert_eq!(entry.read(), i); - i += 1; - } - assert_eq!(i, 9); - - let mut i = 2; - for entry in state.simple.into_iter_range(2..5) { - assert_eq!(entry.read(), i); - i += 1; - } - assert_eq!(i, 5); -} - -#[test] -fn test_mut_vec_iter() { - let mut mut_state = contract_with_vec::contract_state_for_testing(); - for i in 0..9_usize { - mut_state.simple.push(i); - } - - let mut i = 0; - for entry in mut_state.simple.into_iter_full_range() { - assert_eq!(entry.read(), i); - i += 1; - } - assert_eq!(i, 9); - - let mut i = 2; - for entry in mut_state.simple.into_iter_range(2..5) { - assert_eq!(entry.read(), i); - i += 1; - } - assert_eq!(i, 5); -} - -#[test] -fn test_simple_member_write_to_vec() { - let mut map_contract_state = contract_with_map::contract_state_for_testing(); - let mut vec_contract_state = contract_with_vec::contract_state_for_testing(); - vec_contract_state.simple.push(1); - assert_eq!(map_contract_state.simple.entry(0).read(), 1); -} - -#[test] -fn test_nested_member_write_to_map() { - let mut map_contract_state = contract_with_map::contract_state_for_testing(); - let mut vec_contract_state = contract_with_vec::contract_state_for_testing(); - let vec_entry = vec_contract_state.nested.allocate().allocate(); - map_contract_state.nested.entry(0).entry(0).write(1); - assert_eq!(vec_entry.read(), 1); -} - -#[test] -fn test_nested_member_write_to_vec() { - let mut map_contract_state = contract_with_map::contract_state_for_testing(); - let mut vec_contract_state = contract_with_vec::contract_state_for_testing(); - vec_contract_state.nested.allocate().push(1); - assert_eq!(map_contract_state.nested.entry(0).entry(0).read(), 1); -} - -#[test] -fn test_simple_member_push_to_vec() { - let mut state = contract_with_vec::contract_state_for_testing(); - state.simple.push(10); - state.simple.push(20); - state.simple.push(30); - assert_eq!(state.simple.len(), 3); - assert_eq!(state.simple.at(0).read(), 10); - assert_eq!(state.simple.at(1).read(), 20); - assert_eq!(state.simple.at(2).read(), 30); -} - -#[test] -fn test_simple_member_pop_from_vec() { - let mut state = contract_with_vec::contract_state_for_testing(); - state.simple.push(10); - state.simple.push(20); - state.simple.push(30); - assert_eq!(state.simple.pop(), Some(30)); - assert_eq!(state.simple.pop(), Some(20)); - assert_eq!(state.simple.pop(), Some(10)); - assert_eq!(state.simple.len(), 0); - assert_eq!(state.simple.pop(), None); -} diff --git a/test_data/tests_starknet/cairo_level_tests/component_usage_test.cairo b/test_data/tests_starknet/cairo_level_tests/component_usage_test.cairo deleted file mode 100644 index 6f0cd8bb1f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/component_usage_test.cairo +++ /dev/null @@ -1,56 +0,0 @@ -use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - -#[starknet::component] -mod comp_v0 { - #[storage] - pub struct Storage { - pub member: felt252, - } -} - -#[starknet::contract] -mod contract_v0 { - use super::comp_v0; - component!(path: comp_v0, storage: comp, event: comp); - #[storage] - pub struct Storage { - #[substorage(v0)] - pub comp: comp_v0::Storage, - } - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - comp: comp_v0::Event, - } -} - -#[starknet::storage_node] -struct ComponentNewStorage { - member: felt252, -} - -#[starknet::contract] -mod contract_new { - use super::ComponentNewStorage; - #[storage] - pub struct Storage { - #[flat] - pub comp: ComponentNewStorage, - } -} - -#[test] -fn contract_v0_write_new_read_test() { - let mut contract_state_v0 = contract_v0::contract_state_for_testing(); - let mut contract_state_new = contract_new::contract_state_for_testing(); - contract_state_v0.comp.member.write(1); - assert_eq!(contract_state_new.comp.member.read(), 1); -} - -#[test] -fn contract_new_write_v0_read_test() { - let mut contract_state_v0 = contract_v0::contract_state_for_testing(); - let mut contract_state_new = contract_new::contract_state_for_testing(); - contract_state_new.comp.member.write(2); - assert_eq!(contract_state_v0.comp.member.read(), 2); -} diff --git a/test_data/tests_starknet/cairo_level_tests/components.cairo b/test_data/tests_starknet/cairo_level_tests/components.cairo deleted file mode 100644 index 08262c1ac9..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components.cairo +++ /dev/null @@ -1,6 +0,0 @@ -pub mod erc20; -pub mod erc20_mini; -pub mod mintable; -pub mod ownable; -pub mod ownable_mini; -pub mod upgradable; diff --git a/test_data/tests_starknet/cairo_level_tests/components/erc20.cairo b/test_data/tests_starknet/cairo_level_tests/components/erc20.cairo deleted file mode 100644 index 5d43a7e091..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/erc20.cairo +++ /dev/null @@ -1,199 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -pub trait ERC20Trait { - fn get_name(self: @TCS) -> felt252; - fn get_symbol(self: @TCS) -> felt252; - fn get_decimals(self: @TCS) -> u8; - fn get_total_supply(self: @TCS) -> u256; - fn balance_of(self: @TCS, account: ContractAddress) -> u256; - fn allowance(self: @TCS, owner: ContractAddress, spender: ContractAddress) -> u256; - fn transfer(ref self: TCS, recipient: ContractAddress, amount: u256); - fn transfer_from( - ref self: TCS, sender: ContractAddress, recipient: ContractAddress, amount: u256, - ); - fn approve(ref self: TCS, spender: ContractAddress, amount: u256); - fn increase_allowance(ref self: TCS, spender: ContractAddress, added_value: u256); - fn decrease_allowance(ref self: TCS, spender: ContractAddress, subtracted_value: u256); -} - -#[starknet::component] -pub mod erc20 { - use core::num::traits::Zero; - use starknet::storage::{ - Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - use starknet::{ContractAddress, get_caller_address}; - #[storage] - pub struct Storage { - pub name: felt252, - pub symbol: felt252, - pub decimals: u8, - pub total_supply: u256, - pub balances: Map, - pub allowances: Map<(ContractAddress, ContractAddress), u256>, - } - - #[event] - #[derive(Drop, starknet::Event)] - pub enum Event { - Transfer: TransferEvent, - Approval: ApprovalEvent, - } - #[derive(Drop, starknet::Event)] - pub struct TransferEvent { - pub from: ContractAddress, - pub to: ContractAddress, - pub value: u256, - } - #[derive(Drop, starknet::Event)] - pub struct ApprovalEvent { - pub owner: ContractAddress, - pub spender: ContractAddress, - pub value: u256, - } - - #[embeddable_as(IERC20)] - pub impl ERC20Impl< - TContractState, +HasComponent, - > of super::ERC20Trait> { - fn get_name(self: @ComponentState) -> felt252 { - self.name.read() - } - - fn get_symbol(self: @ComponentState) -> felt252 { - self.symbol.read() - } - - fn get_decimals(self: @ComponentState) -> u8 { - self.decimals.read() - } - - fn get_total_supply(self: @ComponentState) -> u256 { - self.total_supply.read() - } - - fn balance_of(self: @ComponentState, account: ContractAddress) -> u256 { - self.balances.read(account) - } - - fn allowance( - self: @ComponentState, owner: ContractAddress, spender: ContractAddress, - ) -> u256 { - self.allowances.read((owner, spender)) - } - - fn transfer( - ref self: ComponentState, recipient: ContractAddress, amount: u256, - ) { - let sender = get_caller_address(); - self.transfer_helper(sender, recipient, amount); - } - - fn transfer_from( - ref self: ComponentState, - sender: ContractAddress, - recipient: ContractAddress, - amount: u256, - ) { - let caller = get_caller_address(); - self.spend_allowance(sender, caller, amount); - self.transfer_helper(sender, recipient, amount); - } - - fn approve( - ref self: ComponentState, spender: ContractAddress, amount: u256, - ) { - let caller = get_caller_address(); - self.approve_helper(caller, spender, amount); - } - - fn increase_allowance( - ref self: ComponentState, spender: ContractAddress, added_value: u256, - ) { - let caller = get_caller_address(); - self - .approve_helper( - caller, spender, self.allowances.read((caller, spender)) + added_value, - ); - } - - fn decrease_allowance( - ref self: ComponentState, - spender: ContractAddress, - subtracted_value: u256, - ) { - let caller = get_caller_address(); - self - .approve_helper( - caller, spender, self.allowances.read((caller, spender)) - subtracted_value, - ); - } - } - - #[generate_trait] - pub impl ERC20HelperImpl< - TContractState, impl X: HasComponent, - > of ERC20HelperTrait { - fn transfer_helper( - ref self: ComponentState, - sender: ContractAddress, - recipient: ContractAddress, - amount: u256, - ) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - self.balances.write(sender, self.balances.read(sender) - amount); - self.balances.write(recipient, self.balances.read(recipient) + amount); - self.emit(TransferEvent { from: sender, to: recipient, value: amount }); - } - - fn spend_allowance( - ref self: ComponentState, - owner: ContractAddress, - spender: ContractAddress, - amount: u256, - ) { - let current_allowance = self.allowances.read((owner, spender)); - let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; - let is_unlimited_allowance = current_allowance.low == ONES_MASK - && current_allowance.high == ONES_MASK; - if !is_unlimited_allowance { - self.approve_helper(owner, spender, current_allowance - amount); - } - } - - fn approve_helper( - ref self: ComponentState, - owner: ContractAddress, - spender: ContractAddress, - amount: u256, - ) { - assert(!spender.is_zero(), 'ERC20: approve from 0'); - self.allowances.write((owner, spender), amount); - self.emit(ApprovalEvent { owner, spender, value: amount }); - } - fn init( - ref self: ComponentState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.name.write(name); - self.symbol.write(symbol); - self.decimals.write(decimals); - assert(!recipient.is_zero(), 'ERC20: mint to the 0 address'); - self.total_supply.write(initial_supply); - self.balances.write(recipient, initial_supply); - self - .emit( - Event::Transfer( - TransferEvent { from: Zero::zero(), to: recipient, value: initial_supply }, - ), - ); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/components/erc20_mini.cairo b/test_data/tests_starknet/cairo_level_tests/components/erc20_mini.cairo deleted file mode 100644 index ad6e632681..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/erc20_mini.cairo +++ /dev/null @@ -1,202 +0,0 @@ -use starknet::storage::{ - StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, -}; -use starknet::{ContractAddress, get_caller_address}; - - -#[starknet::interface] -pub trait ERC20Trait { - fn get_name(self: @TCS) -> felt252; - fn get_symbol(self: @TCS) -> felt252; - fn get_decimals(self: @TCS) -> u8; - fn get_total_supply(self: @TCS) -> u256; - fn balance_of(self: @TCS, account: ContractAddress) -> u256; - fn allowance(self: @TCS, owner: ContractAddress, spender: ContractAddress) -> u256; - fn transfer(ref self: TCS, recipient: ContractAddress, amount: u256); - fn transfer_from( - ref self: TCS, sender: ContractAddress, recipient: ContractAddress, amount: u256, - ); - fn approve(ref self: TCS, spender: ContractAddress, amount: u256); - fn increase_allowance(ref self: TCS, spender: ContractAddress, added_value: u256); - fn decrease_allowance(ref self: TCS, spender: ContractAddress, subtracted_value: u256); -} - -/// A trait that, given a path to a storage, provides the storage node and mutable storage node. -pub trait HasStorage< - TContractState, - /// The storage type. - Storage, - /// The storage node. - impl StorageImpl: starknet::storage::StorageTrait, - /// The mutable storage node. - impl StorageImplMut: starknet::storage::StorageTraitMut, -> { - fn storage(self: @TContractState) -> StorageImpl::BaseType; - fn storage_mut(ref self: TContractState) -> StorageImplMut::BaseType; -} -use core::num::traits::Zero; -use starknet::storage::Map; -#[starknet::storage_node] -pub struct ERC20Storage { - pub name: felt252, - pub symbol: felt252, - pub decimals: u8, - pub total_supply: u256, - pub balances: Map, - pub allowances: Map<(ContractAddress, ContractAddress), u256>, -} - -#[derive(Drop, starknet::Event)] -pub enum Event { - Transfer: TransferEvent, - Approval: ApprovalEvent, -} -#[derive(Drop, starknet::Event)] -pub struct TransferEvent { - pub from: ContractAddress, - pub to: ContractAddress, - pub value: u256, -} -#[derive(Drop, starknet::Event)] -pub struct ApprovalEvent { - pub owner: ContractAddress, - pub spender: ContractAddress, - pub value: u256, -} - -#[starknet::embeddable] -pub impl ERC20Impl< - TContractState, - ContractStateEvent, - +HasStorage, - +Drop, - +starknet::event::EventEmitter, - +Into, -> of ERC20Trait { - fn get_name(self: @TContractState) -> felt252 { - self.storage().name.read() - } - - fn get_symbol(self: @TContractState) -> felt252 { - self.storage().symbol.read() - } - - fn get_decimals(self: @TContractState) -> u8 { - self.storage().decimals.read() - } - - fn get_total_supply(self: @TContractState) -> u256 { - self.storage().total_supply.read() - } - - fn balance_of(self: @TContractState, account: ContractAddress) -> u256 { - self.storage().balances.read(account) - } - - fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { - self.storage().allowances.read((owner, spender)) - } - - fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) { - let sender = get_caller_address(); - self.transfer_helper(sender, recipient, amount); - } - - fn transfer_from( - ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256, - ) { - let caller = get_caller_address(); - self.spend_allowance(sender, caller, amount); - self.transfer_helper(sender, recipient, amount); - } - - fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) { - let caller = get_caller_address(); - self.approve_helper(caller, spender, amount); - } - - fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: u256) { - let caller = get_caller_address(); - self - .approve_helper( - caller, spender, self.storage().allowances.read((caller, spender)) + added_value, - ); - } - - fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: u256, - ) { - let caller = get_caller_address(); - self - .approve_helper( - caller, - spender, - self.storage().allowances.read((caller, spender)) - subtracted_value, - ); - } -} - -#[generate_trait] -pub impl ERC20HelperImpl< - TContractState, - ContractStateEvent, - +HasStorage, - +Drop, - +starknet::event::EventEmitter, - +Into, -> of ERC20HelperTrait { - fn transfer_helper( - ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256, - ) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - self.storage_mut().balances.write(sender, self.storage().balances.read(sender) - amount); - self - .storage_mut() - .balances - .write(recipient, self.storage().balances.read(recipient) + amount); - self.emit(Event::Transfer(TransferEvent { from: sender, to: recipient, value: amount })); - } - - fn spend_allowance( - ref self: TContractState, owner: ContractAddress, spender: ContractAddress, amount: u256, - ) { - let current_allowance = self.storage().allowances.read((owner, spender)); - let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; - let is_unlimited_allowance = current_allowance.low == ONES_MASK - && current_allowance.high == ONES_MASK; - if !is_unlimited_allowance { - self.approve_helper(owner, spender, current_allowance - amount); - } - } - - fn approve_helper( - ref self: TContractState, owner: ContractAddress, spender: ContractAddress, amount: u256, - ) { - assert(!spender.is_zero(), 'ERC20: approve from 0'); - self.storage_mut().allowances.write((owner, spender), amount); - self.emit(Event::Approval(ApprovalEvent { owner, spender, value: amount })); - } - fn erc20_init( - ref self: TContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.storage_mut().name.write(name); - self.storage_mut().symbol.write(symbol); - self.storage_mut().decimals.write(decimals); - assert(!recipient.is_zero(), 'ERC20: mint to the 0 address'); - self.storage_mut().total_supply.write(initial_supply); - self.storage_mut().balances.write(recipient, initial_supply); - self - .emit( - Event::Transfer( - TransferEvent { from: Zero::zero(), to: recipient, value: initial_supply }, - ), - ); - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/components/mintable.cairo b/test_data/tests_starknet/cairo_level_tests/components/mintable.cairo deleted file mode 100644 index 75aec5aa05..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/mintable.cairo +++ /dev/null @@ -1,44 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -pub trait MintTrait { - fn mint(ref self: TContractState, account: ContractAddress, amount: u256); -} - -#[starknet::component] -pub mod mintable { - use core::num::traits::Zero; - use ownable_comp::OwnableHelperImpl; - use starknet::ContractAddress; - use starknet::storage::{ - StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - use crate::components::erc20::erc20 as erc20_comp; - use crate::components::ownable::ownable as ownable_comp; - - #[storage] - pub struct Storage {} - - #[embeddable_as(Mint)] - pub impl MintImpl< - TContractState, - +HasComponent, - impl Ownable: ownable_comp::HasComponent, - impl ERC20: erc20_comp::HasComponent, - +Drop, - > of super::MintTrait> { - fn mint(ref self: ComponentState, account: ContractAddress, amount: u256) { - assert(!account.is_zero(), 'ERC20: mint to the 0 address'); - get_dep_component!(@self, Ownable).validate_ownership(); - let mut erc20_component = get_dep_component_mut!(ref self, ERC20); - let total_supply = erc20_component.total_supply.read(); - erc20_component.total_supply.write(total_supply + amount); - erc20_component - .balances - .write(account, erc20_component.balances.read(account) + amount); - erc20_component - .emit(erc20_comp::TransferEvent { from: Zero::zero(), to: account, value: amount }); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/components/ownable.cairo b/test_data/tests_starknet/cairo_level_tests/components/ownable.cairo deleted file mode 100644 index de6c848cc2..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/ownable.cairo +++ /dev/null @@ -1,46 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -pub trait TransferTrait { - fn owner(self: @TContractState) -> ContractAddress; - fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress); -} - -#[starknet::component] -pub mod ownable { - use starknet::ContractAddress; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - pub struct Storage { - pub owner: ContractAddress, - } - - #[embeddable_as(Transfer)] - pub impl TransferImpl< - TContractState, impl X: HasComponent, - > of super::TransferTrait> { - fn owner(self: @ComponentState) -> ContractAddress { - self.owner.read() - } - - fn transfer_ownership( - ref self: ComponentState, new_owner: ContractAddress, - ) { - self.validate_ownership(); - self.owner.write(new_owner); - } - } - - #[generate_trait] - pub impl OwnableHelperImpl< - TContractState, impl X: HasComponent, - > of OwnableHelperTrait { - fn init_ownable(ref self: ComponentState, owner: ContractAddress) { - self.owner.write(owner); - } - fn validate_ownership(self: @ComponentState) { - assert(self.owner.read() == starknet::get_caller_address(), 'Wrong owner.'); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/components/ownable_mini.cairo b/test_data/tests_starknet/cairo_level_tests/components/ownable_mini.cairo deleted file mode 100644 index c107867d83..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/ownable_mini.cairo +++ /dev/null @@ -1,53 +0,0 @@ -use starknet::ContractAddress; -use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - -#[starknet::interface] -pub trait TransferTrait { - fn owner(self: @TContractState) -> ContractAddress; - fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress); -} - -/// A trait that, given a path to a storage, provides the storage node and mutable storage node. -pub trait HasStorage< - TContractState, - /// The storage type. - Storage, - /// The storage node. - impl Node: starknet::storage::StorageNode, - /// The mutable storage node. - impl NodeMut: starknet::storage::StorageNodeMut, -> { - fn storage(self: @TContractState) -> Node::NodeType; - fn storage_mut(ref self: TContractState) -> NodeMut::NodeType; -} - -#[starknet::storage_node] -pub struct OwnableStorage { - owner: ContractAddress, -} - -#[starknet::embeddable] -pub impl TransferImpl< - TContractState, +HasStorage, +Drop, -> of TransferTrait { - fn owner(self: @TContractState) -> ContractAddress { - self.storage().owner.read() - } - - fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress) { - self.validate_ownership(); - self.storage_mut().owner.write(new_owner); - } -} - -#[generate_trait] -pub impl OwnableHelperImpl< - TContractState, +HasStorage, +Drop, -> of OwnableHelperTrait { - fn init_ownable(ref self: TContractState, owner: ContractAddress) { - self.storage_mut().owner.write(owner); - } - fn validate_ownership(self: @TContractState) { - assert(self.storage().owner.read() == starknet::get_caller_address(), 'Wrong owner.'); - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/components/upgradable.cairo b/test_data/tests_starknet/cairo_level_tests/components/upgradable.cairo deleted file mode 100644 index 1e3e0707b3..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/components/upgradable.cairo +++ /dev/null @@ -1,41 +0,0 @@ -use starknet::ClassHash; -#[starknet::interface] -pub trait IUpgradable { - fn upgrade(ref self: TCS, new_class_hash: ClassHash); -} -#[starknet::component] -pub mod upgradable { - use ownable_comp::OwnableHelperImpl; - use starknet::ClassHash; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use starknet::syscalls::replace_class_syscall; - use crate::components::ownable::ownable as ownable_comp; - #[storage] - pub struct Storage { - pub current_implementation: ClassHash, - } - #[event] - #[derive(Drop, starknet::Event)] - pub enum Event { - ContractUpgraded: ContractUpgraded, - } - #[derive(Drop, starknet::Event)] - struct ContractUpgraded { - old_class_hash: ClassHash, - new_class_hash: ClassHash, - } - #[embeddable_as(UpgradableImpl)] - impl Upgradable< - TContractState, - +HasComponent, - impl Ownable: ownable_comp::HasComponent, - > of super::IUpgradable> { - fn upgrade(ref self: ComponentState, new_class_hash: ClassHash) { - Ownable::get_component(self.get_contract()).validate_ownership(); - replace_class_syscall(new_class_hash).unwrap(); - let old_class_hash = self.current_implementation.read(); - self.emit(ContractUpgraded { old_class_hash, new_class_hash }); - self.current_implementation.write(new_class_hash); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contract_address_test.cairo b/test_data/tests_starknet/cairo_level_tests/contract_address_test.cairo deleted file mode 100644 index f89eb28edd..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contract_address_test.cairo +++ /dev/null @@ -1,15 +0,0 @@ -use starknet::ContractAddress; - -#[test] -fn test_contract_address_ordering() { - let addr10000: ContractAddress = 0x10000.try_into().unwrap(); - let addr20000: ContractAddress = 0x20000.try_into().unwrap(); - assert!(addr10000 < addr20000); - assert!(addr10000 <= addr20000); - assert!(!(addr10000 > addr20000)); - assert!(!(addr10000 >= addr20000)); - assert!(!(addr10000 < addr10000)); - assert!(addr10000 <= addr10000); - assert!(!(addr10000 > addr10000)); - assert!(addr10000 >= addr10000); -} diff --git a/test_data/tests_starknet/cairo_level_tests/contract_tests.cairo b/test_data/tests_starknet/cairo_level_tests/contract_tests.cairo deleted file mode 100644 index 72aeabbbc3..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contract_tests.cairo +++ /dev/null @@ -1,361 +0,0 @@ -use core::num::traits::Zero; -use super::utils::serialized; - -#[starknet::interface] -trait ITestContract {} - -#[starknet::contract] -mod test_contract { - use starknet::StorageAddress; - use starknet::storage::{ - Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - - #[storage] - struct Storage { - value: felt252, - mapping: Map, - large_mapping: Map, - } - - #[external(v0)] - fn get_plus_2(self: @ContractState, a: felt252) -> felt252 { - a + 2 - } - - #[external(v0)] - fn spend_all_gas(self: @ContractState) { - spend_all_gas(self); - } - - #[external(v0)] - fn get_appended_array(self: @ContractState, mut arr: Array) -> Array { - let elem = arr.len().into(); - arr.append(elem); - arr - } - - #[external(v0)] - fn set_value(ref self: ContractState, a: felt252) { - self.value.write(a); - } - - #[external(v0)] - fn get_value(self: @ContractState) -> felt252 { - self.value.read() - } - - #[external(v0)] - fn insert(ref self: ContractState, key: u128) { - self.mapping.write(key, true) - } - - #[external(v0)] - fn remove(ref self: ContractState, key: u128) { - self.mapping.write(key, false) - } - - #[external(v0)] - fn contains(self: @ContractState, key: u128) -> bool { - self.mapping.read(key) - } - - #[external(v0)] - fn set_large(ref self: ContractState, key: u256, value: u256) { - self.large_mapping.write(key, value) - } - - #[external(v0)] - fn get_large(self: @ContractState, key: u256) -> u256 { - self.large_mapping.read(key) - } - - #[external(v0)] - fn test_storage_address( - self: @ContractState, storage_address: StorageAddress, - ) -> StorageAddress { - storage_address - } -} - -#[test] -#[should_panic] -fn test_wrapper_not_enough_args() { - test_contract::__external::get_plus_2(serialized(())); -} - -#[test] -#[should_panic] -fn test_wrapper_too_many_args() { - test_contract::__external::get_plus_2(serialized((1, 2))); -} - -#[test] -fn test_wrapper_valid_args() { - assert_eq!(test_contract::__external::get_plus_2(serialized(1)), serialized(3)); -} - -#[test] -#[available_gas(20000)] -#[should_panic] -fn test_wrapper_valid_args_out_of_gas() { - test_contract::__external::spend_all_gas(serialized(())); -} - -#[test] -fn test_wrapper_array_arg_and_output() { - assert_eq!( - test_contract::__external::get_appended_array(serialized(array![2])), - serialized(array![2, 1]), - ); -} - -#[test] -fn read_first_value() { - assert_eq!(test_contract::__external::get_value(serialized(())), serialized(0)); -} - -#[test] -fn write_read_value() { - assert(test_contract::__external::set_value(serialized(4)).is_empty(), 'Not empty'); - assert_eq!(test_contract::__external::get_value(serialized(())), serialized(4)); -} - -#[test] -fn empty_start() { - assert_eq!(test_contract::__external::contains(serialized(4)), serialized(0)); -} - -#[test] -fn contains_added() { - assert(test_contract::__external::insert(serialized(4)).is_empty(), 'Not empty'); - assert_eq!(test_contract::__external::contains(serialized(4)), serialized(1)); - assert_eq!(test_contract::__external::contains(serialized(5)), serialized(0)); -} - -#[test] -fn not_contains_removed() { - assert(test_contract::__external::insert(serialized(4)).is_empty(), 'Not empty'); - assert(test_contract::__external::remove(serialized(4)).is_empty(), 'Not empty'); - assert_eq!(test_contract::__external::contains(serialized(4)), serialized(0)); -} - -#[test] -fn read_large_first_value() { - assert_eq!( - test_contract::__external::get_large(serialized(0x200000000000000000000000000000001_u256)), - serialized(0_u256), - ); -} - -#[test] -fn write_read_large_value() { - assert( - test_contract::__external::set_large( - serialized( - ( - 0x200000000000000000000000000000001_u256, - 0x400000000000000000000000000000003_u256, - ), - ), - ) - .is_empty(), - 'Array not empty', - ); - assert_eq!( - test_contract::__external::get_large(serialized(0x200000000000000000000000000000001_u256)), - serialized(0x400000000000000000000000000000003_u256), - ); -} - -#[test] -fn test_get_block_info() { - let info = starknet::get_block_info().unbox(); - assert_eq!(info.block_number, 0_u64); - assert_eq!(info.block_timestamp, 0_u64); - assert(info.sequencer_address.is_zero(), 'non default sequencer_address'); - starknet::testing::set_block_number(1_u64); - starknet::testing::set_block_timestamp(2_u64); - starknet::testing::set_sequencer_address(3_felt252.try_into().unwrap()); - let info = starknet::get_block_info().unbox(); - assert_eq!(info.block_number, 1_u64); - assert_eq!(info.block_timestamp, 2_u64); - assert_eq!(info.sequencer_address.into(), 3); -} - -#[test] -fn test_get_caller_address() { - assert(starknet::get_caller_address().is_zero(), 'non default value'); - starknet::testing::set_caller_address(1_felt252.try_into().unwrap()); - assert_eq!(starknet::get_caller_address().into(), 1); -} - -#[test] -fn test_get_contract_address() { - assert(starknet::get_contract_address().is_zero(), 'non default value'); - starknet::testing::set_contract_address(1_felt252.try_into().unwrap()); - assert_eq!(starknet::get_contract_address().into(), 1); -} - -#[test] -fn test_get_version() { - assert(starknet::get_tx_info().unbox().version.is_zero(), 'non default value'); - starknet::testing::set_version(1); - assert_eq!(starknet::get_tx_info().unbox().version, 1_felt252); -} - -#[test] -fn test_get_account_contract_address() { - assert(starknet::get_tx_info().unbox().account_contract_address.is_zero(), 'non default value'); - starknet::testing::set_account_contract_address(1_felt252.try_into().unwrap()); - assert_eq!(starknet::get_tx_info().unbox().account_contract_address.into(), 1); -} - -#[test] -fn test_get_max_fee() { - assert_eq!(starknet::get_tx_info().unbox().max_fee, 0_u128); - starknet::testing::set_max_fee(1); - assert_eq!(starknet::get_tx_info().unbox().max_fee, 1_u128); -} - -#[test] -fn test_get_transaction_hash() { - assert(starknet::get_tx_info().unbox().transaction_hash.is_zero(), 'non default value'); - starknet::testing::set_transaction_hash(1); - assert_eq!(starknet::get_tx_info().unbox().transaction_hash, 1_felt252); -} - -#[test] -fn test_get_chain_id() { - assert(starknet::get_tx_info().unbox().chain_id.is_zero(), 'non default value'); - starknet::testing::set_chain_id(1); - assert_eq!(starknet::get_tx_info().unbox().chain_id, 1_felt252); -} - -#[test] -fn test_get_nonce() { - assert(starknet::get_tx_info().unbox().nonce.is_zero(), 'non default value'); - starknet::testing::set_nonce(1); - assert_eq!(starknet::get_tx_info().unbox().nonce, 1_felt252); -} - -#[test] -fn test_get_signature() { - assert(starknet::get_tx_info().unbox().signature.is_empty(), 'non default value'); - starknet::testing::set_signature(array!['some', 'signature'].span()); - let read_signature = starknet::get_tx_info().unbox().signature; - assert_eq!(read_signature.len(), 2); - assert_eq!(read_signature.at(0), @'some'); - assert_eq!(read_signature.at(1), @'signature'); -} - -#[test] -fn test_get_block_hash() { - assert!( - starknet::syscalls::get_block_hash_syscall(1337) == Err(array!['GET_BLOCK_HASH_NOT_SET']), - ); - starknet::testing::set_block_hash(1337, 'some-value'); - assert!(starknet::syscalls::get_block_hash_syscall(1337) == Ok('some-value')); - assert!( - starknet::syscalls::get_block_hash_syscall(1338) == Err(array!['GET_BLOCK_HASH_NOT_SET']), - ); -} - -#[test] -#[should_panic] -fn test_pop_log_empty_logs() { - starknet::testing::pop_log_raw(0x1234_felt252.try_into().unwrap()).unwrap(); -} - -#[test] -#[should_panic] -fn test_pop_l2_to_l1_message_empty_messages() { - starknet::testing::pop_l2_to_l1_message(0x1234_felt252.try_into().unwrap()).unwrap(); -} - -#[test] -#[should_panic] -fn test_out_of_range_storage_address_from_felt252() -> starknet::StorageAddress { - (-1).try_into().unwrap() -} - -#[test] -fn test_storage_address() { - let mut args = array![0x17]; - let _storage_address: starknet::StorageAddress = 0x17.try_into().unwrap(); - let ret_data = test_contract::__external::test_storage_address(args.span()); - - assert_eq!(args[0_u32], ret_data[0_u32]); -} - -#[derive(starknet::Event, PartialEq, Drop, Clone, Serde, Debug)] -struct A { - x: felt252, - #[key] - data: usize, -} - -#[derive(starknet::Event, PartialEq, Drop, Clone, Serde, Debug)] -struct B { - x: felt252, -} - -#[derive(starknet::Event, PartialEq, Drop, Clone, Debug)] -enum MyEventEnum { - A: A, - B: B, -} - -fn event_serde_tester< - T, +starknet::Event, +Clone, +PartialEq, +Drop, +core::fmt::Debug, ->( - event: T, -) { - let original_event = event.clone(); - let mut keys = Default::default(); - let mut data = Default::default(); - event.append_keys_and_data(ref keys, ref data); - let mut keys = keys.span(); - let mut data = data.span(); - let mut event = starknet::Event::deserialize(ref keys, ref data).unwrap(); - assert_eq!(event, original_event); -} - -#[test] -fn test_event_serde() { - let event = A { x: 0x17, data: 2 }; - event_serde_tester(event.clone()); - let event = MyEventEnum::A(event); - event_serde_tester(event.clone()); -} - -#[test] -fn test_dispatcher_serde() { - // Contract Dispatcher - const CONTRACT_ADDRESS: starknet::ContractAddress = 0x1234_felt252.try_into().unwrap(); - let contract0 = ITestContractDispatcher { contract_address: CONTRACT_ADDRESS }; - - // Serialize - let mut calldata = Default::default(); - Serde::serialize(@contract0, ref calldata); - assert!(calldata == array![CONTRACT_ADDRESS.into()]); - - // Deserialize - let mut serialized = calldata.span(); - let contract0: ITestContractDispatcher = Serde::deserialize(ref serialized).unwrap(); - assert(contract0.contract_address == CONTRACT_ADDRESS, 'Deserialize to Dispatcher'); - - // Library Dispatcher - let contract1 = ITestContractLibraryDispatcher { class_hash: test_contract::TEST_CLASS_HASH }; - - // Serialize - let mut calldata = Default::default(); - Serde::serialize(@contract1, ref calldata); - assert!(calldata == array![test_contract::TEST_CLASS_HASH.into()]); - - // Deserialize - let mut serialized = calldata.span(); - let contract1: ITestContractLibraryDispatcher = Serde::deserialize(ref serialized).unwrap(); - assert!(contract1.class_hash == test_contract::TEST_CLASS_HASH); -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts.cairo b/test_data/tests_starknet/cairo_level_tests/contracts.cairo deleted file mode 100644 index 39160e5b25..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts.cairo +++ /dev/null @@ -1,18 +0,0 @@ -mod account; -mod circuit_contract; -pub mod erc20; -mod hello_starknet; -mod libfuncs_coverage; -mod minimal_contract; -mod mintable; -pub mod multi_component; -mod new_syntax_test_contract; -mod ownable_erc20; -mod storage_accesses; -pub mod test_contract; -mod token_bridge; -mod upgradable_counter; -mod with_erc20; -mod with_erc20_mini; -mod with_ownable; -mod with_ownable_mini; diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/account.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/account.cairo deleted file mode 100644 index 260d290440..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/account.cairo +++ /dev/null @@ -1,92 +0,0 @@ -#[starknet::contract(account)] -mod account { - use core::ecdsa::check_ecdsa_signature; - use core::num::traits::Zero; - use starknet::SyscallResultTrait; - use starknet::account::Call; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use starknet::syscalls::call_contract_syscall; - - #[storage] - struct Storage { - public_key: felt252, - } - - #[constructor] - fn constructor(ref self: ContractState, public_key_: felt252) { - self.public_key.write(public_key_); - } - - trait StorageTrait { - fn validate_transaction(self: @ContractState) -> felt252; - } - impl StorageImpl of StorageTrait { - fn validate_transaction(self: @ContractState) -> felt252 { - let tx_info = starknet::get_tx_info().unbox(); - let signature = tx_info.signature; - assert(signature.len() == 2_u32, 'INVALID_SIGNATURE_LENGTH'); - assert( - check_ecdsa_signature( - message_hash: tx_info.transaction_hash, - public_key: self.public_key.read(), - signature_r: *signature[0_u32], - signature_s: *signature[1_u32], - ), - 'INVALID_SIGNATURE', - ); - - starknet::VALIDATED - } - } - - - #[external(v0)] - fn __validate_deploy__( - self: @ContractState, - class_hash: felt252, - contract_address_salt: felt252, - public_key_: felt252, - ) -> felt252 { - self.validate_transaction() - } - - #[abi(embed_v0)] - impl AccountContractImpl of starknet::account::AccountContract { - fn __validate_declare__(self: @ContractState, class_hash: felt252) -> felt252 { - self.validate_transaction() - } - - fn __validate__(ref self: ContractState, calls: Array) -> felt252 { - self.validate_transaction() - } - - fn __execute__(ref self: ContractState, mut calls: Array) -> Array> { - // Validate caller. - assert(starknet::get_caller_address().is_zero(), 'INVALID_CALLER'); - - // Check the tx version here, since version 0 transaction skip the __validate__ - // function. - let tx_info = starknet::get_tx_info().unbox(); - assert(tx_info.version != 0, 'INVALID_TX_VERSION'); - - let mut result = ArrayTrait::new(); - loop { - match calls.pop_front() { - Some(call) => { - let mut res = call_contract_syscall( - address: call.to, - entry_point_selector: call.selector, - calldata: call.calldata, - ) - .unwrap_syscall(); - result.append(res); - }, - None => { - break; // Can't break result; because of 'variable was previously moved' - }, - } - } - result - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/circuit_contract.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/circuit_contract.cairo deleted file mode 100644 index 5e42fb783f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/circuit_contract.cairo +++ /dev/null @@ -1,41 +0,0 @@ -#[starknet::contract] -mod circuit_contract { - use core::circuit::{ - AddInputResultTrait, CircuitElement, CircuitInput, CircuitInputs, CircuitModulus, - EvalCircuitTrait, circuit_add, circuit_inverse, - }; - - #[storage] - struct Storage {} - - - /// An external method that requires the `AddMod`, `MulMod` and `RangeCheck96` builtins. - #[external(v0)] - fn circuit_builtins(ref self: ContractState) { - let in1 = CircuitElement::> {}; - let in2 = CircuitElement::> {}; - let add = circuit_add(in1, in2); - // Making the type much larger. - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let add = circuit_add(add, add); - let inv = circuit_inverse(add); - - let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap(); - let _outputs = - match (inv,).new_inputs().next([3, 0, 0, 0]).next([6, 0, 0, 0]).done().eval(modulus) { - Ok(outputs) => { outputs }, - Err(_) => { panic!("Expected success") }, - }; - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/erc20.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/erc20.cairo deleted file mode 100644 index 8c3c796bd4..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/erc20.cairo +++ /dev/null @@ -1,188 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -pub trait IERC20 { - fn get_name(self: @TContractState) -> felt252; - fn get_symbol(self: @TContractState) -> felt252; - fn get_decimals(self: @TContractState) -> u8; - fn get_total_supply(self: @TContractState) -> u256; - fn balance_of(self: @TContractState, account: ContractAddress) -> u256; - fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; - fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256); - fn transfer_from( - ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256, - ); - fn approve(ref self: TContractState, spender: ContractAddress, amount: u256); - fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: u256); - fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: u256, - ); -} - -#[starknet::contract] -pub mod erc_20 { - use core::num::traits::Zero; - use starknet::storage::{ - Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - use starknet::{ContractAddress, get_caller_address}; - - #[storage] - struct Storage { - name: felt252, - symbol: felt252, - decimals: u8, - total_supply: u256, - balances: Map, - allowances: Map<(ContractAddress, ContractAddress), u256>, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - Transfer: Transfer, - Approval: Approval, - } - #[derive(Drop, starknet::Event)] - struct Transfer { - from: ContractAddress, - to: ContractAddress, - value: u256, - } - #[derive(Drop, starknet::Event)] - struct Approval { - owner: ContractAddress, - spender: ContractAddress, - value: u256, - } - - #[constructor] - fn constructor( - ref self: ContractState, - name_: felt252, - symbol_: felt252, - decimals_: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.name.write(name_); - self.symbol.write(symbol_); - self.decimals.write(decimals_); - assert(!recipient.is_zero(), 'ERC20: mint to the 0 address'); - self.total_supply.write(initial_supply); - self.balances.write(recipient, initial_supply); - self - .emit( - Event::Transfer( - Transfer { from: Zero::zero(), to: recipient, value: initial_supply }, - ), - ); - } - - #[abi(embed_v0)] - pub impl IERC20Impl of super::IERC20 { - fn get_name(self: @ContractState) -> felt252 { - self.name.read() - } - - fn get_symbol(self: @ContractState) -> felt252 { - self.symbol.read() - } - - fn get_decimals(self: @ContractState) -> u8 { - self.decimals.read() - } - - fn get_total_supply(self: @ContractState) -> u256 { - self.total_supply.read() - } - - fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - self.balances.read(account) - } - - fn allowance( - self: @ContractState, owner: ContractAddress, spender: ContractAddress, - ) -> u256 { - self.allowances.read((owner, spender)) - } - - fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) { - let sender = get_caller_address(); - self.transfer_helper(sender, recipient, amount); - } - - fn transfer_from( - ref self: ContractState, - sender: ContractAddress, - recipient: ContractAddress, - amount: u256, - ) { - let caller = get_caller_address(); - self.spend_allowance(sender, caller, amount); - self.transfer_helper(sender, recipient, amount); - } - - fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) { - let caller = get_caller_address(); - self.approve_helper(caller, spender, amount); - } - - fn increase_allowance( - ref self: ContractState, spender: ContractAddress, added_value: u256, - ) { - let caller = get_caller_address(); - self - .approve_helper( - caller, spender, self.allowances.read((caller, spender)) + added_value, - ); - } - - fn decrease_allowance( - ref self: ContractState, spender: ContractAddress, subtracted_value: u256, - ) { - let caller = get_caller_address(); - self - .approve_helper( - caller, spender, self.allowances.read((caller, spender)) - subtracted_value, - ); - } - } - - #[generate_trait] - impl StorageImpl of StorageTrait { - fn transfer_helper( - ref self: ContractState, - sender: ContractAddress, - recipient: ContractAddress, - amount: u256, - ) { - assert(!sender.is_zero(), 'ERC20: transfer from 0'); - assert(!recipient.is_zero(), 'ERC20: transfer to 0'); - self.balances.write(sender, self.balances.read(sender) - amount); - self.balances.write(recipient, self.balances.read(recipient) + amount); - self.emit(Transfer { from: sender, to: recipient, value: amount }); - } - - fn spend_allowance( - ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256, - ) { - let current_allowance = self.allowances.read((owner, spender)); - let ONES_MASK = 0xffffffffffffffffffffffffffffffff_u128; - let is_unlimited_allowance = current_allowance.low == ONES_MASK - && current_allowance.high == ONES_MASK; - if !is_unlimited_allowance { - self.approve_helper(owner, spender, current_allowance - amount); - } - } - - fn approve_helper( - ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256, - ) { - assert(!spender.is_zero(), 'ERC20: approve from 0'); - self.allowances.write((owner, spender), amount); - self.emit(Approval { owner, spender, value: amount }); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/hello_starknet.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/hello_starknet.cairo deleted file mode 100644 index 1d512a3e7b..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/hello_starknet.cairo +++ /dev/null @@ -1,27 +0,0 @@ -#[starknet::interface] -trait HelloStarknetTrait { - // Increases the balance by the given amount. - fn increase_balance(ref self: TContractState, amount: usize); - // Returns the current balance. - fn get_balance(self: @TContractState) -> usize; -} - -#[starknet::contract] -mod hello_starknet { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - #[storage] - struct Storage { - balance: usize, - } - - #[abi(embed_v0)] - impl HelloStarknetImpl of super::HelloStarknetTrait { - fn increase_balance(ref self: ContractState, amount: usize) { - self.balance.write(self.balance.read() + amount); - } - fn get_balance(self: @ContractState) -> usize { - self.balance.read() - } - } -} - diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/libfuncs_coverage.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/libfuncs_coverage.cairo deleted file mode 100644 index 596ee334a6..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/libfuncs_coverage.cairo +++ /dev/null @@ -1,584 +0,0 @@ -use core::dict::{Felt252Dict, Felt252DictEntryTrait}; -use core::num::traits::One; -use starknet::storage::{StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess}; - -#[starknet::contract] -mod libfuncs_coverage { - #[storage] - struct Storage {} - - #[abi(per_item)] - #[generate_trait] - impl Impl of Trait { - #[external(v0)] - fn entry_point(ref self: ContractState) { - super::all_libfuncs(super::Libfuncs::None) - } - } -} - -enum Libfuncs { - None, - U8: UnsignedIntLibfuncs, - U16: UnsignedIntLibfuncs, - U32: UnsignedIntLibfuncs, - U64: UnsignedIntLibfuncs, - U128: UnsignedIntLibfuncs, - U256: UnsignedIntLibfuncs, - I8: IntLibfuncs, - I16: IntLibfuncs, - I32: IntLibfuncs, - I64: IntLibfuncs, - I128: IntLibfuncs, - Bool: BitwiseLibfuncs, - Felt252: Felt252Libfuncs, - Conversions: ConversionsLibfuncs, - Ec: EcLibfuncs, - Sha256: ByteArray, - ArrayU128: ArrayLibfuncs, - ArrayU256: ArrayLibfuncs, - DictU128: DictLibfuncs, - DictFelt252: DictLibfuncs, - DictNullable: DictLibfuncs>, - NullableFelt252: NullableLibfuncs, - NullableU256: NullableLibfuncs, - NullableNonCopy: NullableLibfuncs>, - Circuit: (u384, u384, u384), - IsValidSignature: (u256, Signature, starknet::EthAddress), - Secp256R1: (u256, u256, u256, u256), - Starknet: StarknetLibfuncs, - Consts: ConstsLibfuncs, - Snapshot: SnapshotLibfuncs, - RangeIter: (u8, u8), -} - -enum NumericLibfuncs { - Add: (T, T), - Sub: (T, T), - Mul: (T, T), - Equal: (T, T), -} - -enum IntLibfuncs { - Div: (T, T), - Mod: (T, T), - Lt: (T, T), - Inc: T, - Dec: T, - Numeric: NumericLibfuncs, -} - -enum UnsignedIntLibfuncs { - Sqrt: T, - Bitwise: BitwiseLibfuncs, - Int: IntLibfuncs, -} - -enum BitwiseLibfuncs { - And: (T, T), - Or: (T, T), - Xor: (T, T), -} - -enum Felt252Libfuncs { - Div: (felt252, NonZero), - Numeric: NumericLibfuncs, -} - -enum ConversionsLibfuncs { - Into: IntoLibfuncs, - Felt252TryInto: Felt252TryIntoLibfuncs, -} - -enum IntoLibfuncs { - U8Felt252: u8, - U16Felt252: u16, - U32Felt252: u32, - U64Felt252: u64, - U128Felt252: u128, - I8Felt252: i8, - I16Felt252: i16, - I32Felt252: i32, - I64Felt252: i64, - I128Felt252: i128, - BoolFelt252: bool, - Felt252U256: felt252, - U256U384: u256, - ContractAddressFelt252: starknet::ContractAddress, - ClassHashFelt252: starknet::ClassHash, - StorageAddressFelt252: starknet::StorageAddress, -} - -enum Felt252TryIntoLibfuncs { - U8: felt252, - U16: felt252, - U32: felt252, - U64: felt252, - U128: felt252, - I8: felt252, - I16: felt252, - I32: felt252, - I64: felt252, - I128: felt252, - Bytes31: felt252, - ContractAddress: felt252, - ClassHash: felt252, - StorageAddress: felt252, -} - -enum EcLibfuncs { - PointNewNz: (felt252, felt252), - PointNewNzFromX: felt252, - PointCoordinates: NonZero, - PointNeg: core::ec::EcPoint, - StateUsage: core::ec::EcPoint, -} - -enum ArrayLibfuncs { - New, - Append: (Array, T), - PopFront: Array, - PopFrontConsume: Array, - Get: (@Array, usize), - Len: @Array, - SnapPopFront: Span, - SnapPopBack: Span, - MultiPopFront: Span, - MultiPopBack: Span, - Slice: Span, - SpanFromBox: Box<@[T; 5]>, - BoxFromSpan: Span, -} - -enum DictLibfuncs { - Default, - EntryGet: (Felt252Dict, felt252), -} - -enum NullableLibfuncs { - Default, - New: T, - IsNull: @Nullable, - Deref: Nullable, -} - -enum StarknetLibfuncs { - LibraryCall: starknet::ClassHash, - ContractCall: starknet::ContractAddress, - StorageRead: starknet::storage::StorageBase>, - StorageWrite: starknet::storage::StorageBase>, - Deploy: (starknet::ClassHash, felt252, Span, bool), - EmitEvent: (Span, Span), - GetBlockHash: u64, - GetExecutionInfo, - GetExecutionInfoV2, - ReplaceClass: starknet::ClassHash, - SendMessageToL1: (felt252, Span), - GetClassHashAt: starknet::ContractAddress, - MetaTxV0: (starknet::ContractAddress, felt252, Span, Span), -} - -enum ConstsLibfuncs { - Felt252, - U8, - U16, - U32, - U64, - U128, - I8, - I16, - I32, - I64, - I128, - Byte31, - StorageBase, - ClassHash, - ContractAddress, -} - -enum SnapshotLibfuncs { - BoxForward: @Box>, - Match: @Option>, -} - -#[inline(never)] -fn all_libfuncs(libfuncs: Libfuncs) { - match libfuncs { - Libfuncs::None => {}, - Libfuncs::U8(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::U16(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::U32(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::U64(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::U128(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::U256(libfuncs) => unsigned_int_libfuncs(libfuncs), - Libfuncs::I8(libfuncs) => int_libfuncs(libfuncs), - Libfuncs::I16(libfuncs) => int_libfuncs(libfuncs), - Libfuncs::I32(libfuncs) => int_libfuncs(libfuncs), - Libfuncs::I64(libfuncs) => int_libfuncs(libfuncs), - Libfuncs::I128(libfuncs) => int_libfuncs(libfuncs), - Libfuncs::Bool(libfuncs) => bitwise_libfuncs(libfuncs), - Libfuncs::Felt252(libfuncs) => felt252_libfuncs(libfuncs), - Libfuncs::Conversions(libfuncs) => conversions_libfuncs(libfuncs), - Libfuncs::Ec(libfuncs) => ec_libfuncs(libfuncs), - Libfuncs::Sha256(input) => use_and_panic(core::sha256::compute_sha256_byte_array(@input)), - Libfuncs::ArrayU128(libfuncs) => array_libfuncs(libfuncs), - Libfuncs::ArrayU256(libfuncs) => array_libfuncs(libfuncs), - Libfuncs::DictU128(libfuncs) => dict_libfuncs(libfuncs), - Libfuncs::DictFelt252(libfuncs) => dict_libfuncs(libfuncs), - Libfuncs::DictNullable(libfuncs) => dict_libfuncs(libfuncs), - Libfuncs::NullableFelt252(libfuncs) => nullable_libfuncs(libfuncs), - Libfuncs::NullableU256(libfuncs) => nullable_libfuncs(libfuncs), - Libfuncs::NullableNonCopy(libfuncs) => nullable_libfuncs(libfuncs), - Libfuncs::Circuit((n, in1, in2)) => circuit_libfuncs(n, in1, in2), - Libfuncs::IsValidSignature(( - msg_hash, signature, eth_address, - )) => starknet::eth_signature::verify_eth_signature(msg_hash, signature, eth_address), - Libfuncs::Secp256R1(sign) => secp_libfuncs::(sign), - Libfuncs::Starknet(libfuncs) => starknet_libfuncs(libfuncs), - Libfuncs::Consts(libfuncs) => consts_libfuncs(libfuncs), - Libfuncs::Snapshot(libfuncs) => snapshot_libfuncs(libfuncs), - Libfuncs::RangeIter((s, e)) => { for _ in s..e {} }, - } -} -use core::num::traits::Sqrt; -use core::traits::{BitAnd, BitOr, BitXor}; - -fn unsigned_int_libfuncs< - T, - impl TSqrt: Sqrt, - +Drop, - +BitAnd, - +BitOr, - +BitXor, - +Div, - +Rem, - +PartialOrd, - +Add, - +Sub, - +Mul, - +PartialEq, - +Copy, - +Drop, - impl One: One, ->( - libfuncs: UnsignedIntLibfuncs, -) { - match libfuncs { - UnsignedIntLibfuncs::Sqrt(a) => use_and_panic(Sqrt::sqrt(a)), - UnsignedIntLibfuncs::Bitwise(libfuncs) => bitwise_libfuncs(libfuncs), - UnsignedIntLibfuncs::Int(libfuncs) => int_libfuncs(libfuncs), - } -} - -fn int_libfuncs< - T, - +Div, - +Rem, - +PartialOrd, - +Add, - +Sub, - +Mul, - +PartialEq, - +Drop, - impl One: One, ->( - libfuncs: IntLibfuncs, -) { - match libfuncs { - IntLibfuncs::Div((a, b)) => use_and_panic(a / b), - IntLibfuncs::Mod((a, b)) => use_and_panic(a % b), - IntLibfuncs::Lt((a, b)) => use_and_panic(a < b), - IntLibfuncs::Inc(a) => use_and_panic(a + One::one()), - IntLibfuncs::Dec(a) => use_and_panic(a - One::one()), - IntLibfuncs::Numeric(libfuncs) => numeric_libfuncs(libfuncs), - } -} - -fn felt252_libfuncs(libfuncs: Felt252Libfuncs) { - match libfuncs { - Felt252Libfuncs::Div((a, b)) => use_and_panic(core::felt252_div(a, b)), - Felt252Libfuncs::Numeric(libfuncs) => numeric_libfuncs(libfuncs), - } -} - -fn numeric_libfuncs, +Sub, +Mul, +PartialEq, +Drop>( - libfuncs: NumericLibfuncs, -) { - match libfuncs { - NumericLibfuncs::Add((a, b)) => use_and_panic(a + b), - NumericLibfuncs::Sub((a, b)) => use_and_panic(a - b), - NumericLibfuncs::Mul((a, b)) => use_and_panic(a * b), - NumericLibfuncs::Equal((a, b)) => use_and_panic(a == b), - } -} - -fn bitwise_libfuncs, +BitOr, +BitXor, +Drop>(libfuncs: BitwiseLibfuncs) { - match libfuncs { - BitwiseLibfuncs::And((a, b)) => use_and_panic(a & b), - BitwiseLibfuncs::Or((a, b)) => use_and_panic(a | b), - BitwiseLibfuncs::Xor((a, b)) => use_and_panic(a ^ b), - } -} - -fn conversions_libfuncs(libfuncs: ConversionsLibfuncs) { - match libfuncs { - ConversionsLibfuncs::Into(libfuncs) => into_libfuncs(libfuncs), - ConversionsLibfuncs::Felt252TryInto(libfuncs) => felt252_try_into_libfuncs(libfuncs), - } -} - -fn into_libfuncs(libfuncs: IntoLibfuncs) { - match libfuncs { - IntoLibfuncs::U8Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::U16Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::U32Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::U64Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::U128Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::I8Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::I16Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::I32Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::I64Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::I128Felt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::BoolFelt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::Felt252U256(v) => use_and_panic::(v.into()), - IntoLibfuncs::U256U384(v) => use_and_panic::(v.into()), - IntoLibfuncs::ContractAddressFelt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::ClassHashFelt252(v) => use_and_panic::(v.into()), - IntoLibfuncs::StorageAddressFelt252(v) => use_and_panic::(v.into()), - } -} - -fn felt252_try_into_libfuncs(libfuncs: Felt252TryIntoLibfuncs) { - match libfuncs { - Felt252TryIntoLibfuncs::U8(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::U16(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::U32(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::U64(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::U128(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::I8(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::I16(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::I32(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::I64(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::I128(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::Bytes31(v) => use_and_panic::>(v.try_into()), - Felt252TryIntoLibfuncs::ContractAddress(v) => use_and_panic::< - Option, - >(v.try_into()), - Felt252TryIntoLibfuncs::ClassHash(v) => use_and_panic::< - Option, - >(v.try_into()), - Felt252TryIntoLibfuncs::StorageAddress(v) => use_and_panic::< - Option, - >(v.try_into()), - } -} -use core::ec::{EcPointTrait, EcStateTrait}; - -fn ec_libfuncs(libfuncs: EcLibfuncs) { - match libfuncs { - EcLibfuncs::PointNewNz((x, y)) => use_and_panic(EcPointTrait::new_nz(x, y)), - EcLibfuncs::PointNewNzFromX(x) => use_and_panic(EcPointTrait::new_from_x(x)), - EcLibfuncs::PointCoordinates(p) => use_and_panic(p.coordinates()), - EcLibfuncs::PointNeg(p) => use_and_panic(-p), - EcLibfuncs::StateUsage(p) => use_and_panic( - { - let mut state = EcStateTrait::init(); - let p = p.try_into().unwrap(); - state.add(p); - state.add_mul(5, p); - state.finalize() - }, - ), - } -} - -fn array_libfuncs, impl BoxFromSpan: TryInto, @Box<[T; 5]>>>( - libfuncs: ArrayLibfuncs, -) { - match libfuncs { - ArrayLibfuncs::New => use_and_panic(ArrayTrait::::new()), - ArrayLibfuncs::Append((mut array, item)) => use_and_panic(array.append(item)), - ArrayLibfuncs::PopFront(mut array) => use_and_panic_drop(array.pop_front()), - ArrayLibfuncs::PopFrontConsume(array) => use_and_panic_drop(array.pop_front_consume()), - ArrayLibfuncs::Get((array, index)) => use_and_panic_drop(array.get(index)), - ArrayLibfuncs::Len(array) => use_and_panic(array.len()), - ArrayLibfuncs::SnapPopFront(mut span) => use_and_panic_drop(span.pop_front()), - ArrayLibfuncs::SnapPopBack(mut span) => use_and_panic_drop(span.pop_back()), - ArrayLibfuncs::MultiPopFront(mut span) => use_and_panic_drop(span.multi_pop_front::<5>()), - ArrayLibfuncs::MultiPopBack(mut span) => use_and_panic_drop(span.multi_pop_back::<5>()), - ArrayLibfuncs::Slice(span) => use_and_panic(span.slice(2, 5)), - ArrayLibfuncs::SpanFromBox(box) => use_and_panic(box.span()), - ArrayLibfuncs::BoxFromSpan(span) => use_and_panic_drop(BoxFromSpan::try_into(span)), - } -} - -fn dict_libfuncs, +Felt252DictValue, +Felt252DictEntryTrait>( - libfuncs: DictLibfuncs, -) { - match libfuncs { - DictLibfuncs::Default => use_and_panic(Default::>::default()), - DictLibfuncs::EntryGet((dict, key)) => { - let (e, _v) = dict.entry(key); - use_and_panic(e) - }, - } -} - -// Handling missing destructor. -impl NullableDictDestruct of Destruct>> { - fn destruct(self: Nullable>) nopanic { - match core::nullable::match_nullable(self) { - core::nullable::FromNullableResult::Null => {}, - core::nullable::FromNullableResult::NotNull(value) => value.unbox().destruct(), - } - } -} - -fn nullable_libfuncs>, +Destruct>(libfuncs: NullableLibfuncs) { - match libfuncs { - NullableLibfuncs::Default => use_and_panic(Default::>::default()), - NullableLibfuncs::New(value) => use_and_panic(NullableTrait::new(value)), - NullableLibfuncs::IsNull(nullable) => use_and_panic(nullable.is_null()), - NullableLibfuncs::Deref(nullable) => use_and_panic(nullable.deref()), - } -} -use core::circuit::{ - AddInputResultTrait, CircuitElement, CircuitInput, CircuitInputs, CircuitModulus, - CircuitOutputsTrait, EvalCircuitTrait, circuit_add, circuit_inverse, circuit_mul, circuit_sub, - u384, -}; - -fn circuit_libfuncs(n: u384, input0: u384, input1: u384) { - let in1 = CircuitElement::> {}; - let in2 = CircuitElement::> {}; - let add = circuit_add(in1, in2); - let inv = circuit_inverse(add); - let sub = circuit_sub(inv, in2); - let mul = circuit_mul(inv, sub); - - let modulus = TryInto::<_, CircuitModulus>::try_into([n.limb0, n.limb1, n.limb2, n.limb3]) - .unwrap(); - let outputs = (mul, add, inv) - .new_inputs() - .next(input0) - .next(input1) - .done() - .eval(modulus) - .unwrap(); - use_and_panic(outputs.get_output(add)); -} -use starknet::secp256_trait::{Secp256PointTrait, Secp256Trait, Signature, is_valid_signature}; - -fn secp_libfuncs< - Secp256Point, - +Drop, - impl Secp256Impl: Secp256Trait, - +Secp256PointTrait, ->( - sign: (u256, u256, u256, u256), -) { - let (a, b, c, x) = sign; - let p = Secp256Impl::secp256_ec_get_point_from_x_syscall(x, true).unwrap().unwrap(); - use_and_panic(is_valid_signature(a, b, c, p)); -} - -#[starknet::interface] -trait Foo { - fn foo(ref self: TContractState); -} -use starknet::syscalls; - -fn starknet_libfuncs(libfuncs: StarknetLibfuncs) { - match libfuncs { - StarknetLibfuncs::LibraryCall(class_hash) => FooLibraryDispatcher { class_hash }.foo(), - StarknetLibfuncs::ContractCall(contract_address) => FooDispatcher { contract_address } - .foo(), - StarknetLibfuncs::StorageRead(storage) => use_and_panic(storage.entry(0).high.read()), - StarknetLibfuncs::StorageWrite(storage) => use_and_panic(storage.write("0")), - StarknetLibfuncs::Deploy(( - class_hash, address, code, is_init, - )) => use_and_panic(syscalls::deploy_syscall(class_hash, address, code, is_init)), - StarknetLibfuncs::EmitEvent(( - keys, data, - )) => use_and_panic(syscalls::emit_event_syscall(keys, data)), - StarknetLibfuncs::GetBlockHash(block_number) => use_and_panic( - syscalls::get_block_hash_syscall(block_number), - ), - StarknetLibfuncs::GetExecutionInfo => use_and_panic(syscalls::get_execution_info_syscall()), - StarknetLibfuncs::GetExecutionInfoV2 => use_and_panic( - syscalls::get_execution_info_v2_syscall(), - ), - StarknetLibfuncs::ReplaceClass(class_hash) => use_and_panic( - syscalls::replace_class_syscall(class_hash), - ), - StarknetLibfuncs::SendMessageToL1(( - address, data, - )) => use_and_panic(syscalls::send_message_to_l1_syscall(address, data)), - StarknetLibfuncs::GetClassHashAt(address) => use_and_panic( - syscalls::get_class_hash_at_syscall(address), - ), - StarknetLibfuncs::MetaTxV0(( - address, entry_point_selector, calldata, signature, - )) => use_and_panic( - syscalls::meta_tx_v0_syscall(address, entry_point_selector, calldata, signature), - ), - } -} - -extern fn felt252_const() -> felt252 nopanic; -extern fn u8_const() -> u8 nopanic; -extern fn u16_const() -> u16 nopanic; -extern fn u32_const() -> u32 nopanic; -extern fn u64_const() -> u64 nopanic; -extern fn u128_const() -> u128 nopanic; -extern fn i8_const() -> i8 nopanic; -extern fn i16_const() -> i16 nopanic; -extern fn i32_const() -> i32 nopanic; -extern fn i64_const() -> i64 nopanic; -extern fn i128_const() -> i128 nopanic; -extern fn bytes31_const() -> bytes31 nopanic; - -#[feature("deprecated-starknet-consts")] -fn consts_libfuncs(libfuncs: ConstsLibfuncs) { - match libfuncs { - ConstsLibfuncs::Felt252 => use_and_panic(felt252_const::<0>()), - ConstsLibfuncs::U8 => use_and_panic(u8_const::<0>()), - ConstsLibfuncs::U16 => use_and_panic(u16_const::<0>()), - ConstsLibfuncs::U32 => use_and_panic(u32_const::<0>()), - ConstsLibfuncs::U64 => use_and_panic(u64_const::<0>()), - ConstsLibfuncs::U128 => use_and_panic(u128_const::<0>()), - ConstsLibfuncs::I8 => use_and_panic(i8_const::<0>()), - ConstsLibfuncs::I16 => use_and_panic(i16_const::<0>()), - ConstsLibfuncs::I32 => use_and_panic(i32_const::<0>()), - ConstsLibfuncs::I64 => use_and_panic(i64_const::<0>()), - ConstsLibfuncs::I128 => use_and_panic(i128_const::<0>()), - ConstsLibfuncs::Byte31 => use_and_panic(bytes31_const::<0>()), - ConstsLibfuncs::StorageBase => use_and_panic( - starknet::storage_access::storage_base_address_const::<0>(), - ), - ConstsLibfuncs::ClassHash => use_and_panic(starknet::class_hash::class_hash_const::<0>()), - ConstsLibfuncs::ContractAddress => use_and_panic( - starknet::contract_address::contract_address_const::<0>(), - ), - } -} - -fn snapshot_libfuncs(libfuncs: SnapshotLibfuncs) { - match libfuncs { - SnapshotLibfuncs::BoxForward(snap) => use_and_panic(snap.as_snapshot()), - SnapshotLibfuncs::Match(snap) => match snap { - Some(value) => use_and_panic(value), - None => {}, - }, - } -} - -#[inline(never)] -fn use_and_panic>(t: T) { - panic!(); -} - -#[inline(never)] -fn use_and_panic_drop>(t: T) { - panic!(); -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/minimal_contract.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/minimal_contract.cairo deleted file mode 100644 index d846b68d10..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/minimal_contract.cairo +++ /dev/null @@ -1,7 +0,0 @@ -#[starknet::contract] -mod minimal_contract { - #[storage] - struct Storage {} - #[external(v0)] - fn empty(ref self: ContractState) {} -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/mintable.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/mintable.cairo deleted file mode 100644 index b42e1b1c9b..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/mintable.cairo +++ /dev/null @@ -1,71 +0,0 @@ -#[starknet::interface] -trait GetSupply { - fn get_total_supply_plus_1(self: @TContractState) -> u256; -} - -#[starknet::contract] -mod mintable_erc20_ownable { - use starknet::ContractAddress; - use crate::components::erc20::erc20 as erc20_comp; - use crate::components::mintable::mintable as mintable_comp; - use crate::components::ownable::ownable as ownable_comp; - #[storage] - struct Storage { - #[substorage(v0)] - erc20_storage: erc20_comp::Storage, - #[substorage(v0)] - ownable_storage: ownable_comp::Storage, - #[substorage(v0)] - mintable_storage: mintable_comp::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - ERC20: erc20_comp::Event, - Ownable: ownable_comp::Event, - Mintable: mintable_comp::Event, - } - - component!(path: erc20_comp, storage: erc20_storage, event: ERC20); - component!(path: ownable_comp, storage: ownable_storage, event: Ownable); - component!(path: mintable_comp, storage: mintable_storage, event: Mintable); - - #[abi(embed_v0)] - impl ERC20Impl = erc20_comp::IERC20; - - impl ERC20Helper = erc20_comp::ERC20HelperImpl; - - #[abi(embed_v0)] - impl OwnershipTransfer = ownable_comp::Transfer; - - impl OwnershipHelper = ownable_comp::OwnableHelperImpl; - - #[abi(embed_v0)] - impl MintImpl = mintable_comp::Mint; - - #[abi(per_item)] - #[generate_trait] - impl ImplCtor of TraitCtor { - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - owner: ContractAddress, - ) { - self.erc20_storage.init(name, symbol, decimals, initial_supply, recipient); - self.ownable_storage.init_ownable(owner); - } - } - - #[abi(embed_v0)] - impl ImplGetSupply of super::GetSupply { - fn get_total_supply_plus_1(self: @ContractState) -> u256 { - self.erc20_storage.get_total_supply() + 1 - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/multi_component.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/multi_component.cairo deleted file mode 100644 index d236ae5d10..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/multi_component.cairo +++ /dev/null @@ -1,79 +0,0 @@ -#[starknet::interface] -pub trait GetSupply { - fn get_total_supply_plus_1(self: @TContractState) -> u256; -} - -#[starknet::contract] -pub mod contract_with_4_components { - use starknet::ContractAddress; - use crate::components::erc20::erc20 as erc20_comp; - use crate::components::mintable::mintable as mintable_comp; - use crate::components::ownable::ownable as ownable_comp; - use crate::components::upgradable::upgradable as upgradable_comp; - #[storage] - struct Storage { - #[substorage(v0)] - erc20_storage: erc20_comp::Storage, - #[substorage(v0)] - ownable_storage: ownable_comp::Storage, - #[substorage(v0)] - mintable_storage: mintable_comp::Storage, - #[substorage(v0)] - upgradable_storage: upgradable_comp::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - ERC20: erc20_comp::Event, - Ownable: ownable_comp::Event, - Mintable: mintable_comp::Event, - Upgradable: upgradable_comp::Event, - } - - component!(path: erc20_comp, storage: erc20_storage, event: ERC20); - component!(path: ownable_comp, storage: ownable_storage, event: Ownable); - component!(path: mintable_comp, storage: mintable_storage, event: Mintable); - component!(path: upgradable_comp, storage: upgradable_storage, event: Upgradable); - - #[abi(embed_v0)] - impl ERC20Impl = erc20_comp::IERC20; - - impl ERC20HelperImpl = erc20_comp::ERC20HelperImpl; - - #[abi(embed_v0)] - impl OwnershipTransfer = ownable_comp::Transfer; - - impl OwnershipHelper = ownable_comp::OwnableHelperImpl; - - #[abi(embed_v0)] - impl MintImpl = mintable_comp::Mint; - - #[abi(embed_v0)] - impl UpgradableImpl = upgradable_comp::UpgradableImpl; - - #[abi(per_item)] - #[generate_trait] - impl ImplCtor of TraitCtor { - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - owner: ContractAddress, - ) { - self.ownable_storage.init_ownable(owner); - self.erc20_storage.init(name, symbol, decimals, initial_supply, recipient); - } - } - - #[abi(embed_v0)] - impl ImplGetSupply of super::GetSupply { - fn get_total_supply_plus_1(self: @ContractState) -> u256 { - self.erc20_storage.get_total_supply() + 1 - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/new_syntax_test_contract.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/new_syntax_test_contract.cairo deleted file mode 100644 index 9c0958db0c..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/new_syntax_test_contract.cairo +++ /dev/null @@ -1,93 +0,0 @@ -#[starknet::interface] -trait IOtherContract { - fn decrease_allowed(self: @TContractState) -> bool; -} - -#[starknet::interface] -trait ICounterContract { - fn increase_counter(ref self: TContractState, amount: u128); - fn decrease_counter(ref self: TContractState, amount: u128); - fn get_counter(self: @TContractState) -> u128; -} - - -#[derive(Drop, starknet::Event)] -struct OutOfScopeEvent {} - -#[starknet::contract] -mod counter_contract { - use starknet::ContractAddress; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use super::{IOtherContractDispatcher, IOtherContractDispatcherTrait, OutOfScopeEvent}; - - component!(path: super::test_component, storage: test_component_storage, event: ABC); - - #[storage] - struct Storage { - #[substorage(v0)] - test_component_storage: super::test_component::Storage, - counter: u128, - other_contract: IOtherContractDispatcher, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - #[flat] - ABC: super::test_component::Event, - CounterIncreased: CounterIncreased, - CounterDecreased: CounterDecreased, - OutOfScopeEvent: OutOfScopeEvent, - } - - #[derive(Drop, starknet::Event)] - struct CounterIncreased { - amount: u128, - } - - #[derive(Drop, starknet::Event)] - struct CounterDecreased { - amount: u128, - } - - #[constructor] - fn constructor( - ref self: ContractState, initial_counter: u128, other_contract_addr: ContractAddress, - ) { - self.counter.write(initial_counter); - self - .other_contract - .write(IOtherContractDispatcher { contract_address: other_contract_addr }); - } - - #[abi(embed_v0)] - impl CounterContract of super::ICounterContract { - fn get_counter(self: @ContractState) -> u128 { - self.counter.read() - } - - fn increase_counter(ref self: ContractState, amount: u128) { - let current = self.counter.read(); - self.counter.write(current + amount); - self.emit(CounterIncreased { amount }); - } - - fn decrease_counter(ref self: ContractState, amount: u128) { - let allowed = self.other_contract.read().decrease_allowed(); - if allowed { - let current = self.counter.read(); - self.counter.write(current - amount); - self.emit(CounterDecreased { amount }); - } - } - } -} - - -#[starknet::component] -mod test_component { - #[storage] - pub struct Storage { - pub data: u32, - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/ownable_erc20.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/ownable_erc20.cairo deleted file mode 100644 index 02de49cf9d..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/ownable_erc20.cairo +++ /dev/null @@ -1,51 +0,0 @@ -#[starknet::contract] -mod ownable_erc20_contract { - use starknet::ContractAddress; - use crate::components::erc20::erc20 as erc20_comp; - use crate::components::ownable::ownable as ownable_comp; - #[storage] - struct Storage { - #[substorage(v0)] - ownable_storage: ownable_comp::Storage, - #[substorage(v0)] - erc20_storage: erc20_comp::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - ERC20: erc20_comp::Event, - Ownable: ownable_comp::Event, - } - - component!(path: erc20_comp, storage: erc20_storage, event: ERC20); - component!(path: ownable_comp, storage: ownable_storage, event: Ownable); - - #[abi(embed_v0)] - impl ERC20Impl = erc20_comp::IERC20; - #[abi(embed_v0)] - impl OwnershipTransfer = ownable_comp::Transfer; - - - impl ERC20HelperImpl = erc20_comp::ERC20HelperImpl; - impl OwnershipHelper = ownable_comp::OwnableHelperImpl; - - - #[abi(per_item)] - #[generate_trait] - impl OwnableERC20Impl of OwnableERC20 { - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - owner: ContractAddress, - ) { - self.erc20_storage.init(name, symbol, decimals, initial_supply, recipient); - self.ownable_storage.init_ownable(owner); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/storage_accesses.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/storage_accesses.cairo deleted file mode 100644 index d1664ed843..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/storage_accesses.cairo +++ /dev/null @@ -1,152 +0,0 @@ -use starknet::ContractAddress; -use starknet::storage::Map; - -#[starknet::interface] -trait IERC20 { - fn get_name(self: @TContractState) -> felt252; - fn get_symbol(self: @TContractState) -> felt252; - fn get_decimals(self: @TContractState) -> u8; - fn get_total_supply(self: @TContractState) -> u256; - fn balance_of(self: @TContractState, account: ContractAddress) -> u256; - fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; - fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: u256); - fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: u256, - ); - fn write_info(ref self: TContractState, user_info: UserInfo); - fn get_info(self: @TContractState) -> UserInfo; -} - -#[derive(starknet::Store, Serde, Drop, Copy)] -struct UserInfo { - name: felt252, - symbol: felt252, - decimals: u8, - total_supply: u256, -} - -#[starknet::storage_node] -struct TransactionInfo { - balances: Map, - allowances: Map>, -} - -#[starknet::contract] -mod storage_accesses { - use core::num::traits::Zero; - use starknet::storage::{ - StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - use starknet::{ContractAddress, get_caller_address}; - use super::{TransactionInfo, UserInfo}; - - #[storage] - struct Storage { - user_info: UserInfo, - transaction_info: TransactionInfo, - } - - #[constructor] - fn constructor( - ref self: ContractState, - name_: felt252, - symbol_: felt252, - decimals_: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.user_info.name.write(name_); - self.user_info.symbol.write(symbol_); - self.user_info.decimals.write(decimals_); - assert(!recipient.is_zero(), 'ERC20: mint to the 0 address'); - self.user_info.total_supply.write(initial_supply); - self.transaction_info.balances.write(recipient, initial_supply); - } - - #[abi(embed_v0)] - impl IERC20Impl of super::IERC20 { - fn get_name(self: @ContractState) -> felt252 { - self.user_info.name.read() - } - - fn get_symbol(self: @ContractState) -> felt252 { - self.user_info.symbol.read() - } - - fn get_decimals(self: @ContractState) -> u8 { - self.user_info.decimals.read() - } - - fn get_total_supply(self: @ContractState) -> u256 { - self.user_info.total_supply.read() - } - - fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - self.transaction_info.balances.read(account) - } - - fn allowance( - self: @ContractState, owner: ContractAddress, spender: ContractAddress, - ) -> u256 { - self.transaction_info.allowances.entry(owner).read(spender) - } - - fn increase_allowance( - ref self: ContractState, spender: ContractAddress, added_value: u256, - ) { - let caller = get_caller_address(); - self - .set_transaction_info( - caller, - spender, - self.transaction_info.allowances.entry(caller).read(spender) + added_value, - ); - } - - fn decrease_allowance( - ref self: ContractState, spender: ContractAddress, subtracted_value: u256, - ) { - let caller = get_caller_address(); - self - .set_transaction_info( - caller, - spender, - self.transaction_info.allowances.entry(caller).read(spender) - subtracted_value, - ); - } - - fn write_info(ref self: ContractState, user_info: UserInfo) { - self.user_info.write(user_info); - } - - fn get_info(self: @ContractState) -> UserInfo { - self.user_info.read() - } - } - - #[generate_trait] - impl StorageImpl of StorageTrait { - fn transfer_helper( - ref self: ContractState, - sender: ContractAddress, - recipient: ContractAddress, - amount: u256, - ) { - self - .transaction_info - .balances - .write(sender, self.transaction_info.balances.read(sender) - amount); - self - .transaction_info - .balances - .write(recipient, self.transaction_info.balances.read(recipient) + amount); - } - - fn set_transaction_info( - ref self: ContractState, owner: ContractAddress, spender: ContractAddress, amount: u256, - ) { - self.transaction_info.allowances.entry(owner).entry(spender).write(amount); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/test_contract.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/test_contract.cairo deleted file mode 100644 index bdc29c15f7..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/test_contract.cairo +++ /dev/null @@ -1,95 +0,0 @@ -#[starknet::interface] -trait IAnotherContract { - fn foo(ref self: T, a: u128) -> u128; -} - -#[starknet::interface] -trait OutsideTrait { - fn ret_3(self: @TContractState) -> felt252; -} -#[starknet::embeddable] -impl OutsideImpl> of OutsideTrait { - fn ret_3(self: @TContractState) -> felt252 { - 3 - } -} - -#[starknet::contract] -mod test_contract { - use core::dict::Felt252Dict; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use super::{ - IAnotherContractDispatcher, IAnotherContractDispatcherTrait, - IAnotherContractLibraryDispatcher, MyType, - }; - - #[storage] - struct Storage { - my_storage_var: felt252, - core: felt252, - } - - fn internal_func() -> felt252 { - -1 - } - - #[abi(embed_v0)] - impl WorkingUsage = super::OutsideImpl; - - #[abi(per_item)] - #[generate_trait] - impl Impl of Trait { - #[constructor] - fn constructor(ref self: ContractState, initial: felt252) { - self.my_storage_var.write(initial); - } - - #[external(v0)] - fn test( - ref self: ContractState, ref arg: felt252, arg1: felt252, arg2: felt252, - ) -> felt252 { - let mut x = self.my_storage_var.read(); - x += 1; - self.my_storage_var.write(x); - x + internal_func() - } - - #[external(v0)] - fn another_function(ref self: ContractState, x: MyType) {} - - #[external(v0)] - fn call_foo( - ref self: ContractState, another_contract_address: starknet::ContractAddress, a: u128, - ) -> u128 { - IAnotherContractDispatcher { contract_address: another_contract_address }.foo(a) - } - - #[external(v0)] - fn libcall_foo(ref self: ContractState, a: u128) -> u128 { - IAnotherContractLibraryDispatcher { class_hash: core::num::traits::Zero::zero() }.foo(a) - } - - /// An external method that requires the `segment_arena` builtin. - #[external(v0)] - fn segment_arena_builtin(ref self: ContractState) { - let x: Felt252Dict = Default::default(); - x.squash(); - } - - #[l1_handler] - fn l1_handle(ref self: ContractState, from_address: felt252, arg: felt252) -> felt252 { - arg - } - - #[external(v0)] - fn fixed_sized_array_usage(ref self: ContractState, value: [felt252; 5]) -> [felt252; 5] { - value - } - } -} - -#[derive(Copy, Drop, Serde)] -struct MyType { - a: felt252, - b: bool, -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/token_bridge.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/token_bridge.cairo deleted file mode 100644 index 7d7fc0285d..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/token_bridge.cairo +++ /dev/null @@ -1,168 +0,0 @@ -use starknet::ContractAddress; - -#[starknet::interface] -trait IMintableToken { - fn permissioned_mint(ref self: T, account: ContractAddress, amount: u256); - fn permissioned_burn(ref self: T, account: ContractAddress, amount: u256); -} - -#[starknet::contract] -mod token_bridge { - use core::num::traits::Zero; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use starknet::syscalls::send_message_to_l1_syscall; - use starknet::{ContractAddress, EthAddress, SyscallResultTrait, get_caller_address}; - use super::{IMintableTokenDispatcher, IMintableTokenDispatcherTrait}; - - const WITHDRAW_MESSAGE: felt252 = 0; - const CONTRACT_IDENTITY: felt252 = 'STARKGATE'; - const CONTRACT_VERSION: felt252 = 2; - - #[storage] - struct Storage { - // The address of the L2 governor of this contract. Only the governor can set the other - // storage variables. - governor: ContractAddress, - // The L1 bridge address. Zero when unset. - l1_bridge: felt252, - // The L2 token contract address. Zero when unset. - l2_token: ContractAddress, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - L1BridgeSet: L1BridgeSet, - L2TokenSet: L2TokenSet, - WithdrawInitiated: WithdrawInitiated, - DepositHandled: DepositHandled, - } - - // An event that is emitted when set_l1_bridge is called. - // * l1_bridge_address is the new l1 bridge address. - #[derive(Drop, starknet::Event)] - struct L1BridgeSet { - l1_bridge_address: EthAddress, - } - - // An event that is emitted when set_l2_token is called. - // * l2_token_address is the new l2 token address. - #[derive(Drop, starknet::Event)] - struct L2TokenSet { - l2_token_address: ContractAddress, - } - - // An event that is emitted when initiate_withdraw is called. - // * l1_recipient is the l1 recipient address. - // * amount is the amount to withdraw. - // * caller_address is the address from which the call was made. - #[derive(Drop, starknet::Event)] - struct WithdrawInitiated { - l1_recipient: EthAddress, - amount: u256, - caller_address: ContractAddress, - } - - // An event that is emitted when handle_deposit is called. - // * account is the recipient address. - // * amount is the amount to deposit. - #[derive(Drop, starknet::Event)] - struct DepositHandled { - account: ContractAddress, - amount: u256, - } - - #[constructor] - fn constructor(ref self: ContractState, governor_address: ContractAddress) { - assert(governor_address.is_non_zero(), 'ZERO_GOVERNOR_ADDRESS'); - self.governor.write(governor_address); - } - - #[generate_trait] - #[abi(per_item)] - impl TokenBridgeImpl of ITokenBridge { - // TODO(spapini): Consider adding a pure option, with no parameters. - #[external(v0)] - fn get_version(self: @ContractState) -> felt252 { - CONTRACT_VERSION - } - - #[external(v0)] - fn get_identity(self: @ContractState) -> felt252 { - CONTRACT_IDENTITY - } - - #[external(v0)] - fn set_l1_bridge(ref self: ContractState, l1_bridge_address: EthAddress) { - // The call is restricted to the governor. - assert(get_caller_address() == self.governor.read(), 'GOVERNOR_ONLY'); - - assert(self.l1_bridge.read().is_zero(), 'L1_BRIDGE_ALREADY_INITIALIZED'); - assert(l1_bridge_address.is_non_zero(), 'ZERO_BRIDGE_ADDRESS'); - - self.l1_bridge.write(l1_bridge_address.into()); - self.emit(L1BridgeSet { l1_bridge_address }); - } - - #[external(v0)] - fn set_l2_token(ref self: ContractState, l2_token_address: ContractAddress) { - // The call is restricted to the governor. - assert(get_caller_address() == self.governor.read(), 'GOVERNOR_ONLY'); - - assert(self.l2_token.read().is_zero(), 'L2_TOKEN_ALREADY_INITIALIZED'); - assert(l2_token_address.is_non_zero(), 'ZERO_TOKEN_ADDRESS'); - - self.l2_token.write(l2_token_address); - self.emit(L2TokenSet { l2_token_address }); - } - - #[external(v0)] - fn initiate_withdraw(ref self: ContractState, l1_recipient: EthAddress, amount: u256) { - // Call burn on l2_token contract. - let caller_address = get_caller_address(); - IMintableTokenDispatcher { contract_address: self.read_initialized_l2_token() } - .permissioned_burn(account: caller_address, :amount); - - // Send the message. - let mut message_payload: Array = array![ - WITHDRAW_MESSAGE, l1_recipient.into(), amount.low.into(), amount.high.into(), - ]; - send_message_to_l1_syscall( - to_address: self.read_initialized_l1_bridge(), payload: message_payload.span(), - ) - .unwrap_syscall(); - self.emit(WithdrawInitiated { l1_recipient, amount, caller_address }); - } - } - - #[l1_handler] - fn handle_deposit( - ref self: ContractState, from_address: felt252, account: ContractAddress, amount: u256, - ) { - assert(from_address == self.l1_bridge.read(), 'EXPECTED_FROM_BRIDGE_ONLY'); - - // Call mint on l2_token contract. - IMintableTokenDispatcher { contract_address: self.read_initialized_l2_token() } - .permissioned_mint(:account, :amount); - - self.emit(Event::DepositHandled(DepositHandled { account, amount })); - } - - /// Helpers (internal functions) - #[generate_trait] - impl HelperImpl of HelperTrait { - // Read l1_bridge and verify it's initialized. - fn read_initialized_l1_bridge(self: @ContractState) -> felt252 { - let l1_bridge_address = self.l1_bridge.read(); - assert(l1_bridge_address.is_non_zero(), 'UNINITIALIZED_L1_BRIDGE_ADDRESS'); - l1_bridge_address - } - - // Read l2_token and verify it's initialized. - fn read_initialized_l2_token(self: @ContractState) -> ContractAddress { - let l2_token_address = self.l2_token.read(); - assert(l2_token_address.is_non_zero(), 'UNINITIALIZED_TOKEN'); - l2_token_address - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/upgradable_counter.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/upgradable_counter.cairo deleted file mode 100644 index 8a15f095ea..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/upgradable_counter.cairo +++ /dev/null @@ -1,70 +0,0 @@ -#[starknet::interface] -trait ICounterContract { - fn increase_counter(ref self: TContractState, amount: u128); - fn decrease_counter(ref self: TContractState, amount: u128); - fn get_counter(self: @TContractState) -> u128; -} - -#[starknet::contract] -mod counter_contract { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use crate::components::ownable::ownable as ownable_comp; - use crate::components::upgradable::upgradable as upgradable_comp; - component!(path: upgradable_comp, storage: upgradable, event: UpgradableEvent); - component!(path: ownable_comp, storage: ownable, event: OwnableEvent); - - #[storage] - struct Storage { - counter: u128, - #[substorage(v0)] - upgradable: upgradable_comp::Storage, - #[substorage(v0)] - ownable: ownable_comp::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - CounterIncreased: CounterIncreased, - CounterDecreased: CounterDecreased, - UpgradableEvent: upgradable_comp::Event, - OwnableEvent: ownable_comp::Event, - } - - #[derive(Drop, starknet::Event)] - struct CounterIncreased { - amount: u128, - } - - #[derive(Drop, starknet::Event)] - struct CounterDecreased { - amount: u128, - } - - #[constructor] - fn constructor(ref self: ContractState, initial_counter: u128) { - self.counter.write(initial_counter); - } - - #[abi(embed_v0)] - impl CounterContract of super::ICounterContract { - fn get_counter(self: @ContractState) -> u128 { - self.counter.read() - } - - fn increase_counter(ref self: ContractState, amount: u128) { - let current = self.counter.read(); - self.counter.write(current + amount); - self.emit(CounterIncreased { amount }); - } - - fn decrease_counter(ref self: ContractState, amount: u128) { - let current = self.counter.read(); - self.counter.write(current - amount); - self.emit(CounterDecreased { amount }); - } - } - - #[abi(embed_v0)] - impl Upgradable = upgradable_comp::UpgradableImpl; -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20.cairo deleted file mode 100644 index cc224c01ee..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20.cairo +++ /dev/null @@ -1,39 +0,0 @@ -#[starknet::contract] -mod erc20_contract { - use starknet::ContractAddress; - use crate::components::erc20::erc20 as erc20_comp; - #[storage] - struct Storage { - #[substorage(v0)] - erc20_token: erc20_comp::Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - ERC20Token: erc20_comp::Event, - } - - component!(path: erc20_comp, storage: erc20_token, event: ERC20Token); - - #[abi(embed_v0)] - impl ERC20Impl = erc20_comp::IERC20; - - impl ERC20HelperImpl = erc20_comp::ERC20HelperImpl; - - #[abi(per_item)] - #[generate_trait] - impl CtorImpl of CtorTrait { - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.erc20_token.init(name, symbol, decimals, initial_supply, recipient); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20_mini.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20_mini.cairo deleted file mode 100644 index d6e70d53ff..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/with_erc20_mini.cairo +++ /dev/null @@ -1,49 +0,0 @@ -#[starknet::contract] -mod erc20_mini_contract { - use starknet::ContractAddress; - use starknet::storage::{StorageTrait, StorageTraitMut}; - use crate::components::erc20_mini; - #[storage] - struct Storage { - #[flat] - erc20_token: erc20_mini::ERC20Storage, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - ERC20Token: erc20_mini::Event, - } - - #[abi(embed_v0)] - impl ERC20Impl = erc20_mini::ERC20Impl; - - impl ERC20HelperImpl = erc20_mini::ERC20HelperImpl; - - impl ERC20HasStorage of erc20_mini::HasStorage { - fn storage(self: @ContractState) -> StorageTrait::::BaseType { - self.erc20_token.deref() - } - fn storage_mut( - ref self: ContractState, - ) -> StorageTraitMut::::BaseType { - self.erc20_token.deref() - } - } - - #[abi(per_item)] - #[generate_trait] - impl CtorImpl of CtorTrait { - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - decimals: u8, - initial_supply: u256, - recipient: ContractAddress, - ) { - self.erc20_init(name, symbol, decimals, initial_supply, recipient); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable.cairo deleted file mode 100644 index a1eb77070c..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable.cairo +++ /dev/null @@ -1,44 +0,0 @@ -#[starknet::contract] -mod ownable_balance { - use starknet::ContractAddress; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use crate::components::ownable::ownable as ownable_comp; - #[storage] - struct Storage { - #[substorage(v0)] - ownable: ownable_comp::Storage, - balance: u128, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - Ownable: ownable_comp::Event, - } - - component!(path: ownable_comp, storage: ownable, event: Ownable); - - #[abi(embed_v0)] - impl OwnershipTransfer = ownable_comp::Transfer; - - impl OwnershipHelper = ownable_comp::OwnableHelperImpl; - - #[abi(per_item)] - #[generate_trait] - impl OwnableBalanceImpl of OwnableBalance { - #[constructor] - fn constructor(ref self: ContractState, owner: ContractAddress, initial: u128) { - self.ownable.init_ownable(owner); - self.balance.write(initial); - } - #[external(v0)] - fn get_balance(self: @ContractState) -> u128 { - self.balance.read() - } - #[external(v0)] - fn set_balance(ref self: ContractState, new_balance: u128) { - self.ownable.validate_ownership(); - self.balance.write(new_balance); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable_mini.cairo b/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable_mini.cairo deleted file mode 100644 index c10b1d208f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/contracts/with_ownable_mini.cairo +++ /dev/null @@ -1,52 +0,0 @@ -#[starknet::contract] -mod ownable_mini_contract { - use starknet::ContractAddress; - use starknet::storage::{ - StorageAsPath, StorageNode, StorageNodeMut, StoragePointerReadAccess, - StoragePointerWriteAccess, - }; - use crate::components::ownable_mini; - - #[storage] - struct Storage { - ownable: ownable_mini::OwnableStorage, - balance: u128, - } - - #[abi(embed_v0)] - impl OwnershipTransfer = ownable_mini::TransferImpl; - - impl OwnershipHelper = ownable_mini::OwnableHelperImpl; - - impl OwnableHasStorage of ownable_mini::HasStorage< - ContractState, ownable_mini::OwnableStorage, - > { - fn storage(self: @ContractState) -> StorageNode::::NodeType { - self.ownable.as_path().storage_node() - } - fn storage_mut( - ref self: ContractState, - ) -> StorageNodeMut::::NodeType { - self.ownable.as_path().storage_node_mut() - } - } - - #[abi(per_item)] - #[generate_trait] - impl OwnableBalanceImpl of OwnableBalance { - #[constructor] - fn constructor(ref self: ContractState, owner: ContractAddress, initial: u128) { - self.init_ownable(owner); - self.balance.write(initial); - } - #[external(v0)] - fn get_balance(self: @ContractState) -> u128 { - self.balance.read() - } - #[external(v0)] - fn set_balance(ref self: ContractState, new_balance: u128) { - self.validate_ownership(); - self.balance.write(new_balance); - } - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/deployment.cairo b/test_data/tests_starknet/cairo_level_tests/deployment.cairo deleted file mode 100644 index cb55d00e0f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/deployment.cairo +++ /dev/null @@ -1,124 +0,0 @@ -use starknet::deployment::DeploymentParams; -use starknet::syscalls::deploy_syscall; - -#[starknet::interface] -trait IValue { - fn get_value(self: @TContractState) -> felt252; - fn set_value(ref self: TContractState, value: felt252); -} - -#[starknet::contract] -mod self_caller { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use super::{IValueDispatcher, IValueDispatcherTrait}; - #[storage] - struct Storage { - value: felt252, - } - - #[constructor] - fn constructor(ref self: ContractState) { - IValueDispatcher { contract_address: starknet::get_contract_address() }.set_value(1); - } - - #[abi(embed_v0)] - impl ValueImpl of super::IValue { - fn get_value(self: @ContractState) -> felt252 { - self.value.read() - } - - fn set_value(ref self: ContractState, value: felt252) { - self.value.write(value); - } - } -} - -#[starknet::contract] -pub mod advanced { - #[storage] - struct Storage {} - - #[constructor] - fn constructor( - ref self: ContractState, - arr: Array>, - one: u8, - two: i16, - three: ByteArray, - four: (bool, u32), - five: u256, - six: felt252, - ) {} -} - -#[test] -fn test_deploy_in_construct() { - let (contract_address, _) = deploy_syscall(self_caller::TEST_CLASS_HASH, 0, [].span(), false) - .expect('deployment failed'); - assert!(IValueDispatcher { contract_address }.get_value() == 1); -} - - -#[test] -fn test_redeploy_in_construct() { - assert!(deploy_syscall(self_caller::TEST_CLASS_HASH, 0, [].span(), false).is_ok()); - assert!( - deploy_syscall( - self_caller::TEST_CLASS_HASH, 0, [].span(), false, - ) == Err(array!['CONTRACT_ALREADY_DEPLOYED']), - ); -} - -#[test] -fn test_typed_redeploy_default() { - assert!(self_caller::deploy_for_test(self_caller::TEST_CLASS_HASH, Default::default()).is_ok()); - assert!( - deploy_syscall( - self_caller::TEST_CLASS_HASH, 0, [].span(), false, - ) == Err(array!['CONTRACT_ALREADY_DEPLOYED']), - ); -} - -#[test] -fn test_typed_redeploy_with_params() { - let deployment_params = DeploymentParams { salt: 42, deploy_from_zero: true }; - assert!(self_caller::deploy_for_test(self_caller::TEST_CLASS_HASH, deployment_params).is_ok()); - assert!( - deploy_syscall( - self_caller::TEST_CLASS_HASH, 42, [].span(), true, - ) == Err(array!['CONTRACT_ALREADY_DEPLOYED']), - ); -} - -#[test] -fn test_typed_deploy_default_with_complex_args() { - let arr: Array> = array![array![1, 2, 3], array![4, 5]]; - let one: u8 = 42; - let two: i16 = -123; - let three: ByteArray = "Hello, Starknet!"; - let four: (bool, u32) = (true, 456); - let five: u256 = 0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0; - let six: felt252 = 123; - - let mut calldata = array![]; - arr.serialize(ref calldata); - one.serialize(ref calldata); - two.serialize(ref calldata); - three.serialize(ref calldata); - four.serialize(ref calldata); - five.serialize(ref calldata); - six.serialize(ref calldata); - - assert!( - advanced::deploy_for_test( - advanced::TEST_CLASS_HASH, Default::default(), arr, one, two, three, four, five, six, - ) - .is_ok(), - ); - - assert!( - deploy_syscall( - advanced::TEST_CLASS_HASH, 0, calldata.span(), false, - ) == Err(array!['CONTRACT_ALREADY_DEPLOYED']), - ); -} diff --git a/test_data/tests_starknet/cairo_level_tests/erc20_test.cairo b/test_data/tests_starknet/cairo_level_tests/erc20_test.cairo deleted file mode 100644 index d306a9c6e6..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/erc20_test.cairo +++ /dev/null @@ -1,9 +0,0 @@ -use starknet::testing::set_caller_address; -use crate::contracts::erc20::{IERC20DispatcherTrait, IERC20LibraryDispatcher, erc_20}; - -#[test] -fn test_erc20_transfer() { - set_caller_address(2.try_into().unwrap()); - IERC20LibraryDispatcher { class_hash: erc_20::TEST_CLASS_HASH } - .transfer(1.try_into().unwrap(), 0_u256); -} diff --git a/test_data/tests_starknet/cairo_level_tests/events.cairo b/test_data/tests_starknet/cairo_level_tests/events.cairo deleted file mode 100644 index ac1d8e527f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/events.cairo +++ /dev/null @@ -1,128 +0,0 @@ -use starknet::SyscallResultTrait; -use starknet::syscalls::deploy_syscall; - -#[starknet::interface] -trait IContractWithEvent { - fn emit_event(ref self: T, incremental: bool); - fn emit_flat_event(ref self: T); -} - -#[starknet::contract] -mod contract_with_event { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - value: u128, - } - - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub struct IncrementalEvent { - pub value: u128, - } - - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub struct StaticEvent {} - - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub enum FlatEvent { - FlatEvent: StaticEvent, - } - - #[event] - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub enum Event { - IncrementalEvent: IncrementalEvent, - StaticEvent: StaticEvent, - #[flat] - FlatEvent: FlatEvent, - } - - #[constructor] - fn constructor(ref self: ContractState) { - self.value.write(0); - } - - #[external(v0)] - fn emit_event(ref self: ContractState, incremental: bool) { - if incremental { - self.emit(Event::IncrementalEvent(IncrementalEvent { value: self.value.read() })); - self.value.write(self.value.read() + 1); - } else { - self.emit(Event::StaticEvent(StaticEvent {})); - } - } - - #[external(v0)] - fn emit_flat_event(ref self: ContractState) { - self.emit(FlatEvent::FlatEvent(StaticEvent {})); - } -} -use contract_with_event::{Event, FlatEvent, IncrementalEvent, StaticEvent}; - -#[test] -fn test_events() { - core::internal::revoke_ap_tracking(); - // Set up. - let (contract_address, _) = deploy_syscall( - contract_with_event::TEST_CLASS_HASH.try_into().unwrap(), 0, [].span(), false, - ) - .unwrap(); - let mut contract = IContractWithEventDispatcher { contract_address }; - contract.emit_event(true); - contract.emit_event(true); - contract.emit_event(false); - contract.emit_event(false); - contract.emit_event(true); - contract.emit_event(false); - contract.emit_event(true); - contract.emit_flat_event(); - contract.emit_flat_event(); - - assert_eq!( - starknet::testing::pop_log(contract_address), - Some(Event::IncrementalEvent(IncrementalEvent { value: 0 })), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), - Some(Event::IncrementalEvent(IncrementalEvent { value: 1 })), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), Some(Event::StaticEvent(StaticEvent {})), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), Some(Event::StaticEvent(StaticEvent {})), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), - Some(Event::IncrementalEvent(IncrementalEvent { value: 2 })), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), Some(Event::StaticEvent(StaticEvent {})), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), - Some(Event::IncrementalEvent(IncrementalEvent { value: 3 })), - ); - assert_eq!( - starknet::testing::pop_log(contract_address), - Some(Event::FlatEvent(FlatEvent::FlatEvent(StaticEvent {}))), - ); - // Check that `FlatEvent` is flattened and can be deserialized directly. - assert_eq!( - starknet::testing::pop_log(contract_address), Some(FlatEvent::FlatEvent(StaticEvent {})), - ); - assert!(starknet::testing::pop_log_raw(contract_address).is_none()); -} - -#[test] -fn test_pop_log() { - const CONTRACT_ADDRESS: starknet::ContractAddress = 0x1234_felt252.try_into().unwrap(); - starknet::testing::set_contract_address(CONTRACT_ADDRESS); - let (keys, data) = ([1234].span(), [2345].span()); - starknet::syscalls::emit_event_syscall(keys, data).unwrap_syscall(); - starknet::syscalls::emit_event_syscall(keys, data).unwrap_syscall(); - - assert_eq!(starknet::testing::pop_log_raw(CONTRACT_ADDRESS), Some((keys, data))); - assert_eq!(starknet::testing::pop_log_raw(CONTRACT_ADDRESS), Some((keys, data))); -} diff --git a/test_data/tests_starknet/cairo_level_tests/flat_storage_test.cairo b/test_data/tests_starknet/cairo_level_tests/flat_storage_test.cairo deleted file mode 100644 index 2714afe38f..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/flat_storage_test.cairo +++ /dev/null @@ -1,51 +0,0 @@ -use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - -#[starknet::storage_node] -struct Struct1 { - pub member1: felt252, -} - -#[starknet::storage_node] -struct Struct0 { - pub member0: Struct1, -} - -#[starknet::contract] -mod with_ignored { - use super::Struct0; - #[storage] - pub struct Storage { - pub member: Struct0, - } -} - -#[starknet::storage_node] -struct IgnoredMemberStruct { - #[flat] - pub ignored_member: Struct0, -} - -#[starknet::contract] -mod without_ignored { - use super::IgnoredMemberStruct; - #[storage] - pub struct Storage { - pub member: IgnoredMemberStruct, - } -} - -#[test] -fn with_ignored_write_without_ignored_read_test() { - let mut contract_state_v0 = with_ignored::contract_state_for_testing(); - let mut contract_state_new = without_ignored::contract_state_for_testing(); - contract_state_v0.member.member0.member1.write(1); - assert_eq!(contract_state_new.member.ignored_member.member0.member1.read(), 1); -} - -#[test] -fn without_ignored_write_with_ignored_read_test() { - let mut contract_state_v0 = with_ignored::contract_state_for_testing(); - let mut contract_state_new = without_ignored::contract_state_for_testing(); - contract_state_new.member.ignored_member.member0.member1.write(2); - assert_eq!(contract_state_v0.member.member0.member1.read(), 2); -} diff --git a/test_data/tests_starknet/cairo_level_tests/interoperability.cairo b/test_data/tests_starknet/cairo_level_tests/interoperability.cairo deleted file mode 100644 index 561917916d..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/interoperability.cairo +++ /dev/null @@ -1,165 +0,0 @@ -use starknet::SyscallResultTrait; -use starknet::syscalls::{deploy_syscall, get_block_hash_syscall}; - -#[starknet::interface] -trait IContract { - fn foo(ref self: T, a: u128) -> u128; -} - -#[starknet::contract] -mod contract_a { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - value: u128, - } - - #[constructor] - fn constructor(ref self: ContractState, value: u128) { - self.value.write(value); - } - - #[external(v0)] - fn foo(ref self: ContractState, a: u128) -> u128 { - let value = self.value.read(); - self.value.write(a); - value - } - - #[generate_trait] - pub impl MyImpl of MyTrait { - fn internal_func(self: @ContractState) -> u128 { - 5 - } - } -} -use contract_a::MyTrait; -#[test] -fn test_internal_func() { - let mut contract_state = contract_a::contract_state_for_testing(); - contract_state.internal_func(); -} - -#[test] -fn test_flow() { - // Set up. - let (address0, _) = deploy_syscall(contract_a::TEST_CLASS_HASH, 0, [100].span(), false) - .unwrap(); - let mut contract0 = IContractDispatcher { contract_address: address0 }; - let (address1, _) = deploy_syscall(contract_a::TEST_CLASS_HASH, 0, [200].span(), false) - .unwrap(); - let mut contract1 = IContractDispatcher { contract_address: address1 }; - - // Interact. - assert_eq!(contract0.foo(300), 100); - assert_eq!(contract1.foo(300), 200); - assert_eq!(contract0.foo(300), 300); - assert_eq!(contract1.foo(300), 300); - - // Library calls. - let mut library = IContractLibraryDispatcher { class_hash: contract_a::TEST_CLASS_HASH }; - assert_eq!(library.foo(300), 0); -} - -#[test] -#[feature("safe_dispatcher")] -fn test_flow_safe_dispatcher() { - // Set up. - let (contract_address, _) = deploy_syscall(contract_a::TEST_CLASS_HASH, 0, [100].span(), false) - .unwrap(); - let mut contract = IContractSafeDispatcher { contract_address }; - - // Interact. - assert_eq!(contract.foo(300), Ok(100)); - - // Library calls. - let mut library = IContractSafeLibraryDispatcher { class_hash: contract_a::TEST_CLASS_HASH }; - assert_eq!(library.foo(300), Ok(0)); -} - -// If the test is failing due to gas usage changes, update the gas limit by taking `test_flow` test -// gas usage and add about 51220. -#[test] -#[available_gas(750000)] -#[should_panic(expected: ('Out of gas', 'ENTRYPOINT_FAILED'))] -fn test_flow_out_of_gas() { - // Calling the `test_flow` test but a low gas limit. - test_flow(); -} - -#[test] -fn test_class_hash_not_found() { - assert_eq!( - deploy_syscall(5.try_into().unwrap(), 0, [100].span(), false), - Err(array!['CLASS_HASH_NOT_FOUND']), - ); -} - -#[test] -#[should_panic(expected: ('CONTRACT_NOT_DEPLOYED', 'ENTRYPOINT_FAILED'))] -fn test_contract_not_deployed() { - let mut contract = IContractDispatcher { contract_address: 5.try_into().unwrap() }; - contract.foo(10); -} - -#[starknet::contract] -mod contract_failed_constructor { - #[storage] - struct Storage {} - - #[constructor] - fn constructor(ref self: ContractState, value: u128) { - core::panic_with_felt252('Failure'); - } -} - -#[test] -fn test_failed_constructor() { - // Set up. - let mut calldata = array![]; - calldata.append(100); - let mut err = deploy_syscall( - contract_failed_constructor::TEST_CLASS_HASH, 0, calldata.span(), false, - ) - .unwrap_err(); - assert_eq!(err.pop_front().unwrap(), 'Failure'); - assert_eq!(err.pop_front().unwrap(), 'CONSTRUCTOR_FAILED'); -} - -#[starknet::contract] -mod contract_failed_entrypoint { - #[storage] - struct Storage {} - - #[external(v0)] - fn foo(ref self: ContractState, value: u128) { - core::panic_with_felt252('Failure'); - } -} - -#[test] -fn test_non_empty_calldata_nonexistent_constructor() { - let mut err = deploy_syscall( - contract_failed_entrypoint::TEST_CLASS_HASH, 0, array![100].span(), false, - ) - .unwrap_err(); - assert_eq!(err.pop_front().unwrap(), 'INVALID_CALLDATA_LEN'); -} - -#[test] -#[should_panic(expected: ('Failure', 'ENTRYPOINT_FAILED'))] -fn test_entrypoint_failed() { - let (address0, _) = deploy_syscall( - contract_failed_entrypoint::TEST_CLASS_HASH, 0, array![].span(), false, - ) - .unwrap(); - let mut contract = IContractDispatcher { contract_address: address0 }; - contract.foo(300); -} - -#[test] -#[should_panic(expected: ('GET_BLOCK_HASH_NOT_SET',))] -fn test_get_block_hash() { - get_block_hash_syscall(0).unwrap_syscall(); -} diff --git a/test_data/tests_starknet/cairo_level_tests/keccak.cairo b/test_data/tests_starknet/cairo_level_tests/keccak.cairo deleted file mode 100644 index 0d04a2c708..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/keccak.cairo +++ /dev/null @@ -1,17 +0,0 @@ -/// Returns the selector for the given `ByteArray`. -fn selector(ba: ByteArray) -> felt252 { - let value = core::keccak::compute_keccak_byte_array(@ba); - u256 { - low: core::integer::u128_byte_reverse(value.high), - high: core::integer::u128_byte_reverse(value.low) & 0x3ffffffffffffffffffffffffffffff, - } - .try_into() - .unwrap() -} - -#[test] -fn test_keccak_byte_array() { - assert_eq!(selector(""), selector!("")); - assert_eq!(selector("0123456789abedef"), selector!("0123456789abedef")); - assert_eq!(selector("hello-world"), selector!("hello-world")); -} diff --git a/test_data/tests_starknet/cairo_level_tests/l2_to_l1_messages.cairo b/test_data/tests_starknet/cairo_level_tests/l2_to_l1_messages.cairo deleted file mode 100644 index 6b83af2451..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/l2_to_l1_messages.cairo +++ /dev/null @@ -1,94 +0,0 @@ -use contract_with_messages_sent_to_l1::IContractWithMessagesSentToL1; -use starknet::{SyscallResultTrait, testing}; - -#[starknet::contract] -mod contract_with_messages_sent_to_l1 { - use core::array::ArrayTrait; - use starknet::SyscallResultTrait; - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use super::generate_payload; - - #[storage] - struct Storage { - value: u128, - } - - #[constructor] - fn constructor(ref self: ContractState) { - self.value.write(0); - } - - #[abi(per_item)] - #[generate_trait] - pub impl IContractWithMessagesSentToL1Impl of IContractWithMessagesSentToL1 { - #[external(v0)] - fn send_message_to_l1(ref self: ContractState) { - let value_ = self.value.read(); - - starknet::syscalls::send_message_to_l1_syscall( - to_address: value_.into(), payload: generate_payload(n: value_).span(), - ) - .unwrap_syscall(); - self.value.write(value_ + 1); - } - } -} - - -// Generates the array [0, 1, 2, ..., n] -fn generate_payload(n: u128) -> Array { - let mut payload = array![]; - - let mut i: u128 = 0; - loop { - if (i > n) { - break; - } - - payload.append(i.into()); - i += 1; - } - - payload -} - -#[test] -fn test_l2_to_l1_messages() { - // Set up. - let mut contract = contract_with_messages_sent_to_l1::unsafe_new_contract_state(); - const CONTRACT_ADDRESS: starknet::ContractAddress = 0x42_felt252.try_into().unwrap(); - const OTHER_CONTRACT_ADDRESS: starknet::ContractAddress = 0xdead_felt252.try_into().unwrap(); - - testing::set_contract_address(CONTRACT_ADDRESS); - - // Send messages. - contract.send_message_to_l1(); - contract.send_message_to_l1(); - contract.send_message_to_l1(); - - // Assert other addresses did not send messages. - assert!(testing::pop_l2_to_l1_message(OTHER_CONTRACT_ADDRESS).is_none()); - - // Pop messages. - assert_eq!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS), Some((0, [0].span()))); - assert_eq!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS), Some((1, [0, 1].span()))); - assert_eq!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS), Some((2, [0, 1, 2].span()))); - - // Assert all messages have been popped. - assert!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS).is_none()); -} - -#[test] -fn test_pop_l2_to_l1_message() { - const CONTRACT_ADDRESS: starknet::ContractAddress = 0x42_felt252.try_into().unwrap(); - testing::set_contract_address(CONTRACT_ADDRESS); - - let mut to_address = 1234; - let mut payload = [2345].span(); - - starknet::syscalls::send_message_to_l1_syscall(to_address, payload).unwrap_syscall(); - starknet::syscalls::send_message_to_l1_syscall(to_address, payload).unwrap_syscall(); - - assert_eq!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS), Some((to_address, payload))); - assert_eq!(testing::pop_l2_to_l1_message(CONTRACT_ADDRESS), Some((to_address, payload))); -} diff --git a/test_data/tests_starknet/cairo_level_tests/lib.cairo b/test_data/tests_starknet/cairo_level_tests/lib.cairo deleted file mode 100644 index ff4c468e48..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/lib.cairo +++ /dev/null @@ -1,35 +0,0 @@ -#[cfg(test)] -mod abi_dispatchers_tests; -#[cfg(test)] -mod collections_test; -#[cfg(test)] -mod component_usage_test; -mod components; -#[cfg(test)] -mod contract_address_test; -#[cfg(test)] -mod contract_tests; -mod contracts; -#[cfg(test)] -mod deployment; -#[cfg(test)] -mod erc20_test; -#[cfg(test)] -mod events; -#[cfg(test)] -mod flat_storage_test; -#[cfg(test)] -mod interoperability; -#[cfg(test)] -mod keccak; -#[cfg(test)] -mod l2_to_l1_messages; -#[cfg(test)] -mod multi_component_test; -#[cfg(test)] -mod renamed_storage_test; -#[cfg(test)] -mod replace_class_test; -#[cfg(test)] -mod storage_access; -mod utils; diff --git a/test_data/tests_starknet/cairo_level_tests/multi_component_test.cairo b/test_data/tests_starknet/cairo_level_tests/multi_component_test.cairo deleted file mode 100644 index e56108da0c..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/multi_component_test.cairo +++ /dev/null @@ -1,24 +0,0 @@ -use crate::components::mintable::{MintTraitDispatcher, MintTraitDispatcherTrait}; -use crate::contracts::multi_component::{ - GetSupplyDispatcher, GetSupplyDispatcherTrait, contract_with_4_components, -}; -use super::utils::serialized; - -#[test] -fn test_flow() { - // Set up. - const RECIPIENT: starknet::ContractAddress = 0x1337_felt252.try_into().unwrap(); - let (contract_address, _) = starknet::syscalls::deploy_syscall( - contract_with_4_components::TEST_CLASS_HASH, - 0, - serialized((('name', 'symbol'), (18_u8, 1000_u256, RECIPIENT), RECIPIENT)), - false, - ) - .unwrap(); - let mut get_supply_dispatcher = GetSupplyDispatcher { contract_address }; - assert_eq!(get_supply_dispatcher.get_total_supply_plus_1(), 1001); - let mut mint_dispatcher = MintTraitDispatcher { contract_address }; - starknet::testing::set_contract_address(RECIPIENT); - mint_dispatcher.mint(RECIPIENT, 1999_u256); - assert_eq!(get_supply_dispatcher.get_total_supply_plus_1(), 3000); -} diff --git a/test_data/tests_starknet/cairo_level_tests/renamed_storage_test.cairo b/test_data/tests_starknet/cairo_level_tests/renamed_storage_test.cairo deleted file mode 100644 index bb8cd0c208..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/renamed_storage_test.cairo +++ /dev/null @@ -1,47 +0,0 @@ -use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - -#[starknet::storage_node] -struct A { - pub a: felt252, -} - -#[starknet::storage_node] -struct B { - #[rename("a")] - pub b: felt252, -} - -#[starknet::storage_node] -struct AB { - #[flat] - pub a: A, - #[allow(starknet::colliding_storage_paths)] - #[flat] - pub b: B, -} - -#[starknet::contract] -mod contract { - #[storage] - pub struct Storage { - pub a: super::A, - #[allow(starknet::colliding_storage_paths)] - #[rename("a")] - pub b: super::B, - pub ab: super::AB, - } -} - -#[test] -fn rename_test() { - let mut state = contract::contract_state_for_testing(); - state.a.a.write(1); - assert_eq!(state.b.b.read(), 1); - state.b.b.write(2); - assert_eq!(state.a.a.read(), 2); - assert_eq!(state.ab.a.a.read(), 0); - state.ab.a.a.write(3); - assert_eq!(state.ab.b.b.read(), 3); - state.ab.b.b.write(4); - assert_eq!(state.ab.a.a.read(), 4); -} diff --git a/test_data/tests_starknet/cairo_level_tests/replace_class_test.cairo b/test_data/tests_starknet/cairo_level_tests/replace_class_test.cairo deleted file mode 100644 index 88e2f4b086..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/replace_class_test.cairo +++ /dev/null @@ -1,113 +0,0 @@ -use starknet::class_hash::ClassHash; -use starknet::syscalls::{deploy_syscall, get_class_hash_at_syscall}; - -#[starknet::interface] -trait IWithReplace { - fn replace(ref self: TContractState, class_hash: ClassHash); -} - -#[starknet::contract] -mod contract_a { - use starknet::SyscallResultTrait; - use starknet::class_hash::ClassHash; - use starknet::storage::StoragePointerWriteAccess; - - #[storage] - struct Storage { - value: u128, - } - - #[constructor] - fn constructor(ref self: ContractState, value: u128) { - self.value.write(value); - } - - #[abi(embed_v0)] - impl IWithReplaceImpl of super::IWithReplace { - fn replace(ref self: ContractState, class_hash: ClassHash) { - starknet::syscalls::replace_class_syscall(class_hash).unwrap_syscall(); - } - } -} - -#[starknet::interface] -trait IWithFoo { - fn foo(ref self: TContractState) -> u128; -} - -#[starknet::contract] -mod contract_b { - use starknet::storage::StoragePointerReadAccess; - #[storage] - struct Storage { - value: u128, - } - - #[external(v0)] - fn foo(ref self: ContractState) -> u128 { - self.value.read() - } -} - -#[test] -fn test_replace_flow() { - // Deploy ContractA with 100 in the storage. - let (address0, _) = deploy_syscall( - class_hash: contract_a::TEST_CLASS_HASH, - contract_address_salt: 0, - calldata: [100].span(), - deploy_from_zero: false, - ) - .unwrap(); - - // Replace its class hash to Class B. - let mut contract0 = IWithReplaceDispatcher { contract_address: address0 }; - contract0.replace(contract_b::TEST_CLASS_HASH); - - // Read the previously stored value. - let mut contract1 = IWithFooDispatcher { contract_address: address0 }; - assert_eq!(contract1.foo(), 100); -} - -#[test] -#[available_gas(30000000)] -#[should_panic(expected: ('CLASS_HASH_NOT_FOUND', 'ENTRYPOINT_FAILED'))] -fn test_cannot_replace_with_non_existing_class_hash() { - // Deploy ContractA with 100 in the storage. - let (address0, _) = deploy_syscall( - class_hash: contract_a::TEST_CLASS_HASH, - contract_address_salt: 0, - calldata: [100].span(), - deploy_from_zero: false, - ) - .unwrap(); - - // Replace its class hash to Class B. - let mut contract0 = IWithReplaceDispatcher { contract_address: address0 }; - contract0.replace('not a valid class hash'.try_into().unwrap()); -} - -#[test] -fn test_class_hash_at_syscall() { - // Deploy ContractA with 100 in the storage. - let (address0, _) = deploy_syscall( - class_hash: contract_a::TEST_CLASS_HASH, - contract_address_salt: 0, - calldata: [100].span(), - deploy_from_zero: false, - ) - .unwrap(); - - assert_eq!(get_class_hash_at_syscall(address0), Ok(contract_a::TEST_CLASS_HASH)); - // Replace its class hash to Class B. - IWithReplaceDispatcher { contract_address: address0 }.replace(contract_b::TEST_CLASS_HASH); - assert_eq!(get_class_hash_at_syscall(address0), Ok(contract_b::TEST_CLASS_HASH)); -} - -#[test] -fn test_class_hash_at_syscall_undeployed_contract() { - assert_eq!( - get_class_hash_at_syscall('undeployed'.try_into().unwrap()), - Ok(core::num::traits::Zero::zero()), - ); -} diff --git a/test_data/tests_starknet/cairo_level_tests/storage_access.cairo b/test_data/tests_starknet/cairo_level_tests/storage_access.cairo deleted file mode 100644 index f0d65fa4ee..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/storage_access.cairo +++ /dev/null @@ -1,326 +0,0 @@ -#[feature("deprecated-bounded-int-trait")] -use core::integer::BoundedInt; -use core::num::traits::Zero; -use starknet::storage::{ - Map, MutableVecTrait, StorageMapReadAccess, StoragePointerReadAccess, StoragePointerWriteAccess, - SubPointersForward, Vec, -}; -use starknet::{ClassHash, ContractAddress, EthAddress, StorageAddress}; - -impl StorageAddressPartialEq of PartialEq { - fn eq(lhs: @StorageAddress, rhs: @StorageAddress) -> bool { - let lhs: felt252 = (*lhs).into(); - let rhs: felt252 = (*rhs).into(); - lhs == rhs - } -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq, starknet::Store)] -struct Abc { - a: u8, - b: u16, - c: u32, -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq)] -struct TupleStructure { - v1: u256, - v2: u256, -} -impl TupleStructureStorePacking of starknet::storage_access::StorePacking< - TupleStructure, (felt252, felt252), -> { - fn pack(value: TupleStructure) -> (felt252, felt252) { - (value.v1.try_into().unwrap(), value.v2.try_into().unwrap()) - } - fn unpack(value: (felt252, felt252)) -> TupleStructure { - let (v1, v2) = value; - TupleStructure { v1: v1.into(), v2: v2.into() } - } -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq, starknet::Store)] -enum Efg { - #[default] - E: (), - F: (), - G: u256, -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq, starknet::Store)] -struct AbcEtc { - a: u8, - b: u16, - c: u32, - d: u64, - e: u128, - f: u256, - g: ContractAddress, - h: ClassHash, - i: StorageAddress, - j: bool, - k: EthAddress, - abc: Abc, - ts: TupleStructure, - efg1: Efg, - efg2: Efg, -} - -#[derive(Clone, Drop, Debug, Serde, PartialEq, starknet::Store)] -struct ByteArrays { - empty: ByteArray, - single_word: ByteArray, - multi_word: ByteArray, - multi_chunk: ByteArray, -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq, starknet::Store)] -struct NonZeros { - value_u8: NonZero, - value_u256: NonZero, - value_felt252: NonZero, -} - -#[starknet::storage_node] -struct Vecs { - vec: Vec, - vec_of_vecs: Vec>, - #[allow(starknet::colliding_storage_paths)] - #[rename("vec")] - equiv_map: Map, -} - -#[derive(Copy, Drop, Debug, Serde, PartialEq, starknet::Store)] -#[starknet::sub_pointers(QueryableEnumVariants)] -enum QueryableEnum { - #[default] - A: (), - B: u128, - C: u256, -} - -#[starknet::contract] -mod test_contract { - #[storage] - pub struct Storage { - pub data: super::AbcEtc, - pub byte_arrays: super::ByteArrays, - pub non_zeros: super::NonZeros, - pub vecs: super::Vecs, - pub queryable_enum: super::QueryableEnum, - pub option_value: Option, - pub offset_option_value: (felt252, Option), - pub result_value: Result, - pub offset_result_value: (felt252, Result), - } -} - -#[test] -fn write_read_struct() { - let mut state = test_contract::contract_state_for_testing(); - let value = AbcEtc { - a: 1_u8, - b: 2_u16, - c: 3_u32, - d: 4_u64, - e: 5_u128, - f: BoundedInt::max() - 1, - g: Zero::zero(), - h: Zero::zero(), - i: 123.try_into().unwrap(), - j: true, - k: 123_felt252.try_into().unwrap(), - abc: Abc { a: 1_u8, b: 2_u16, c: 3_u32 }, - ts: TupleStructure { v1: 1_u256, v2: 2_u256 }, - efg1: Efg::E, - efg2: Efg::G(123_u256), - }; - state.data.write(value); - assert_eq!(state.data.read(), value); - assert_eq!(state.data.f.low.read(), value.f.low); - assert_eq!(state.data.f.high.read(), value.f.high); -} - -#[test] -fn write_read_byte_arrays() { - let mut multi_chunk: ByteArray = - "0123456789abcdef0123456789abcdef"; // 32 bytes, 2 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 64 bytes, 3 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 128 bytes, 5 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 256 bytes, 9 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 512 bytes, 17 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 1024 bytes, 34 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 2048 bytes, 67 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 4096 bytes, 133 felt252s, 1 chunk. - multi_chunk.append(@multi_chunk); // 8192 bytes, 265 felt252s, 2 chunks. - multi_chunk.append(@multi_chunk); // 16384 bytes, 529 felt252s, 3 chunks. - let value = ByteArrays { - empty: "", - single_word: "shorter than 31", - multi_word: "a byte array with more than 31 bytes", - multi_chunk, - }; - let mut state = test_contract::contract_state_for_testing(); - state.byte_arrays.write(value.clone()); - assert_eq!(state.byte_arrays.read(), value); - // Make sure the lengths were saved correctly. - let base_address = starknet::storage_access::storage_base_address_from_felt252( - selector!("byte_arrays"), - ); - assert!(starknet::Store::read_at_offset(0, base_address, 0) == Ok(0_usize)); - assert!(starknet::Store::read_at_offset(0, base_address, 1) == Ok(15_usize)); - assert!(starknet::Store::read_at_offset(0, base_address, 2) == Ok(36_usize)); - assert!(starknet::Store::read_at_offset(0, base_address, 3) == Ok(16384_usize)); - // Make sure the internal data was saved correctly. - let (r, _, _) = core::poseidon::hades_permutation( - starknet::storage_access::storage_address_from_base_and_offset(base_address, 3).into(), - 2, - 'ByteArray'_felt252, - ); - let internal_data_address = starknet::storage_access::storage_base_address_from_felt252(r); - assert_eq!( - starknet::Store::read_at_offset(0, internal_data_address, 0), - Ok('0123456789abcdef0123456789abcde'_felt252), - ); - assert_eq!( - starknet::Store::read_at_offset(0, internal_data_address, 1), - Ok('f0123456789abcdef0123456789abcd'_felt252), - ); - assert_eq!( - starknet::Store::read_at_offset(0, internal_data_address, 2), - Ok('ef0123456789abcdef0123456789abc'_felt252), - ); -} - -#[test] -fn test_read_write_non_zero() { - let value = NonZeros { - value_u8: 1_u8.try_into().unwrap(), - value_u256: 3_u256.try_into().unwrap(), - value_felt252: 5_felt252.try_into().unwrap(), - }; - let mut state = test_contract::contract_state_for_testing(); - state.non_zeros.write(value); - assert_eq!(state.non_zeros.read(), value); -} - -#[test] -fn test_storage_array() { - let mut state = test_contract::contract_state_for_testing(); - state.vecs.vec.push(1_u32); - state.vecs.vec.push(2_u32); - state.vecs.vec.push(3_u32); - assert_eq!(state.vecs.vec.len(), 3); - assert_eq!(state.vecs.vec[0].read(), 1); - assert_eq!(state.vecs.vec[1].read(), 2); - assert_eq!(state.vecs.vec[2].read(), 3); - assert_eq!(state.vecs.equiv_map.read(0), 1); - assert_eq!(state.vecs.equiv_map.read(1), 2); - assert_eq!(state.vecs.equiv_map.read(2), 3); - assert_eq!(state.vecs.equiv_map.read(3), 0); -} - -#[test] -fn test_storage_vec_of_vecs() { - let mut state = test_contract::contract_state_for_testing(); - state.vecs.vec_of_vecs.allocate(); - state.vecs.vec_of_vecs[0].push(1); - state.vecs.vec_of_vecs[0].push(2); - state.vecs.vec_of_vecs[0].push(3); - state.vecs.vec_of_vecs.allocate(); - state.vecs.vec_of_vecs[1].push(4); - state.vecs.vec_of_vecs[1].push(5); - assert_eq!(state.vecs.vec_of_vecs.len(), 2); - assert_eq!(state.vecs.vec_of_vecs[0].len(), 3); - assert_eq!(state.vecs.vec_of_vecs[0][0].read(), 1); - assert_eq!(state.vecs.vec_of_vecs[0][1].read(), 2); - assert_eq!(state.vecs.vec_of_vecs[0][2].read(), 3); - assert_eq!(state.vecs.vec_of_vecs[1].len(), 2); - assert_eq!(state.vecs.vec_of_vecs[1][0].read(), 4); - assert_eq!(state.vecs.vec_of_vecs[1][1].read(), 5); -} - -#[test] -fn test_enum_sub_pointers() { - let mut state = test_contract::contract_state_for_testing(); - state.queryable_enum.write(QueryableEnum::A); - let QueryableEnumVariants::A(_) = (@state).queryable_enum.sub_pointers() else { - panic!("expected QueryableEnumVariants::A(_)"); - }; - state.queryable_enum.write(QueryableEnum::B(123_u128)); - let QueryableEnumVariants::B(ptr) = (@state).queryable_enum.sub_pointers() else { - panic!("expected QueryableEnumVariants::B(_)"); - }; - assert_eq!(ptr.read(), 123); - state.queryable_enum.write(QueryableEnum::C(456_u256)); - let QueryableEnumVariants::C(ptr) = (@state).queryable_enum.sub_pointers() else { - panic!("expected QueryableEnumVariants::C(_)"); - }; - assert_eq!(ptr.low.read(), 456); - assert_eq!(ptr.high.read(), 0); - state.queryable_enum.write(QueryableEnum::C(789_u256)); - let QueryableEnumVariants::C(ptr) = (@state).queryable_enum.sub_pointers() else { - panic!("expected QueryableEnumVariants::C(_)"); - }; - assert_eq!(ptr.low.read(), 789); - assert_eq!(ptr.high.read(), 0); -} - -#[test] -fn test_option_and_result_base_access() { - let mut state = test_contract::contract_state_for_testing(); - state.option_value.write(Some(101_u32)); - state.offset_option_value.write((202_felt252, Some(102_u32))); - state.result_value.write(Ok(103_u32)); - state.offset_result_value.write((204_felt252, Ok(104_u32))); - assert_eq!((@state).option_value.read(), Some(101)); - assert_eq!((@state).offset_option_value.read(), (202_felt252, Some(102_u32))); - assert_eq!((@state).result_value.read(), Ok(103)); - assert_eq!((@state).offset_result_value.read(), (204_felt252, Ok(104_u32))); - state.option_value.write(None); - state.offset_option_value.write((205_felt252, None)); - state.result_value.write(Err(106_u32)); - state.offset_result_value.write((207_felt252, Err(107_u32))); - assert_eq!((@state).option_value.read(), None); - assert_eq!((@state).offset_option_value.read(), (205_felt252, None)); - assert_eq!((@state).result_value.read(), Err(106)); - assert_eq!((@state).offset_result_value.read(), (207_felt252, Err(107_u32))); -} - -#[test] -fn test_option_sub_pointers() { - let mut state = test_contract::contract_state_for_testing(); - assert!((@state).option_value.sub_pointers().is_none()); - state.option_value.write(Some(123_u32)); - let Some(ptr) = (@state).option_value.sub_pointers() else { - panic!("expected Some(_)"); - }; - assert_eq!(ptr.read(), 123); - - let Some(ptr) = state.option_value.sub_pointers_mut() else { - panic!("expected Some(_)"); - }; - assert_eq!(ptr.read(), 123); - ptr.write(234); - assert_eq!(state.option_value.read(), Some(234)); -} - -#[test] -fn test_scrub_clears_memory() { - let base_address = starknet::storage_access::storage_base_address_from_felt252( - selector!("data"), - ); - for i in 0..=255_u8 { - starknet::Store::::write_at_offset(0, base_address, i, 1).unwrap(); - } - starknet::Store::<[felt252; 11]>::scrub(0, base_address, 7).unwrap(); - for i in 0..7_u8 { - assert_eq!(starknet::Store::::read_at_offset(0, base_address, i), Ok(1)); - } - for i in 7..18_u8 { - assert_eq!(starknet::Store::::read_at_offset(0, base_address, i), Ok(0)); - } - for i in 18..=255_u8 { - assert_eq!(starknet::Store::::read_at_offset(0, base_address, i), Ok(1)); - } -} diff --git a/test_data/tests_starknet/cairo_level_tests/utils.cairo b/test_data/tests_starknet/cairo_level_tests/utils.cairo deleted file mode 100644 index 9eb3612f93..0000000000 --- a/test_data/tests_starknet/cairo_level_tests/utils.cairo +++ /dev/null @@ -1,9 +0,0 @@ -pub fn serialized, +Destruct>(value: T) -> Span { - let mut arr = Default::default(); - value.serialize(ref arr); - arr.span() -} - -pub fn deserialized, +Destruct>(mut value: Span) -> T { - Serde::deserialize(ref value).unwrap() -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index eeb00cff7c..769cd2e4b3 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -52,6 +52,12 @@ use proptest::{strategy::Strategy, test_runner::TestCaseError}; use starknet_types_core::felt::Felt; use std::{collections::HashMap, env::var, fs, ops::Neg, path::Path}; +/// Creates an `Arg::Value` from a `Felt`, bridging the starknet-types-core +/// version gap (our 1.0.0 vs cairo-lang's 0.2.x). +pub fn felt_to_arg(felt: Felt) -> Arg { + Arg::Value(felt.to_biguint().into()) +} + #[allow(unused_macros)] macro_rules! load_cairo { ( $( $program:tt )+ ) => { @@ -333,7 +339,7 @@ pub fn run_vm_contract( let result = runner .run_function_with_starknet_context( runner.find_function(&func_name).unwrap(), - vec![Arg::Array(args.iter().cloned().map(Arg::Value).collect())], + vec![Arg::Array(args.iter().cloned().map(felt_to_arg).collect())], Some(usize::MAX), StarknetState::default(), ) @@ -359,7 +365,10 @@ pub fn run_vm_contract( result.memory[start..end] .iter() - .map(|cell| cell.expect("memory cell in span range should be initialized")) + .map(|cell| { + let old_felt = cell.expect("memory cell in span range should be initialized"); + Felt::from_bytes_be(&old_felt.to_bytes_be()) + }) .collect() } RunResultValue::Panic(values) => { @@ -759,11 +768,12 @@ pub fn compare_outputs( .map(|x| x.starts_with("core::panics::PanicResult")) .unwrap_or(false) }); + // Convert old Felt (0.2.x from cairo-lang) gas counter to BigInt for comparison. assert_eq!( vm_result .gas_counter - .unwrap_or_else(|| Felt::from(0)) - .to_bigint(), + .map(|f| f.to_bigint()) + .unwrap_or_default(), Felt::from(native_result.remaining_gas.unwrap_or(0)).to_bigint(), "gas mismatch" ); @@ -797,8 +807,19 @@ pub fn compare_outputs( assert_eq_sorted!(vm_builtins, native_builtins, "builtin mismatch",); + // Convert old Felt (0.2.x from cairo-lang) to new Felt (1.0.0). + let vm_memory: Vec> = vm_result + .memory + .iter() + .map(|cell| cell.as_ref().map(|f| Felt::from_bytes_be(&f.to_bytes_be()))) + .collect(); + let vm_result = match &vm_result.value { RunResultValue::Success(values) if !values.is_empty() | returns_panic => { + let values: Vec = values + .iter() + .map(|f| Felt::from_bytes_be(&f.to_bytes_be())) + .collect(); if returns_panic { let inner_ty = match registry.get_type(ty.unwrap())? { CoreTypeConcrete::Enum(info) => &info.variants[0], @@ -809,8 +830,8 @@ pub fn compare_outputs( value: Box::new(map_vm_values( &mut size_cache, ®istry, - &vm_result.memory, - values, + &vm_memory, + &values, inner_ty, )), debug_name: None, @@ -819,8 +840,8 @@ pub fn compare_outputs( map_vm_values( &mut size_cache, ®istry, - &vm_result.memory, - values, + &vm_memory, + &values, ty.unwrap(), ) } else { diff --git a/tests/tests/arrays.rs b/tests/tests/arrays.rs index 613e29d6d9..fe1de8405d 100644 --- a/tests/tests/arrays.rs +++ b/tests/tests/arrays.rs @@ -1,6 +1,5 @@ -use crate::common::{any_felt, run_native_program, run_vm_program}; +use crate::common::{any_felt, felt_to_arg, run_native_program, run_vm_program}; use crate::common::{compare_outputs, DEFAULT_GAS}; -use cairo_lang_runner::Arg; use cairo_native::starknet::DummySyscallHandler; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::Value; @@ -13,7 +12,7 @@ fn array_get_test() { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from(10)), Arg::Value(Felt::from(5))], + vec![felt_to_arg(Felt::from(10)), felt_to_arg(Felt::from(5))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -39,8 +38,8 @@ proptest! { fn array_get_test_proptest(value in any_felt(), idx in 0u32..26) { let program = &load_program_and_runner("test_data_artifacts/programs/array_get"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from_bytes_be(&value.to_bytes_be())), - Arg::Value(Felt::from(idx)) + felt_to_arg(Felt::from_bytes_be(&value.to_bytes_be())), + felt_to_arg(Felt::from(idx)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, diff --git a/tests/tests/boolean.rs b/tests/tests/boolean.rs index 14f8476c74..989d71a0e4 100644 --- a/tests/tests/boolean.rs +++ b/tests/tests/boolean.rs @@ -1,5 +1,4 @@ -use crate::common::{compare_outputs, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_lang_runner::Arg; +use crate::common::{compare_outputs, felt_to_arg, run_native_program, run_vm_program, DEFAULT_GAS}; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::{starknet::DummySyscallHandler, Value}; use proptest::prelude::*; @@ -12,7 +11,7 @@ fn felt252_to_bool_bug() { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from(a))], + vec![felt_to_arg(Felt::from(a))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -36,7 +35,7 @@ fn felt252_to_bool_bug() { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from(a))], + vec![felt_to_arg(Felt::from(a))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -62,7 +61,7 @@ proptest! { fn bool_to_felt252_proptest(a: bool) { let program = &load_program_and_runner("test_data_artifacts/programs/bool_to_felt252"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from(a)), + felt_to_arg(Felt::from(a)), ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -85,7 +84,7 @@ proptest! { fn bool_not_proptest(a: bool) { let program = &load_program_and_runner("test_data_artifacts/programs/bool_not"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from(a)), + felt_to_arg(Felt::from(a)), ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -108,8 +107,8 @@ proptest! { fn bool_and_proptest(a: bool, b: bool) { let program = &load_program_and_runner("test_data_artifacts/programs/bool_and"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from(a)), - Arg::Value(Felt::from(b)) + felt_to_arg(Felt::from(a)), + felt_to_arg(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -132,8 +131,8 @@ proptest! { fn bool_or_proptest(a: bool, b: bool) { let program = &load_program_and_runner("test_data_artifacts/programs/bool_or"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from(a)), - Arg::Value(Felt::from(b)) + felt_to_arg(Felt::from(a)), + felt_to_arg(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, @@ -156,8 +155,8 @@ proptest! { fn bool_xor_proptest(a: bool, b: bool) { let program = &load_program_and_runner("test_data_artifacts/programs/bool_xor"); let result_vm = run_vm_program(program, "run_test", vec![ - Arg::Value(Felt::from(a)), - Arg::Value(Felt::from(b)) + felt_to_arg(Felt::from(a)), + felt_to_arg(Felt::from(b)) ], Some(DEFAULT_GAS as usize)).unwrap(); let result_native = run_native_program( program, diff --git a/tests/tests/dict.rs b/tests/tests/dict.rs index 7a32e2efa6..4c04201a40 100644 --- a/tests/tests/dict.rs +++ b/tests/tests/dict.rs @@ -1,5 +1,6 @@ -use crate::common::{any_felt, compare_outputs, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_lang_runner::Arg; +use crate::common::{ + any_felt, compare_outputs, felt_to_arg, run_native_program, run_vm_program, DEFAULT_GAS, +}; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::{starknet::DummySyscallHandler, Value}; use proptest::prelude::*; @@ -12,7 +13,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/e2e_libfuncs.rs b/tests/tests/e2e_libfuncs.rs new file mode 100644 index 0000000000..822a40432c --- /dev/null +++ b/tests/tests/e2e_libfuncs.rs @@ -0,0 +1,60 @@ +use cairo_lang_sierra::ProgramParser; +use cairo_native::context::NativeContext; +use std::fs; +use std::path::Path; + +/// Collects all `.sierra` files under the e2e_sierra directory and compiles each +/// through cairo-native (Sierra → LLVM) to verify they compile without errors. +#[test] +fn compile_e2e_libfunc_sierra() { + let sierra_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("test_data/e2e_sierra"); + assert!( + sierra_dir.exists(), + "{} not found. Run 'git submodule update --init && make test_data/e2e_sierra' first.", + sierra_dir.display() + ); + + let context = NativeContext::new(); + let parser = ProgramParser::new(); + + let mut total = 0; + let mut failures = Vec::new(); + + for entry in walkdir::WalkDir::new(&sierra_dir) { + let entry = entry.unwrap(); + let path = entry.path(); + if path.extension().is_some_and(|e| e == "sierra") { + total += 1; + let source = fs::read_to_string(path).unwrap(); + let rel_path = path.strip_prefix(&sierra_dir).unwrap(); + + let program = match parser.parse(&source) { + Ok(p) => p, + Err(e) => { + failures.push(format!("{}: parse error: {e}", rel_path.display())); + continue; + } + }; + + eprintln!("compiling {}", rel_path.display()); + if let Err(e) = context.compile(&program, false, Some(Default::default()), None) { + failures.push(format!("{}: compile error: {e}", rel_path.display())); + } + } + } + + assert!( + total > 0, + "No .sierra files found in {}", + sierra_dir.display() + ); + + if !failures.is_empty() { + panic!( + "{}/{} e2e libfunc sierra files failed to compile:\n{}", + failures.len(), + total, + failures.join("\n") + ); + } +} diff --git a/tests/tests/ec.rs b/tests/tests/ec.rs index 97f33c05c4..9534c6bad1 100644 --- a/tests/tests/ec.rs +++ b/tests/tests/ec.rs @@ -1,5 +1,6 @@ -use crate::common::{any_felt, compare_outputs, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_lang_runner::Arg; +use crate::common::{ + any_felt, compare_outputs, felt_to_arg, run_native_program, run_vm_program, DEFAULT_GAS, +}; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::{starknet::DummySyscallHandler, Value}; use num_bigint::BigUint; @@ -41,7 +42,7 @@ fn ec_point_from_x_big() { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(x)], + vec![felt_to_arg(x)], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -69,7 +70,7 @@ fn ec_point_from_x_small() { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(x)], + vec![felt_to_arg(x)], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -97,7 +98,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -123,7 +124,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/felt252.rs b/tests/tests/felt252.rs index f38a91857b..fbd94087d5 100644 --- a/tests/tests/felt252.rs +++ b/tests/tests/felt252.rs @@ -1,7 +1,7 @@ use crate::common::{ - any_felt, compare_outputs, nonzero_felt, run_native_program, run_vm_program, DEFAULT_GAS, + any_felt, compare_outputs, felt_to_arg, nonzero_felt, run_native_program, run_vm_program, + DEFAULT_GAS, }; -use cairo_lang_runner::Arg; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::{starknet::DummySyscallHandler, Value}; use proptest::prelude::*; @@ -14,7 +14,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -40,7 +40,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -66,7 +66,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -92,7 +92,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/mod.rs b/tests/tests/mod.rs index d864318e8d..9526058119 100644 --- a/tests/tests/mod.rs +++ b/tests/tests/mod.rs @@ -5,6 +5,7 @@ pub mod cases; pub mod circuit; pub mod compile_library; pub mod dict; +pub mod e2e_libfuncs; pub mod ec; pub mod felt252; pub mod libfuncs; diff --git a/tests/tests/programs.rs b/tests/tests/programs.rs index aee4938af9..be88ef3e4e 100644 --- a/tests/tests/programs.rs +++ b/tests/tests/programs.rs @@ -1,5 +1,6 @@ -use crate::common::{any_felt, compare_outputs, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_lang_runner::Arg; +use crate::common::{ + any_felt, compare_outputs, felt_to_arg, run_native_program, run_vm_program, DEFAULT_GAS, +}; use cairo_native::starknet::DummySyscallHandler; use cairo_native::utils::felt252_str; use cairo_native::utils::testing::load_program_and_runner; @@ -13,7 +14,7 @@ fn fib() { let result_vm = run_vm_program( &program, "fibonacci", - vec![Arg::Value(Felt::from(10))], + vec![felt_to_arg(Felt::from(10))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -40,7 +41,7 @@ fn logistic_map() { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from(1000))], + vec![felt_to_arg(Felt::from(1000))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -68,13 +69,13 @@ fn pedersen() { &program, "run_test", vec![ - Arg::Value( + felt_to_arg( Felt::from_dec_str( "2163739901324492107409690946633517860331020929182861814098856895601180685", ) .unwrap(), ), - Arg::Value( + felt_to_arg( Felt::from_dec_str( "2392090257937917229310563411601744459500735555884672871108624696010915493156", ) @@ -114,7 +115,7 @@ fn factorial() { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from(13))], + vec![felt_to_arg(Felt::from(13))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -142,7 +143,7 @@ proptest! { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from(n))], + vec![felt_to_arg(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -168,7 +169,7 @@ proptest! { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from(n))], + vec![felt_to_arg(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -194,7 +195,7 @@ proptest! { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from(n))], + vec![felt_to_arg(Felt::from(n))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -220,7 +221,7 @@ proptest! { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -247,9 +248,9 @@ proptest! { let result_vm = run_vm_program( &program, "run_test", - vec![Arg::Value(Felt::from_bytes_be(&a.clone().to_bytes_be())), - Arg::Value(Felt::from_bytes_be(&b.clone().to_bytes_be())), - Arg::Value(Felt::from_bytes_be(&c.clone().to_bytes_be()))], + vec![felt_to_arg(Felt::from_bytes_be(&a.clone().to_bytes_be())), + felt_to_arg(Felt::from_bytes_be(&b.clone().to_bytes_be())), + felt_to_arg(Felt::from_bytes_be(&c.clone().to_bytes_be()))], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/tests/tests/uint.rs b/tests/tests/uint.rs index a4b08a2ea3..dfc5437073 100644 --- a/tests/tests/uint.rs +++ b/tests/tests/uint.rs @@ -1,5 +1,4 @@ -use crate::common::{compare_outputs, run_native_program, run_vm_program, DEFAULT_GAS}; -use cairo_lang_runner::Arg; +use crate::common::{compare_outputs, felt_to_arg, run_native_program, run_vm_program, DEFAULT_GAS}; use cairo_native::utils::testing::load_program_and_runner; use cairo_native::{starknet::DummySyscallHandler, Value}; use proptest::prelude::*; @@ -11,7 +10,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -37,7 +36,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -63,7 +62,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -89,7 +88,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -115,7 +114,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -141,7 +140,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -169,7 +168,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -195,7 +194,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -221,7 +220,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -247,7 +246,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -273,7 +272,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -299,7 +298,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -327,7 +326,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -353,7 +352,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -379,7 +378,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -405,7 +404,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -431,7 +430,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -457,7 +456,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -485,7 +484,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -511,7 +510,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -537,7 +536,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -563,7 +562,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -589,7 +588,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -615,7 +614,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -643,7 +642,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -669,7 +668,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -695,7 +694,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -721,7 +720,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into()), Arg::Value(b.into())], + vec![felt_to_arg(a.into()), felt_to_arg(b.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -747,7 +746,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); @@ -773,7 +772,7 @@ proptest! { let result_vm = run_vm_program( program, "run_test", - vec![Arg::Value(a.into())], + vec![felt_to_arg(a.into())], Some(DEFAULT_GAS as usize), ) .unwrap(); diff --git a/vendor/cairo b/vendor/cairo new file mode 160000 index 0000000000..6a43d7c941 --- /dev/null +++ b/vendor/cairo @@ -0,0 +1 @@ +Subproject commit 6a43d7c9419481fcb82376447fecf85c44d8fbbf

, - +Destruct, -> of Iterator> { - type Item = TIter::Item; - fn next(ref self: Filter) -> Option { - self.iter.find(@self.predicate) - } -} diff --git a/corelib/src/iter/adapters/map.cairo b/corelib/src/iter/adapters/map.cairo deleted file mode 100644 index 51fd1c6d65..0000000000 --- a/corelib/src/iter/adapters/map.cairo +++ /dev/null @@ -1,32 +0,0 @@ -/// An iterator that maps the values of `iter` with `f`. -/// -/// This `struct` is created by the [`map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map`]: Iterator::map -/// [`Iterator`]: core::iter::Iterator -/// -#[must_use] -#[derive(Drop, Clone)] -pub struct Map { - iter: I, - f: F, -} - -pub fn mapped_iterator(iter: I, f: F) -> Map { - Map { iter, f } -} - -impl MapIterator< - I, - F, - impl TIter: Iterator, - impl func: core::ops::Fn, - +Destruct, - +Destruct, -> of Iterator> { - type Item = func::Output; - fn next(ref self: Map) -> Option { - self.iter.next().map(@self.f) - } -} diff --git a/corelib/src/iter/adapters/peekable.cairo b/corelib/src/iter/adapters/peekable.cairo deleted file mode 100644 index 3561d8b7b1..0000000000 --- a/corelib/src/iter/adapters/peekable.cairo +++ /dev/null @@ -1,90 +0,0 @@ -/// An iterator with a `peek()` that returns a copy of the next -/// element. -/// -/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`peekable`]: Iterator::peekable -#[must_use] -#[derive(Drop, Debug)] -pub struct Peekable { - /// The underlying iterator. - iter: I, - /// Caches the next value of the iterator when `peek()` is called, - /// consuming the iterator only once even when several consecutive calls - /// to `peek()` are made. - /// - /// - `None`: Indicates that no peek has been performed. - /// - `Some(None)`: Indicates that a peek has been performed but the iterator is exhausted. - /// - `Some(Some(R))`: Contains the next element in the iterator, ready to be returned by - /// `peek()`. - /// - /// `peeked` is reset to `None` when `next()` is called. - peeked: Option>, -} - -pub fn peekable_iterator(iter: I) -> Peekable { - Peekable { iter, peeked: Option::None } -} - -impl PeekableIterator< - I, impl IterI: Iterator, +Destruct, +Destruct, -> of Iterator> { - type Item = IterI::Item; - - fn next(ref self: Peekable) -> Option { - let next_value = match self.peeked { - Option::Some(v) => v, - Option::None => self.iter.next(), - }; - self.peeked = Option::None; - next_value - } -} - -#[generate_trait] -pub impl PeekableTraitImpl< - I, impl IterI: Iterator, +Copy, +Drop, -> of PeekableTrait { - /// Returns a copy of the next() value without advancing the iterator. - /// - /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. - /// But if the iteration is over, `None` is returned. - /// - /// [`next`]: Iterator::next - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = (1..4_u8).into_iter().peekable(); - /// - /// // peek() lets us see one step into the future - /// assert_eq!(iter.peek(), Some(1)); - /// assert_eq!(iter.next(), Some(1)); - /// - /// assert_eq!(iter.next(), Some(2)); - /// - /// // The iterator does not advance even if we `peek` multiple times - /// assert_eq!(iter.peek(), Some(3)); - /// assert_eq!(iter.peek(), Some(3)); - /// - /// assert_eq!(iter.next(), Some(3)); - /// - /// // After the iterator is finished, so is `peek()` - /// assert_eq!(iter.peek(), None); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - fn peek(ref self: Peekable) -> Option { - match self.peeked { - Option::Some(value) => value, - Option::None => { - let next_value = self.iter.next(); - self.peeked = Option::Some(next_value); - next_value - }, - } - } -} diff --git a/corelib/src/iter/adapters/take.cairo b/corelib/src/iter/adapters/take.cairo deleted file mode 100644 index 27c91f98ad..0000000000 --- a/corelib/src/iter/adapters/take.cairo +++ /dev/null @@ -1,76 +0,0 @@ -use crate::num::traits::CheckedSub; - -/// An iterator that only iterates over the first `n` iterations of `iter`. -/// -/// This `struct` is created by the [`take`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take`]: Iterator::take -#[must_use] -#[derive(Drop, Clone)] -pub struct Take { - iter: I, - n: usize, -} - -pub fn take_iterator(iter: I, n: usize) -> Take { - Take { iter, n } -} - -impl TakeIterator, +Drop> of Iterator> { - type Item = TIter::Item; - #[inline] - fn next(ref self: Take) -> Option { - self.n = self.n.checked_sub(1)?; - self.iter.next() - } - - #[inline] - fn nth<+Destruct>, +Destruct>( - ref self: Take, n: usize, - ) -> Option { - if let Some(updated_n) = self.n.checked_sub(n + 1) { - self.n = updated_n; - self.iter.nth(n) - } else { - if self.n != 0 { - let _ = self.iter.advance_by(self.n); - self.n = 0; - } - None - } - } - - #[inline] - fn advance_by<+Destruct>, +Destruct>( - ref self: Take, n: usize, - ) -> Result<(), NonZero> { - if let Some(updated_n) = self.n.checked_sub(n) { - self.n = updated_n; - match self.iter.advance_by(n) { - Ok(_) => Ok(()), - Err(rem_nz) => { - self.n += rem_nz.into(); - Err(rem_nz) - }, - } - } else { - let available = self.n; - let inner_taken = match self.iter.advance_by(available) { - Ok(_) => { - self.n = 0; - available - }, - Err(inner_untaken) => { - self.n = inner_untaken.into(); - available - self.n - }, - }; - match (n - inner_taken).try_into() { - Some(nz) => Err(nz), - // Can't actually happen - but preventing the `unwrap` generated code. - None => Ok(()), - } - } - } -} diff --git a/corelib/src/iter/adapters/zip.cairo b/corelib/src/iter/adapters/zip.cairo deleted file mode 100644 index 1f32e9f542..0000000000 --- a/corelib/src/iter/adapters/zip.cairo +++ /dev/null @@ -1,70 +0,0 @@ -/// An iterator that iterates two other iterators simultaneously. -/// -/// This `struct` is created by [`zip`] or [`Iterator::zip`]. -/// See their documentation for more. -/// -/// [`Iterator::zip`]: core::iter::Iterator::zip -#[derive(Drop, Clone)] -#[must_use] -pub struct Zip { - a: A, - b: B, -} - -#[inline] -pub fn zipped_iterator(a: A, b: B) -> Zip { - Zip { a, b } -} - -/// Converts the arguments to iterators and zips them. -/// -/// See the documentation of [`Iterator::zip`] for more. -/// -/// # Examples -/// -/// ``` -/// use core::iter::zip; -/// -/// let xs = array![1, 2, 3]; -/// let ys = array![4, 5, 6]; -/// -/// let mut iter = zip(xs, ys); -/// -/// assert_eq!(iter.next().unwrap(), (1, 4)); -/// assert_eq!(iter.next().unwrap(), (2, 5)); -/// assert_eq!(iter.next().unwrap(), (3, 6)); -/// assert!(iter.next().is_none()); -/// ``` -#[inline] -pub fn zip< - A, - B, - impl AIntoIter: IntoIterator, - impl BIntoIter: IntoIterator, - +Destruct, - +Destruct, ->( - a: A, b: B, -) -> Zip { - zipped_iterator(a.into_iter(), b.into_iter()) -} - -impl ZipIterator< - A, - B, - impl IterA: Iterator, - impl IterB: Iterator, - +Destruct, - +Destruct, - +Destruct, - +Destruct, -> of Iterator> { - type Item = (IterA::Item, IterB::Item); - - #[inline] - fn next(ref self: Zip) -> Option { - let a = self.a.next()?; - let b = self.b.next()?; - Some((a, b)) - } -} diff --git a/corelib/src/iter/traits.cairo b/corelib/src/iter/traits.cairo deleted file mode 100644 index 6c03be86d7..0000000000 --- a/corelib/src/iter/traits.cairo +++ /dev/null @@ -1,6 +0,0 @@ -mod accum; -mod collect; -mod iterator; -pub use accum::{Product, Sum}; -pub use collect::{Extend, FromIterator, IntoIterator}; -pub use iterator::Iterator; diff --git a/corelib/src/iter/traits/accum.cairo b/corelib/src/iter/traits/accum.cairo deleted file mode 100644 index d83cc0f4ab..0000000000 --- a/corelib/src/iter/traits/accum.cairo +++ /dev/null @@ -1,40 +0,0 @@ -/// Trait to represent types that can be created by summing up an iterator. -/// -/// This trait is used to implement [`Iterator::sum()`]. Types which implement -/// this trait can be generated by using the [`sum()`] method on an iterator. -/// Like [`FromIterator`], this trait should rarely be called directly. -/// -/// [`sum()`]: crate::iter::Iterator::sum -/// [`FromIterator`]: crate::iter::FromIterator -pub trait Sum { - /// Takes an iterator and generates `Self` from the elements by "summing up" - /// the items. - fn sum[Item: A], +Destruct, +Destruct>(iter: I) -> A; -} - -impl SumAddableTypesImpl, impl ZeroA: core::num::traits::Zero> of Sum { - fn sum[Item: A], +Destruct, +Destruct>(mut iter: I) -> A { - iter.fold(ZeroA::zero(), |acc, x| acc + x) - } -} -/// Trait to represent types that can be created by multiplying elements of an -/// iterator. -/// -/// This trait is used to implement [`Iterator::product()`]. Types which implement -/// this trait can be generated by using the [`product()`] method on an iterator. -/// Like [`FromIterator`], this trait should rarely be called directly. -/// -/// [`product()`]: Iterator::product -/// [`FromIterator`]: crate::iter::FromIterator -pub trait Product { - /// Takes an iterator and generates `Self` from the elements by multiplying the items. - fn product[Item: A], +Destruct, +Destruct>(iter: I) -> A; -} - -impl ProductMultiplicativeTypesImpl< - A, +Mul, impl OneA: core::num::traits::One, -> of Product { - fn product[Item: A], +Destruct, +Destruct>(mut iter: I) -> A { - iter.fold(OneA::one(), |acc, x| acc * x) - } -} diff --git a/corelib/src/iter/traits/collect.cairo b/corelib/src/iter/traits/collect.cairo deleted file mode 100644 index 4dbdc7c12c..0000000000 --- a/corelib/src/iter/traits/collect.cairo +++ /dev/null @@ -1,249 +0,0 @@ -use crate::metaprogramming::TypeEqual; - -/// Conversion from an [`Iterator`]. -/// -/// By implementing `FromIterator` for a type, you define how it will be -/// created from an iterator. This is common for types that describe a -/// collection of some kind. -/// -/// If you want to create a collection from the contents of an iterator, the -/// [`Iterator::collect()`] method is preferred. However, when you need to -/// specify the container type, [`FromIterator::from_iter()`] can be more -/// readable than using a turbofish (e.g. `::>()`). See the -/// [`Iterator::collect()`] documentation for more examples of its use. -/// -/// See also: [`IntoIterator`]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let v = FromIterator::from_iter(0..5_u32); -/// -/// assert_eq!(v, array![0, 1, 2, 3, 4]); -/// ``` -/// -/// Implementing `FromIterator` for your type: -/// -/// ``` -/// use core::metaprogramming::TypeEqual; -/// -/// // A sample collection, that's just a wrapper over Array -/// #[derive(Drop, Debug)] -/// struct MyCollection { -/// arr: Array, -/// } -/// -/// // Let's give it some methods so we can create one and add things -/// // to it. -/// #[generate_trait] -/// impl MyCollectionImpl of MyCollectionTrait { -/// fn new() -> MyCollection { -/// MyCollection { arr: ArrayTrait::new() } -/// } -/// -/// fn add(ref self: MyCollection, elem: u32) { -/// self.arr.append(elem); -/// } -/// } -/// -/// // and we'll implement FromIterator -/// impl MyCollectionFromIterator of FromIterator { -/// fn from_iter< -/// I, -/// impl IntoIter: IntoIterator, -/// +TypeEqual, -/// +Destruct, -/// +Destruct, -/// >( -/// iter: I -/// ) -> MyCollection { -/// let mut c = MyCollectionTrait::new(); -/// for i in iter { -/// c.add(i); -/// }; -/// c -/// } -/// } -/// -/// // Now we can make a new iterator... -/// let iter = (0..5_u32).into_iter(); -/// -/// // ... and make a MyCollection out of it -/// let c = FromIterator::::from_iter(iter); -/// -/// assert_eq!(c.arr, array![0, 1, 2, 3, 4]); -/// ``` -pub trait FromIterator { - /// Creates a value from an iterator. - /// - /// See the [module-level documentation] for more. - /// - /// [module-level documentation]: crate::iter - /// - /// # Examples - /// - /// ``` - /// let iter = (0..5_u32).into_iter(); - /// - /// let v = FromIterator::from_iter(iter); - /// - /// assert_eq!(v, array![0, 1, 2, 3, 4]); - /// ``` - fn from_iter< - I, - impl IntoIter: IntoIterator, - +TypeEqual, - +Destruct, - +Destruct, - >( - iter: I, - ) -> T; -} - -/// Conversion into an [`Iterator`]. -/// -/// By implementing `IntoIterator` for a type, you define how it will be -/// converted to an iterator. This is common for types that describe a -/// collection of some kind. -/// -/// One benefit of implementing `IntoIterator` is that your type will work -/// with Cairo's `for` loop syntax. -/// -/// See also: [`FromIterator`]. -/// -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let mut iter = array![1, 2, 3].into_iter(); -/// -/// assert!(Some(1) == iter.next()); -/// assert!(Some(2) == iter.next()); -/// assert!(Some(3) == iter.next()); -/// assert!(None == iter.next()); -/// ``` -/// -/// Implementing `IntoIterator` for your type: -/// -/// ``` -/// // A sample collection, that's just a wrapper over `Array` -/// #[derive(Drop, Debug)] -/// struct MyCollection { -/// arr: Array -/// } -/// -/// // Let's give it some methods so we can create one and add things -/// // to it. -/// #[generate_trait] -/// impl MyCollectionImpl of MyCollectionTrait { -/// fn new() -> MyCollection { -/// MyCollection { -/// arr: ArrayTrait::new() -/// } -/// } -/// -/// fn add(ref self: MyCollection, elem: u32) { -/// self.arr.append(elem); -/// } -/// } -/// -/// // and we'll implement `IntoIterator` -/// impl MyCollectionIntoIterator of IntoIterator { -/// type IntoIter = core::array::ArrayIter; -/// fn into_iter(self: MyCollection) -> Self::IntoIter { -/// self.arr.into_iter() -/// } -/// } -/// -/// // Now we can make a new collection... -/// let mut c = MyCollectionTrait::new(); -/// -/// // ... add some stuff to it ... -/// c.add(0); -/// c.add(1); -/// c.add(2); -/// -/// // ... and then turn it into an `Iterator`: -/// let mut n = 0; -/// for i in c { -/// assert!(i == n); -/// n += 1; -/// }; -/// ``` -pub trait IntoIterator { - /// The iterator type that will be created. - type IntoIter; - impl Iterator: Iterator; - - /// Creates an iterator from a value. - /// - /// See the [module-level documentation] for more. - /// - /// [module-level documentation]: crate::iter - /// - /// # Examples - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// - /// assert_eq!(Some(1), iter.next()); - /// assert_eq!(Some(2), iter.next()); - /// assert_eq!(Some(3), iter.next()); - /// assert_eq!(None, iter.next()); - /// ``` - fn into_iter(self: T) -> Self::IntoIter; -} - -impl IteratorIntoIterator> of IntoIterator { - type IntoIter = T; - fn into_iter(self: T) -> T { - self - } -} - -impl SnapshotFixedSizeArrayIntoIterator< - T, const SIZE: usize, +Drop, impl ToSpan: crate::array::ToSpanTrait<[T; SIZE], T>, -> of IntoIterator<@[T; SIZE]> { - type IntoIter = crate::array::SpanIter; - fn into_iter(self: @[T; SIZE]) -> Self::IntoIter { - ToSpan::span(self).into_iter() - } -} - -/// Extend a collection with the contents of an iterator. -/// -/// Iterators produce a series of values, and collections can also be thought -/// of as a series of values. The `Extend` trait bridges this gap, allowing you -/// to extend a collection by including the contents of that iterator. When -/// extending a collection with an already existing key, that entry is updated -/// or, in the case of collections that permit multiple entries with equal -/// keys, that entry is inserted. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let mut arr = array![1, 2]; -/// -/// arr.extend(array![3, 4, 5]); -/// -/// assert_eq!(arr, array![1, 2, 3, 4, 5]); -/// ``` -pub trait Extend { - /// Extends a collection with the contents of an iterator. - fn extend< - I, - impl IntoIter: IntoIterator, - +TypeEqual, - +Destruct, - +Destruct, - >( - ref self: T, iter: I, - ); -} - diff --git a/corelib/src/iter/traits/iterator.cairo b/corelib/src/iter/traits/iterator.cairo deleted file mode 100644 index 490465fd0a..0000000000 --- a/corelib/src/iter/traits/iterator.cairo +++ /dev/null @@ -1,846 +0,0 @@ -use crate::iter::adapters::zip::zipped_iterator; -use crate::iter::adapters::{ - Chain, Enumerate, Filter, Map, Peekable, Take, Zip, chained_iterator, enumerated_iterator, - filter_iterator, mapped_iterator, peekable_iterator, take_iterator, -}; -use crate::iter::traits::{Product, Sum}; -use crate::metaprogramming::TypeEqual; - -/// A trait for dealing with iterators. -/// -/// This is the main iterator trait. For more about the concept of iterators -/// generally, please see the [module-level documentation]. In particular, you -/// may want to know how to [implement `Iterator`][impl]. -/// -/// [module-level documentation]: crate::iter -/// [impl]: crate::iter#implementing-iterator -pub trait Iterator { - /// The type of the elements being iterated over. - type Item; - - /// Advances the iterator and returns the next value. - /// - /// Returns [`None`] when iteration is finished. Individual iterator - /// implementations may choose to resume iteration, and so calling `next()` - /// again may or may not eventually start returning [`Some(Item)`] again at some - /// point. - /// - /// [`Some(Item)`]: Some - /// [`None`]: None - /// - /// # Examples - /// - /// ``` - /// let mut iter = [1, 2, 3].span().into_iter(); - /// - /// // A call to next() returns the next value... - /// assert_eq!(Some(@1), iter.next()); - /// assert_eq!(Some(@2), iter.next()); - /// assert_eq!(Some(@3), iter.next()); - /// - /// // ... and then None once it's over. - /// assert_eq!(None, iter.next()); - /// - /// // More calls may or may not return `None`. Here, they always will. - /// assert_eq!(None, iter.next()); - /// assert_eq!(None, iter.next()); - /// ``` - fn next(ref self: T) -> Option; - - /// Consumes the iterator, counting the number of iterations and returning it. - /// - /// This method will call [`next`] repeatedly until [`None`] is encountered, - /// returning the number of times it saw [`Some`]. Note that [`next`] has to be - /// called at least once even if the iterator does not have any elements. - /// - /// [`next`]: Iterator::next - /// - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so counting elements of - /// an iterator with more than [`Bounded::::MAX`] elements either produces the - /// wrong result or panics. - /// - /// [`Bounded::::MAX`]: core::num::traits::Bounded - /// - /// # Panics - /// - /// This function might panic if the iterator has more than [`Bounded::::MAX`] - /// elements. - /// - /// # Examples - /// - /// ``` - /// let mut a = array![1, 2, 3].into_iter(); - /// assert_eq!(a.count(), 3); - /// - /// let mut a = array![1, 2, 3, 4, 5].into_iter(); - /// assert_eq!(a.count(), 5); - /// ``` - #[inline] - fn count<+Destruct, +Destruct>( - self: T, - ) -> usize { - Self::fold(self, 0_usize, |count, _x| { - count + 1 - }) - } - - /// Consumes the iterator, returning the last element. - /// - /// This method will evaluate the iterator until it returns [`None`]. While - /// doing so, it keeps track of the current element. After [`None`] is - /// returned, `last()` will then return the last element it saw. - /// - /// # Examples - /// - /// ``` - /// let mut a = array![1, 2, 3].into_iter(); - /// assert_eq!(a.last(), Option::Some(3)); - /// - /// let mut a = array![].into_iter(); - /// assert_eq!(a.last(), Option::None); - /// ``` - #[inline] - fn last<+Destruct, +Destruct>( - self: T, - ) -> Option< - Self::Item, - > { - let mut self = self; - let next = Self::next(ref self)?; - Option::Some(Self::last(self).unwrap_or(next)) - } - - /// Advances the iterator by `n` elements. - /// - /// This method will eagerly skip `n` elements by calling [`next`] up to `n` - /// times until [`None`] is encountered. - /// - /// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by - /// `n` elements, or an `Err(NonZero)` with value `k` if [`None`] is encountered, - /// where `k` is remaining number of steps that could not be advanced because the iterator ran - /// out. - /// If `self` is empty and `n` is non-zero, then this returns `Err(n)`. - /// Otherwise, `k` is always less than `n`. - /// - /// [`None`]: None - /// [`next`]: Iterator::next - /// - /// # Examples - /// - /// ``` - /// let mut iter = array![1_u8, 2, 3, 4].into_iter(); - /// - /// assert_eq!(iter.advance_by(2), Ok(())); - /// assert_eq!(iter.next(), Some(3)); - /// assert_eq!(iter.advance_by(0), Ok(())); - /// assert_eq!(iter.advance_by(100), Err(99)); - /// ``` - fn advance_by<+Destruct, +Destruct>( - ref self: T, n: usize, - ) -> Result< - (), NonZero, - > { - if let Some(nz_n) = n.try_into() { - if let Some(_) = Self::next(ref self) { - return Self::advance_by(ref self, n - 1); - } else { - Err(nz_n) - } - } else { - Ok(()) - } - } - - /// Returns the `n`th element of the iterator. - /// - /// Like most indexing operations, the count starts from zero, so `nth(0)` - /// returns the first value, `nth(1)` the second, and so on. - /// - /// Note that all preceding elements, as well as the returned element, will be - /// consumed from the iterator. That means that the preceding elements will be - /// discarded, and also that calling `nth(0)` multiple times on the same iterator - /// will return different elements. - /// - /// `nth()` will return [`None`] if `n` is greater than or equal to the length of the - /// iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// assert_eq!(iter.nth(1), Some(2)); - /// ``` - /// - /// Calling `nth()` multiple times doesn't rewind the iterator: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// - /// assert_eq!(iter.nth(1), Some(2)); - /// assert_eq!(iter.nth(1), None); - /// ``` - /// - /// Returning `None` if there are fewer than `n + 1` elements: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter(); - /// assert_eq!(iter.nth(10), None); - /// ``` - #[inline] - fn nth<+Destruct, +Destruct>( - ref self: T, n: usize, - ) -> Option< - Self::Item, - > { - match Self::advance_by(ref self, n) { - Result::Ok(_) => Self::next(ref self), - Result::Err(_) => Option::None, - } - } - - /// Takes a closure and creates an iterator that calls that closure on each - /// element. - /// - /// `map()` transforms one iterator into another, by means of its argument: - /// something that implements [`FnOnce`]. It produces a new iterator that - /// calls this closure on each element of the original iterator. - /// - /// If you are good at thinking in types, you can think of `map()` like this: - /// If you have an iterator that gives you elements of some type `A`, and - /// you want an iterator of some other type `B`, you can use `map()`, - /// passing a closure that takes an `A` and returns a `B`. - /// - /// `map()` is conceptually similar to a `for` loop. However, as `map()` is - /// lazy, it is best used when you're already working with other iterators. - /// If you're doing some sort of looping for a side effect, it's considered - /// more idiomatic to use `for` than `map()`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = array![1, 2, 3].into_iter().map(|x| 2 * x); - /// - /// assert!(iter.next() == Some(2)); - /// assert!(iter.next() == Some(4)); - /// assert!(iter.next() == Some(6)); - /// assert!(iter.next() == None); - /// ``` - /// - /// If you're doing some sort of side effect, prefer `for` to `map()`: - /// - /// ``` - /// // don't do this: - /// let _ = (0..5_usize).into_iter().map(|x| println!("{x}")); - /// - /// // it won't even execute, as it is lazy. Cairo will warn you about this if not specifically - /// ignored, as is done here. - /// - /// // Instead, use for: - /// for x in 0..5_usize { - /// println!("{x}"); - /// } - /// ``` - #[inline] - fn map[Output: B], +Drop, +Drop>( - self: T, f: F, - ) -> Map { - mapped_iterator(self, f) - } - - /// Creates an iterator that gives the current iteration count as well as - /// the next value. - /// - /// The iterator returned yields pairs `(i, val)`, where `i` is the - /// current index of iteration and `val` is the value returned by the - /// iterator. - /// - /// `enumerate()` keeps its count as a [`usize`]. - /// - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// `Bounded::::MAX` elements will always panic. - /// - /// [`Bounded`]: core::num::traits::Bounded - /// - /// # Panics - /// - /// The returned iterator will panic if the to-be-returned index overflows a `usize`. - /// - /// # Examples - /// - /// ``` - /// let mut iter = array!['a', 'b', 'c'].into_iter().enumerate(); - /// - /// assert_eq!(iter.next(), Some((0, 'a'))); - /// assert_eq!(iter.next(), Some((1, 'b'))); - /// assert_eq!(iter.next(), Some((2, 'c'))); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - fn enumerate(self: T) -> Enumerate { - 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 Implementers - /// - /// 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[Output: B], - +Destruct, - +Destruct, - +Destruct, - >( - self: T, init: B, f: F, - ) -> B { - let mut self = self; - match Self::next(ref self) { - None => init, - Some(x) => Self::fold(self, f(init, x), f), - } - } - - /// Tests if any element of the iterator matches a predicate. - /// - /// `any()` takes a closure that returns `true` or `false`. It applies this closure to each - /// element of the iterator, and if any of them return `true`, then so does `any()`. If they all - /// return `false`, it returns `false`. - /// - /// `any()` is short-circuiting; in other words, it will stop processing as soon as it finds a - /// `true`, given that no matter what else happens, the result will also be `true`. - /// - /// An empty iterator returns `false`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(array![1, 2, 3].into_iter().any(|x| x == 2)); - /// - /// assert!(!array![1, 2, 3].into_iter().any(|x| x > 5)); - /// ``` - fn any< - P, - +core::ops::Fn[Output: bool], - +Destruct