Skip to main content

tasm_lib/list/
new.rs

1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::prelude::*;
6use crate::rust_shadowing_helper_functions::list::list_new;
7use crate::snippet_bencher::BenchmarkCase;
8use crate::traits::function::Function;
9use crate::traits::function::FunctionInitialState;
10use crate::traits::rust_shadow::RustShadowError;
11
12/// Creates a new list and returns a pointer to it.
13///
14/// Lists like these do not have an explicit capacity. Instead, they have
15/// access to a full [memory page][crate::memory]. Snippets like
16/// [`Push`][super::push::Push] and [`Set`][super::set::Set] ensure that all
17/// list access is in bounds.
18#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
19pub struct New;
20
21impl BasicSnippet for New {
22    fn parameters(&self) -> Vec<(DataType, String)> {
23        vec![]
24    }
25
26    fn return_values(&self) -> Vec<(DataType, String)> {
27        vec![(DataType::VoidPointer, "*list".to_string())]
28    }
29
30    fn entrypoint(&self) -> String {
31        "tasmlib_list_new".to_string()
32    }
33
34    fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
35        let dyn_malloc = library.import(Box::new(DynMalloc));
36
37        triton_asm!(
38            // BEFORE: _
39            // AFTER:  _ *list
40            {self.entrypoint()}:
41                call {dyn_malloc}
42                            // _ *list
43
44                /* write initial length = 0 to `*list` */
45                push 0
46                pick 1
47                write_mem 1
48                addi -1
49                            // _ *list
50
51                return
52        )
53    }
54}
55
56impl Function for New {
57    fn rust_shadow(
58        &self,
59        stack: &mut Vec<BFieldElement>,
60        memory: &mut HashMap<BFieldElement, BFieldElement>,
61    ) -> Result<(), RustShadowError> {
62        DynMalloc.rust_shadow(stack, memory)?;
63
64        let list_pointer = stack.last().copied();
65        let list_pointer = list_pointer.ok_or(RustShadowError::StackUnderflow)?;
66        list_new(list_pointer, memory);
67
68        Ok(())
69    }
70
71    fn pseudorandom_initial_state(
72        &self,
73        _: [u8; 32],
74        _: Option<BenchmarkCase>,
75    ) -> FunctionInitialState {
76        FunctionInitialState {
77            stack: self.init_stack_for_isolated_run(),
78            ..Default::default()
79        }
80    }
81}
82
83#[cfg(test)]
84pub(crate) mod tests {
85    use super::*;
86    use crate::test_prelude::*;
87
88    #[macro_rules_attr::apply(test)]
89    fn rust_shadow() {
90        ShadowedFunction::new(New).test();
91    }
92}
93
94#[cfg(test)]
95mod benches {
96    use super::*;
97    use crate::test_prelude::*;
98
99    #[macro_rules_attr::apply(test)]
100    fn benchmark() {
101        ShadowedFunction::new(New).bench();
102    }
103}