1macro_rules! cache {
3 ($F:ty, $compute:expr) => {{
4 use std::mem::ManuallyDrop;
16 use std::cell::RefCell;
17 use std::any::{Any, TypeId};
18
19 const NUM_MAX_GENERIC: usize = 2;
21
22 thread_local! {
23 static CACHE: ManuallyDrop<RefCell<[Option<Box<dyn Any>>; NUM_MAX_GENERIC]>> =
24 const { ManuallyDrop::new(RefCell::new([None, None])) };
25 }
26
27 CACHE.with(|cache| {
28 let mut cache = cache.borrow_mut();
29 let type_id = TypeId::of::<$F>();
30
31 cache.iter_mut().find(|c| match c {
32 None => true,
33 Some(any) => (&**any).type_id() == type_id,
34 })
35 .unwrap()
36 .get_or_insert_with(|| Box::new($compute))
37 .downcast_ref::<$F>()
38 .cloned()
39 .unwrap()
40 })
41 }};
42}
43
44macro_rules! cache_one {
46 ($F:ty, $compute:expr) => {{
47 use std::{cell::RefCell, mem::ManuallyDrop};
51
52 thread_local! {
53 static CACHE: ManuallyDrop<RefCell<Option<Box<$F>>>> =
54 const { ManuallyDrop::new(RefCell::new(Option::None)) };
55 }
56
57 CACHE.with(|cache| {
58 let mut cache = cache.borrow_mut();
59 if let Some(cached) = cache.as_ref() {
60 return (**cached).clone();
61 }
62 let data = $compute;
63 let _ = cache.insert(Box::new(data.clone()));
64 data
65 })
66 }};
67}
68
69#[cfg(test)]
70mod tests {
71 use crate::proofs::field::FieldWitness;
72 use ark_ec::short_weierstrass_jacobian::GroupAffine;
73 use poly_commitment::srs::endos;
74 use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
75
76 #[cfg(target_family = "wasm")]
77 use wasm_bindgen_test::wasm_bindgen_test as test;
78
79 #[test]
80 fn test_cache() {
81 use mina_curves::pasta::{Fp, Fq};
82
83 static COUNTER: AtomicUsize = AtomicUsize::new(0);
84
85 fn my_test<F: FieldWitness>() -> (F, F::Scalar) {
86 cache!((F, F::Scalar), {
87 COUNTER.fetch_add(1, Relaxed);
88 endos::<GroupAffine<F::Parameters>>()
89 })
90 }
91
92 let counter = || COUNTER.load(Relaxed);
93
94 assert_eq!(counter(), 0);
95
96 dbg!(my_test::<Fp>());
97 assert_eq!(counter(), 1);
98 dbg!(my_test::<Fp>());
99 dbg!(my_test::<Fp>());
100 dbg!(my_test::<Fp>());
101 assert_eq!(counter(), 1);
102
103 dbg!(my_test::<Fq>());
104 assert_eq!(counter(), 2);
105 dbg!(my_test::<Fq>());
106 dbg!(my_test::<Fq>());
107 dbg!(my_test::<Fq>());
108 assert_eq!(counter(), 2);
109
110 dbg!(my_test::<Fp>());
111 dbg!(my_test::<Fq>());
112 dbg!(my_test::<Fp>());
113 dbg!(my_test::<Fq>());
114 assert_eq!(counter(), 2);
115 }
116}