Skip to main content

tasm_lib/list/
set_length.rs

1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::prelude::*;
6use crate::traits::basic_snippet::Reviewer;
7use crate::traits::basic_snippet::SignOffFingerprint;
8
9/// Set the length of a [`BFieldCodec`]-encoded list in memory.
10///
11/// This snippet does not perform any checks. It is to be considered “unsafe”.
12///
13/// ### Behavior
14///
15/// ```text
16/// BEFORE: _ *list [list_length: u32]
17/// AFTER:  _ *list
18/// ```
19///
20/// ### Preconditions
21///
22/// - all input arguments are properly [`BFieldCodec`] encoded
23/// - the input argument `*list` is a pointer to a [`BFieldCodec`] encoded list
24///
25/// ### Postconditions
26///
27/// None.
28#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
29pub struct SetLength;
30
31impl BasicSnippet for SetLength {
32    fn parameters(&self) -> Vec<(DataType, String)> {
33        vec![
34            (DataType::VoidPointer, "*list".to_string()),
35            (DataType::U32, "list_length".to_string()),
36        ]
37    }
38
39    fn return_values(&self) -> Vec<(DataType, String)> {
40        vec![(DataType::VoidPointer, "*list".to_string())]
41    }
42
43    fn entrypoint(&self) -> String {
44        "tasmlib_list_set_length".to_string()
45    }
46
47    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
48        triton_asm!(
49            // BEFORE: _ *list list_length
50            // AFTER:  _ *list
51            {self.entrypoint()}:
52                pick 1      // _ list_length *list
53                write_mem 1 // _ (*list + 1)
54                addi -1     // _ *list
55                return
56        )
57    }
58
59    fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
60        let mut sign_offs = HashMap::new();
61        sign_offs.insert(Reviewer("ferdinand"), 0xff218b8ee1882c10.into());
62        sign_offs
63    }
64}
65
66#[cfg(test)]
67pub(crate) mod tests {
68    use super::*;
69    use crate::U32_TO_USIZE_ERR;
70    use crate::empty_stack;
71    use crate::rust_shadowing_helper_functions::list::list_set_length;
72    use crate::test_prelude::*;
73
74    impl Function for SetLength {
75        fn rust_shadow(
76            &self,
77            stack: &mut Vec<BFieldElement>,
78            memory: &mut HashMap<BFieldElement, BFieldElement>,
79        ) -> Result<(), RustShadowError> {
80            let new_length = pop_encodable::<u32>(stack)?;
81            let list_address = stack.pop().ok_or(RustShadowError::StackUnderflow)?;
82            stack.push(list_address);
83
84            let new_length = new_length.try_into().expect(U32_TO_USIZE_ERR);
85            list_set_length(list_address, new_length, memory);
86            Ok(())
87        }
88
89        fn pseudorandom_initial_state(
90            &self,
91            seed: [u8; 32],
92            _: Option<BenchmarkCase>,
93        ) -> FunctionInitialState {
94            let mut rng = StdRng::from_seed(seed);
95
96            let mut stack = empty_stack();
97            stack.push(rng.random());
98            stack.push(bfe!(rng.next_u32()));
99
100            FunctionInitialState {
101                stack,
102                ..Default::default()
103            }
104        }
105    }
106
107    #[macro_rules_attr::apply(test)]
108    fn rust_shadow() {
109        ShadowedFunction::new(SetLength).test();
110    }
111}
112
113#[cfg(test)]
114mod benches {
115    use super::*;
116    use crate::test_prelude::*;
117
118    #[macro_rules_attr::apply(test)]
119    fn benchmark() {
120        ShadowedFunction::new(SetLength).bench();
121    }
122}