Skip to content

Commit

Permalink
Update for Cairo 2.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
smonicas committed Jan 24, 2024
1 parent fb8c6cb commit 6f95299
Show file tree
Hide file tree
Showing 83 changed files with 1,536 additions and 905 deletions.
162 changes: 102 additions & 60 deletions Cargo.lock

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ once_cell = "1.17"
smol_str = "0.2"
num-integer = "0.1"
termcolor = "1.2"
graphviz-rust = "0.6.2"
cairo-felt = "0.8.7"
graphviz-rust = "0.7.0"
cairo-felt = "0.9.1"
thiserror = "1.0.47"
rayon = "1.8"
fxhash = "0.2.1"

cairo-lang-compiler = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-defs = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-plugins = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-starknet = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-filesystem = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-parser = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-syntax = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-semantic = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-utils = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-sierra-generator = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-sierra = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.4.3" }
cairo-lang-compiler = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-defs = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-plugins = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-starknet = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-filesystem = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-parser = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-syntax = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-semantic = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-utils = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-sierra-generator = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }
cairo-lang-sierra = { git = "https://github.com/starkware-libs/cairo.git", tag = "v2.5.0" }


[dev-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions corelib/Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "core"
version = "2.4.3"
edition = "2023_10"
version = "2.5.0"
edition = "2023_11"

# 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.
Expand Down
5 changes: 4 additions & 1 deletion corelib/cairo_project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
core = "src"

[config.global]
edition = "2023_10"
edition = "2023_11"

[config.global.experimental_features]
negative_impls = true
44 changes: 36 additions & 8 deletions corelib/src/array.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use core::box::BoxTrait;
use core::gas::withdraw_gas;
use core::option::OptionTrait;
use core::serde::Serde;
use core::metaprogramming::TypeEqual;

#[derive(Drop)]
extern type Array<T>;
pub extern type Array<T>;

extern fn array_new<T>() -> Array<T> nopanic;
extern fn array_append<T>(ref arr: Array<T>, value: T) nopanic;
Expand All @@ -24,7 +25,7 @@ extern fn array_slice<T>(
extern fn array_len<T>(arr: @Array<T>) -> usize nopanic;

#[generate_trait]
impl ArrayImpl<T> of ArrayTrait<T> {
pub impl ArrayImpl<T> of ArrayTrait<T> {
#[inline(always)]
fn new() -> Array<T> {
array_new()
Expand Down Expand Up @@ -64,14 +65,21 @@ impl ArrayImpl<T> of ArrayTrait<T> {
array_at(self, index).unbox()
}
#[inline(always)]
#[must_use]
fn len(self: @Array<T>) -> usize {
array_len(self)
}
#[inline(always)]
#[must_use]
fn is_empty(self: @Array<T>) -> bool {
self.len() == 0_usize
let mut snapshot = self;
match array_snapshot_pop_front(ref snapshot) {
Option::Some(_) => false,
Option::None => true,
}
}
#[inline(always)]
#[must_use]
fn span(self: @Array<T>) -> Span<T> {
Span { snapshot: self }
}
Expand Down Expand Up @@ -123,14 +131,28 @@ fn deserialize_array_helper<T, +Serde<T>, +Drop<T>>(
}

// Span.
struct Span<T> {
pub struct Span<T> {
snapshot: @Array<T>
}

impl SpanCopy<T> of Copy<Span<T>>;
impl SpanDrop<T> of Drop<Span<T>>;

impl SpanSerde<T, +Serde<T>, +Drop<T>> of Serde<Span<T>> {
impl SpanFelt252Serde of Serde<Span<felt252>> {
fn serialize(self: @Span<felt252>, ref output: Array<felt252>) {
(*self).len().serialize(ref output);
serialize_array_helper(*self, ref output)
}

fn deserialize(ref serialized: Span<felt252>) -> Option<Span<felt252>> {
let length: u32 = (*serialized.pop_front()?).try_into()?;
let res = serialized.slice(0, length);
serialized = serialized.slice(length, serialized.len() - length);
Option::Some(res)
}
}

impl SpanSerde<T, +Serde<T>, +Drop<T>, -TypeEqual<felt252, T>> of Serde<Span<T>> {
fn serialize(self: @Span<T>, ref output: Array<felt252>) {
(*self).len().serialize(ref output);
serialize_array_helper(*self, ref output)
Expand All @@ -144,7 +166,7 @@ impl SpanSerde<T, +Serde<T>, +Drop<T>> of Serde<Span<T>> {
}

#[generate_trait]
impl SpanImpl<T> of SpanTrait<T> {
pub impl SpanImpl<T> of SpanTrait<T> {
#[inline(always)]
fn pop_front(ref self: Span<T>) -> Option<@T> {
let mut snapshot = self.snapshot;
Expand Down Expand Up @@ -178,16 +200,22 @@ impl SpanImpl<T> of SpanTrait<T> {
Span { snapshot: array_slice(self.snapshot, start, length).expect('Index out of bounds') }
}
#[inline(always)]
#[must_use]
fn len(self: Span<T>) -> usize {
array_len(self.snapshot)
}
#[inline(always)]
#[must_use]
fn is_empty(self: Span<T>) -> bool {
self.len() == 0_usize
let mut snapshot = self.snapshot;
match array_snapshot_pop_front(ref snapshot) {
Option::Some(_) => false,
Option::None => true,
}
}
}

impl SpanIndex<T> of IndexView<Span<T>, usize, @T> {
pub impl SpanIndex<T> of IndexView<Span<T>, usize, @T> {
#[inline(always)]
fn index(self: @Span<T>, index: usize) -> @T {
array_at(*self.snapshot, index).unbox()
Expand Down
19 changes: 19 additions & 0 deletions corelib/src/boolean.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#[generate_trait]
pub impl BoolImpl<T, +Drop<T>> of BoolTrait<T> {
/// Returns `Some(t)` if the `bool` is `true`, or `None` otherwise.
///
/// # Examples
///
/// ```
/// assert(false.then_some(0) == Option::None);
/// assert(true.then_some(0) == Option::Some(0));
/// ```
#[inline(always)]
fn then_some(self: bool, t: T) -> Option<T> nopanic {
if self {
Option::Some(t)
} else {
Option::None
}
}
}
18 changes: 16 additions & 2 deletions corelib/src/box.cairo
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
#[derive(Copy, Drop)]
extern type Box<T>;
pub extern type Box<T>;

// These functions are only exposed in the corelib through the trait below since calling them
// directly with tuples panics due to auto unpacking of the tuple.
// TODO(Gil): Expose in the core lib when the described behaviour is fixed.
extern fn into_box<T>(value: T) -> Box<T> nopanic;
extern fn unbox<T>(box: Box<T>) -> T nopanic;
extern fn box_forward_snapshot<T>(value: @Box<T>) -> Box<@T> nopanic;

#[generate_trait]
impl BoxImpl<T> of BoxTrait<T> {
pub impl BoxImpl<T> of BoxTrait<T> {
#[inline(always)]
#[must_use]
fn new(value: T) -> Box<T> nopanic {
into_box(value)
}
#[inline(always)]
#[must_use]
fn unbox(self: Box<T>) -> T nopanic {
unbox(self)
}
#[must_use]
fn as_snapshot(self: @Box<T>) -> Box<@T> nopanic {
box_forward_snapshot(self)
}
}

impl BoxDebug<T, impl TDebug: core::fmt::Debug<T>> of core::fmt::Debug<Box<T>> {
fn fmt(self: @Box<T>, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> {
write!(f, "&")?;
TDebug::fmt(self.as_snapshot().unbox(), ref f)
}
}
18 changes: 10 additions & 8 deletions corelib/src/byte_array.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,31 @@ use core::zeroable::NonZeroIntoImpl;
/// A magic constant for identifying serialization of ByteArrays. An array of felt252s with this
/// magic as one of the felt252s indicates that right after it you should expect a serialized
/// ByteArray. This is currently used mainly for prints and panics.
const BYTE_ARRAY_MAGIC: felt252 = 0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3;
pub(crate) const BYTE_ARRAY_MAGIC: felt252 =
0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3;
const BYTES_IN_U128: usize = 16;
// TODO(yuval): change to `BYTES_IN_BYTES31 - 1` once consteval_int supports non-literals.
const BYTES_IN_BYTES31_MINUS_ONE: usize = consteval_int!(31 - 1);

// TODO(yuval): don't allow creation of invalid ByteArray?
#[derive(Drop, Clone, PartialEq, Serde, Default)]
struct ByteArray {
pub struct ByteArray {
// Full "words" of 31 bytes each. The first byte of each word in the byte array
// is the most significant byte in the word.
data: Array<bytes31>,
pub(crate) data: Array<bytes31>,
// This felt252 actually represents a bytes31, with < 31 bytes.
// It is represented as a felt252 to improve performance of building the byte array.
// The number of bytes in here is specified in `pending_word_len`.
// The first byte is the most significant byte among the `pending_word_len` bytes in the word.
pending_word: felt252,
pub(crate) pending_word: felt252,
// Should be in range [0, 30].
pending_word_len: usize,
pub(crate) pending_word_len: usize,
}

impl ByteArrayStringLiteral of core::string::StringLiteral<ByteArray>;
pub(crate) impl ByteArrayStringLiteral of core::string::StringLiteral<ByteArray>;

#[generate_trait]
impl ByteArrayImpl of ByteArrayTrait {
pub impl ByteArrayImpl of ByteArrayTrait {
// TODO(yuval): add a `new` function for initialization.

// Appends a single word of `len` bytes to the end of the ByteArray.
Expand Down Expand Up @@ -166,6 +167,7 @@ impl ByteArrayImpl of ByteArrayTrait {
self.pending_word_len = 0;
}

#[must_use]
fn len(self: @ByteArray) -> usize {
self.data.len() * BYTES_IN_BYTES31.into() + (*self.pending_word_len).into()
}
Expand Down Expand Up @@ -353,7 +355,7 @@ impl ByteArrayAddEq of AddEq<ByteArray> {
}
}

impl ByteArrayIndexView of IndexView<ByteArray, usize, u8> {
pub(crate) impl ByteArrayIndexView of IndexView<ByteArray, usize, u8> {
fn index(self: @ByteArray, index: usize) -> u8 {
self.at(index).expect('Index out of bounds')
}
Expand Down
38 changes: 22 additions & 16 deletions corelib/src/bytes_31.cairo
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use core::traits::{Into, TryInto};
use core::option::OptionTrait;
use core::integer::{u256_from_felt252, u128_safe_divmod, u128_to_felt252};
use core::integer::{u128_safe_divmod, u128_to_felt252};

const BYTES_IN_BYTES31: usize = 31;
pub(crate) const BYTES_IN_BYTES31: usize = 31;
const BYTES_IN_U128: usize = 16;
const POW_2_128: felt252 = 0x100000000000000000000000000000000;
const POW_2_8: u128 = 0x100;
pub(crate) const POW_2_128: felt252 = 0x100000000000000000000000000000000;
pub(crate) const POW_2_8: u128 = 0x100;

#[derive(Copy, Drop)]
extern type bytes31;
pub extern type bytes31;

extern fn bytes31_const<const value: felt252>() -> bytes31 nopanic;
pub(crate) extern fn bytes31_const<const value: felt252>() -> bytes31 nopanic;
extern fn bytes31_try_from_felt252(value: felt252) -> Option<bytes31> implicits(RangeCheck) nopanic;
extern fn bytes31_to_felt252(value: bytes31) -> felt252 nopanic;

#[generate_trait]
impl Bytes31Impl of Bytes31Trait {
pub impl Bytes31Impl of Bytes31Trait {
// Gets the byte at the given index (LSB's index is 0), assuming that
// `index < BYTES_IN_BYTES31`. If the assumption is not met, the behavior is undefined.
fn at(self: @bytes31, index: usize) -> u8 {
Expand All @@ -29,34 +29,40 @@ impl Bytes31Impl of Bytes31Trait {
}
}

impl Bytes31IndexView of IndexView<bytes31, usize, u8> {
pub(crate) impl Bytes31IndexView of IndexView<bytes31, usize, u8> {
fn index(self: @bytes31, index: usize) -> u8 {
self.at(index)
}
}

impl Bytes31IntoFelt252 of Into<bytes31, felt252> {
impl Bytes31BitSize of core::num::traits::BitSize<bytes31> {
fn bits() -> usize {
248
}
}

pub(crate) impl Bytes31IntoFelt252 of Into<bytes31, felt252> {
fn into(self: bytes31) -> felt252 {
bytes31_to_felt252(self)
}
}

impl Bytes31IntoU256 of Into<bytes31, u256> {
pub(crate) impl Bytes31IntoU256 of Into<bytes31, u256> {
fn into(self: bytes31) -> u256 {
let as_felt: felt252 = self.into();
as_felt.into()
}
}

impl Felt252TryIntoBytes31 of TryInto<felt252, bytes31> {
pub(crate) impl Felt252TryIntoBytes31 of TryInto<felt252, bytes31> {
fn try_into(self: felt252) -> Option<bytes31> {
bytes31_try_from_felt252(self)
}
}

impl Bytes31Serde = core::serde::into_felt252_based::SerdeImpl<bytes31>;

impl U8IntoBytes31 of Into<u8, bytes31> {
pub(crate) impl U8IntoBytes31 of Into<u8, bytes31> {
fn into(self: u8) -> bytes31 {
core::integer::upcast(self)
}
Expand All @@ -76,7 +82,7 @@ impl U64IntoBytes31 of Into<u64, bytes31> {
core::integer::upcast(self)
}
}
impl U128IntoBytes31 of Into<u128, bytes31> {
pub(crate) impl U128IntoBytes31 of Into<u128, bytes31> {
fn into(self: u128) -> bytes31 {
core::integer::upcast(self)
}
Expand All @@ -90,7 +96,7 @@ impl U128IntoBytes31 of Into<u128, bytes31> {
// 3. 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 expansive.
fn split_bytes31(word: felt252, len: usize, index: usize) -> (felt252, felt252) {
pub(crate) fn split_bytes31(word: felt252, len: usize, index: usize) -> (felt252, felt252) {
if index == 0 {
return (0, word);
}
Expand Down Expand Up @@ -135,7 +141,7 @@ fn split_bytes31(word: felt252, len: usize, index: usize) -> (felt252, felt252)
// Note: if `n_bytes >= BYTES_IN_BYTES31`, the behavior is undefined. If one wants to assert that in
// the callsite, it's sufficient to assert that `n_bytes != BYTES_IN_BYTES31` because if
// `n_bytes > 31` then `n_bytes - 16 > 15` and `one_shift_left_bytes_u128` would panic.
fn one_shift_left_bytes_felt252(n_bytes: usize) -> felt252 {
pub(crate) fn one_shift_left_bytes_felt252(n_bytes: usize) -> felt252 {
if n_bytes < BYTES_IN_U128 {
one_shift_left_bytes_u128(n_bytes).into()
} else {
Expand All @@ -146,7 +152,7 @@ fn one_shift_left_bytes_felt252(n_bytes: usize) -> felt252 {
// Returns 1 << (8 * `n_bytes`) as u128, where `n_bytes` must be < BYTES_IN_U128.
//
// Panics if `n_bytes >= BYTES_IN_U128`.
fn one_shift_left_bytes_u128(n_bytes: usize) -> u128 {
pub(crate) fn one_shift_left_bytes_u128(n_bytes: usize) -> u128 {
// TODO(yuval): change to match once it's supported for integers.
if n_bytes == 0 {
0x1_u128
Expand Down
3 changes: 2 additions & 1 deletion corelib/src/clone.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
trait Clone<T> {
pub trait Clone<T> {
#[must_use]
fn clone(self: @T) -> T;
}

Expand Down
Loading

0 comments on commit 6f95299

Please sign in to comment.