tasm_lib/traits/
closure.rs1use rand::prelude::*;
2use triton_vm::prelude::*;
3
4use super::basic_snippet::BasicSnippet;
5use super::rust_shadow::RustShadow;
6use crate::linker::execute_bench;
7use crate::prelude::Tip5;
8use crate::push_encodable;
9use crate::snippet_bencher::write_benchmarks;
10use crate::snippet_bencher::BenchmarkCase;
11use crate::snippet_bencher::NamedBenchmarkResult;
12use crate::test_helpers::test_rust_equivalence_given_complete_state;
13
14pub trait Closure: BasicSnippet {
27 type Args: BFieldCodec;
34
35 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>);
36
37 fn pseudorandom_args(&self, seed: [u8; 32], bench_case: Option<BenchmarkCase>) -> Self::Args;
40
41 fn corner_case_args(&self) -> Vec<Self::Args> {
42 vec![]
43 }
44
45 fn set_up_test_stack(&self, args: Self::Args) -> Vec<BFieldElement> {
46 let mut stack = self.init_stack_for_isolated_run();
47 push_encodable(&mut stack, &args);
48 stack
49 }
50}
51
52pub struct ShadowedClosure<C: Closure> {
53 closure: C,
54}
55
56impl<C: Closure> ShadowedClosure<C> {
57 pub fn new(closure: C) -> Self {
58 Self { closure }
59 }
60}
61
62impl<C: Closure> RustShadow for ShadowedClosure<C> {
63 fn inner(&self) -> &dyn BasicSnippet {
64 &self.closure
65 }
66
67 fn rust_shadow_wrapper(
68 &self,
69 _stdin: &[BFieldElement],
70 _nondeterminism: &NonDeterminism,
71 stack: &mut Vec<BFieldElement>,
72 _memory: &mut std::collections::HashMap<BFieldElement, BFieldElement>,
73 _sponge: &mut Option<Tip5>,
74 ) -> Vec<BFieldElement> {
75 self.closure.rust_shadow(stack);
76 vec![]
77 }
78
79 fn test(&self) {
80 let num_states = 5;
81 let mut rng = rand::rng();
82
83 for args in self.closure.corner_case_args() {
85 test_rust_equivalence_given_complete_state(
86 self,
87 &self.closure.set_up_test_stack(args),
88 &[],
89 &NonDeterminism::default(),
90 &None,
91 None,
92 );
93 }
94
95 for _ in 0..num_states {
96 let seed: [u8; 32] = rng.random();
97 let args = self.closure.pseudorandom_args(seed, None);
98 let stack = self.closure.set_up_test_stack(args);
99
100 let stdin = vec![];
101 test_rust_equivalence_given_complete_state(
102 self,
103 &stack,
104 &stdin,
105 &NonDeterminism::default(),
106 &None,
107 None,
108 );
109 }
110 }
111
112 fn bench(&self) {
113 let mut rng = StdRng::from_seed(
114 hex::decode("73a24b6b8b32e4d7d563a4d9a85f476573a24b6b8b32e4d7d563a4d9a85f4765")
115 .unwrap()
116 .try_into()
117 .unwrap(),
118 );
119 let mut benchmarks = Vec::with_capacity(2);
120
121 for bench_case in [BenchmarkCase::CommonCase, BenchmarkCase::WorstCase] {
122 let args = self
123 .closure
124 .pseudorandom_args(rng.random(), Some(bench_case));
125 let stack = self.closure.set_up_test_stack(args);
126 let program = self.closure.link_for_isolated_run();
127 let benchmark =
128 execute_bench(&program, &stack, vec![], NonDeterminism::new(vec![]), None);
129 let benchmark = NamedBenchmarkResult {
130 name: self.closure.entrypoint(),
131 benchmark_result: benchmark,
132 case: bench_case,
133 };
134 benchmarks.push(benchmark);
135 }
136
137 write_benchmarks(benchmarks);
138 }
139}