Skip to content

Commit

Permalink
implemented push and pop
Browse files Browse the repository at this point in the history
  • Loading branch information
orizi authored and dean-starkware committed Jan 28, 2025
1 parent 42c370c commit 983d91c
Show file tree
Hide file tree
Showing 17 changed files with 336 additions and 99 deletions.
89 changes: 88 additions & 1 deletion corelib/src/starknet/storage/vec.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,55 @@ pub trait MutableVecTrait<T> {
/// }
/// ```
fn append(self: T) -> StoragePath<Mutable<Self::ElementType>>;

/// 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.
///
/// # Examples
///
/// ```
/// use core::starknet::storage::{Vec, MutableVecTrait};
///
/// #[storage]
/// struct Storage {
/// numbers: Vec<u256>,
/// }
///
/// fn push_number(ref self: ContractState, number: u256) {
/// self.numbers.push(number);
/// }
/// ```
fn push<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
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 core::starknet::storage::{Vec, MutableVecTrait};
///
/// #[storage]
/// struct Storage {
/// numbers: Vec<u256>,
/// }
///
/// fn pop_number(ref self: ContractState) -> Option<u256> {
/// self.numbers.pop()
/// }
/// ```
fn pop<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: T,
) -> Option<Self::ElementType>;
}

/// Implement `MutableVecTrait` for `StoragePath<Mutable<Vec<T>>`.
Expand Down Expand Up @@ -350,8 +399,34 @@ impl MutableVecImpl<T> of MutableVecTrait<StoragePath<Mutable<Vec<T>>>> {
self.as_ptr().write(vec_len + 1);
self.update(vec_len)
}
}

fn push<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: StoragePath<Mutable<Vec<T>>>, value: Self::ElementType,
) {
self.append().write(value);
}

fn pop<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: StoragePath<Mutable<Vec<T>>>,
) -> Option<Self::ElementType> {
let len_ptr = self.as_ptr();
let vec_len: u64 = len_ptr.read();
if vec_len == 0 {
return None;
}
let entry: StoragePath<Mutable<T>> = 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<
Expand All @@ -377,6 +452,18 @@ impl PathableMutableVecImpl<
fn append(self: T) -> StoragePath<Mutable<VecTraitImpl::ElementType>> {
self.as_path().append()
}

fn push<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: T, value: Self::ElementType,
) {
self.as_path().push(value)
}

fn pop<+Drop<Self::ElementType>, +starknet::Store<Self::ElementType>>(
self: T,
) -> Option<Self::ElementType> {
self.as_path().pop()
}
}

pub impl VecIndexView<
Expand Down
31 changes: 31 additions & 0 deletions corelib/src/starknet/storage_access.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,37 @@ pub trait Store<T> {
/// 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.
#[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.
Expand Down
33 changes: 17 additions & 16 deletions crates/bin/cairo-execute/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct Args {
/// In `--build-only` this would be the executable artifact.
/// In bootloader mode it will be the resulting cairo PIE file.
/// In standalone mode this parameter is disallowed.
#[clap(long, required_if_eq("standalone", "false"))]
#[clap(long, required_unless_present("standalone"))]
output_path: Option<PathBuf>,

/// Whether to only run a prebuilt executable.
Expand Down Expand Up @@ -94,7 +94,7 @@ struct RunArgs {
long,
default_value_t = false,
conflicts_with_all = ["build_only", "output_path"],
requires_all=["trace_file", "memory_file", "air_public_input", "air_private_input"],
requires_all=["air_public_input", "air_private_input"],
)]
standalone: bool,
/// If set, the program will be run in secure mode.
Expand All @@ -104,7 +104,7 @@ struct RunArgs {
#[clap(long)]
allow_missing_builtins: Option<bool>,
#[clap(flatten)]
standalone_outputs: StandaloneOutputArgs,
proof_outputs: ProofOutputArgs,
}

#[derive(Parser, Debug)]
Expand All @@ -123,19 +123,20 @@ struct SerializedArgs {
as_file: Option<PathBuf>,
}

/// The arguments for output files required for creating a proof.
#[derive(Parser, Debug)]
struct StandaloneOutputArgs {
struct ProofOutputArgs {
/// The resulting trace file.
#[clap(long, conflicts_with = "build_only", requires = "standalone")]
#[clap(long, conflicts_with = "build_only")]
trace_file: Option<PathBuf>,
/// The resulting memory file.
#[clap(long, conflicts_with = "build_only", requires = "standalone")]
#[clap(long, conflicts_with = "build_only")]
memory_file: Option<PathBuf>,
/// The resulting AIR public input file.
#[clap(long, conflicts_with = "build_only", requires = "standalone")]
#[clap(long, conflicts_with = "build_only")]
air_public_input: Option<PathBuf>,
/// The resulting AIR private input file.
#[clap(long, conflicts_with = "build_only", requires = "standalone")]
#[clap(long, conflicts_with = "build_only", requires_all=["trace_file", "memory_file"])]
air_private_input: Option<PathBuf>,
}

Expand Down Expand Up @@ -230,8 +231,8 @@ fn main() -> anyhow::Result<()> {
};

let cairo_run_config = CairoRunConfig {
trace_enabled: args.run.standalone,
relocate_mem: args.run.standalone,
trace_enabled: args.run.proof_outputs.trace_file.is_some(),
relocate_mem: args.run.proof_outputs.memory_file.is_some(),
layout: args.run.layout,
proof_mode: args.run.standalone,
secure_run: args.run.secure_run,
Expand All @@ -257,29 +258,29 @@ fn main() -> anyhow::Result<()> {
}
}

if let Some(trace_path) = &args.run.standalone_outputs.trace_file {
if let Some(trace_path) = &args.run.proof_outputs.trace_file {
let relocated_trace =
runner.relocated_trace.as_ref().with_context(|| "Trace not relocated.")?;
let mut writer = FileWriter::new(3 * 1024 * 1024, trace_path)?;
cairo_run::write_encoded_trace(relocated_trace, &mut writer)?;
writer.flush()?;
}

if let Some(memory_path) = &args.run.standalone_outputs.memory_file {
if let Some(memory_path) = &args.run.proof_outputs.memory_file {
let mut writer = FileWriter::new(5 * 1024 * 1024, memory_path)?;
cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?;
writer.flush()?;
}

if let Some(file_path) = args.run.standalone_outputs.air_public_input {
if let Some(file_path) = args.run.proof_outputs.air_public_input {
let json = runner.get_air_public_input()?.serialize_json()?;
std::fs::write(file_path, json)?;
}

if let (Some(file_path), Some(trace_file), Some(memory_file)) = (
args.run.standalone_outputs.air_private_input,
args.run.standalone_outputs.trace_file,
args.run.standalone_outputs.memory_file,
args.run.proof_outputs.air_private_input,
args.run.proof_outputs.trace_file,
args.run.proof_outputs.memory_file,
) {
let absolute = |path_buf: PathBuf| {
path_buf.as_path().canonicalize().unwrap_or(path_buf).to_string_lossy().to_string()
Expand Down
12 changes: 3 additions & 9 deletions crates/cairo-lang-semantic/src/expr/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1230,15 +1230,9 @@ impl SemanticRewriter<TypeLongId, NoError> for Inference<'_> {
let impl_id = impl_type_id.impl_id();
let trait_ty = impl_type_id.ty();
return Ok(match impl_id.lookup_intern(self.db) {
ImplLongId::GenericParameter(_) | ImplLongId::SelfImpl(_) => {
impl_type_id_rewrite_result
}
ImplLongId::ImplImpl(impl_impl) => {
// The grand parent impl must be var free since we are rewriting the parent,
// and the parent is not var.
assert!(impl_impl.impl_id().is_var_free(self.db));
impl_type_id_rewrite_result
}
ImplLongId::GenericParameter(_)
| ImplLongId::SelfImpl(_)
| ImplLongId::ImplImpl(_) => impl_type_id_rewrite_result,
ImplLongId::Concrete(_) => {
if let Ok(ty) = self.db.impl_type_concrete_implized(ImplTypeId::new(
impl_id, trait_ty, self.db,
Expand Down
6 changes: 1 addition & 5 deletions crates/cairo-lang-semantic/src/expr/inference/infers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,7 @@ impl InferenceEmbeddings for Inference<'_> {
.map_err(|diag_added| self.set_error(InferenceError::Reported(diag_added)))?;
let impl_id = self.new_impl_var(concrete_trait_id, stable_ptr, lookup_context);
for (trait_ty, ty1) in param.type_constraints.iter() {
let ty0 = self.reduce_impl_ty(ImplTypeId::new(
impl_id,
trait_ty.trait_type(self.db),
self.db,
))?;
let ty0 = self.reduce_impl_ty(ImplTypeId::new(impl_id, *trait_ty, self.db))?;
// Conforming the type will always work as the impl is a new inference variable.
self.conform_ty(ty0, *ty1).ok();
}
Expand Down
17 changes: 15 additions & 2 deletions crates/cairo-lang-semantic/src/items/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,9 +855,22 @@ pub fn concrete_function_closure_params(
let ConcreteFunction { generic_function, generic_args, .. } =
function_id.lookup_intern(db).function;
let generic_params = generic_function.generic_params(db)?;
let generic_closure_params = db.get_closure_params(generic_function)?;
let mut generic_closure_params = db.get_closure_params(generic_function)?;
let substitution = GenericSubstitution::new(&generic_params, &generic_args);
SubstitutionRewriter { db, substitution: &substitution }.rewrite(generic_closure_params)
let mut rewriter = SubstitutionRewriter { db, substitution: &substitution };
let mut changed_keys = vec![];
for (key, value) in generic_closure_params.iter_mut() {
rewriter.internal_rewrite(value)?;
let updated_key = rewriter.rewrite(*key)?;
if updated_key != *key {
changed_keys.push((*key, updated_key));
}
}
for (old_key, new_key) in changed_keys {
let v = generic_closure_params.swap_remove(&old_key).unwrap();
generic_closure_params.insert(new_key, v);
}
Ok(generic_closure_params)
}

/// For a given list of AST parameters, returns the list of semantic parameters along with the
Expand Down
9 changes: 4 additions & 5 deletions crates/cairo-lang-semantic/src/items/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cairo_lang_debug::DebugWithDb;
use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::{
GenericItemId, GenericKind, GenericModuleItemId, GenericParamId, GenericParamLongId,
LanguageElementId, LookupItemId, ModuleFileId, TraitId,
LanguageElementId, LookupItemId, ModuleFileId, TraitId, TraitTypeId,
};
use cairo_lang_diagnostics::{Diagnostics, Maybe};
use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
Expand Down Expand Up @@ -200,7 +200,7 @@ pub struct GenericParamConst {
pub struct GenericParamImpl {
pub id: GenericParamId,
pub concrete_trait: Maybe<ConcreteTraitId>,
pub type_constraints: OrderedHashMap<ConcreteTraitTypeId, TypeId>,
pub type_constraints: OrderedHashMap<TraitTypeId, TypeId>,
}
impl Hash for GenericParamImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Expand Down Expand Up @@ -397,8 +397,7 @@ pub fn generic_params_type_constraints(
let Ok(concrete_trait_id) = imp.concrete_trait else {
continue;
};
for (concrete_trait_type_id, ty1) in imp.type_constraints {
let trait_ty = concrete_trait_type_id.trait_type(db);
for (trait_ty, ty1) in imp.type_constraints {
let impl_type = TypeLongId::ImplType(ImplTypeId::new(
ImplLongId::GenericParameter(*param).intern(db),
trait_ty,
Expand Down Expand Up @@ -617,7 +616,7 @@ fn impl_generic_param_semantic(

let concrete_trait_type_id =
ConcreteTraitTypeId::new(db, concrete_trait_id, trait_type_id);
match map.entry(concrete_trait_type_id) {
match map.entry(trait_type_id) {
Entry::Vacant(entry) => {
entry.insert(resolve_type(
db,
Expand Down
Loading

0 comments on commit 983d91c

Please sign in to comment.