bimm_contracts/
bindings.rs1use alloc::vec::Vec;
4
5pub trait StackMap<'a, V>
7where
8 V: Default + Copy,
9{
10 #[must_use]
20 fn lookup(&self, key: &'a str) -> Option<V>;
21
22 #[must_use]
36 fn export_key_values<const K: usize>(&self, keys: &'a [&str; K]) -> [V; K] {
37 let mut values: [V; K] = [Default::default(); K];
38 for i in 0..K {
39 let key = keys[i];
40 values[i] = match self.lookup(key) {
41 Some(v) => v,
42 None => panic!("No value for key \"{key}\""),
43 };
44 }
45 values
46 }
47}
48
49pub type StackEnvironment<'a> = &'a [(&'a str, usize)];
51
52impl<'a> StackMap<'a, usize> for StackEnvironment<'a> {
53 #[inline]
54 fn lookup(&self, key: &'a str) -> Option<usize> {
55 for &(k, v) in self.iter() {
56 if k == key {
57 return Some(v);
58 }
59 }
60 None
61 }
62}
63
64pub trait MutableStackMap<'a, V>: StackMap<'a, V>
68where
69 V: Default + Copy,
70{
71 fn bind(&mut self, key: &'a str, value: V);
86}
87
88pub struct MutableStackEnvironment<'a> {
90 pub backing: StackEnvironment<'a>,
92
93 pub updates: Vec<(&'a str, usize)>,
95}
96
97impl<'a> MutableStackEnvironment<'a> {
98 #[inline]
112 #[must_use]
113 fn updates_first_lookup(&self, key: &'a str) -> Option<usize> {
114 self.updates
115 .as_slice()
116 .lookup(key)
117 .or_else(|| self.backing.lookup(key))
118 }
119}
120
121impl<'a> StackMap<'a, usize> for MutableStackEnvironment<'a> {
122 #[inline]
123 fn lookup(&self, key: &str) -> Option<usize> {
124 self.backing
125 .lookup(key)
126 .or_else(|| self.updates.as_slice().lookup(key))
127 }
128
129 #[inline]
130 fn export_key_values<const K: usize>(&self, keys: &'a [&str; K]) -> [usize; K] {
131 let mut values: [usize; K] = [Default::default(); K];
132 for i in 0..K {
133 let key = keys[i];
134 values[i] = match self.updates_first_lookup(key) {
135 Some(v) => v,
136 None => panic!("No value for key \"{key}\""),
137 };
138 }
139 values
140 }
141}
142
143impl<'a> MutableStackMap<'a, usize> for MutableStackEnvironment<'a> {
144 #[inline]
145 fn bind(&mut self, key: &'a str, value: usize) {
146 #[cfg(debug_assertions)]
147 assert!(self.lookup(key).is_none(), "double-bind: {key}");
148
149 self.updates.push((key, value))
150 }
151}
152
153impl<'a> MutableStackEnvironment<'a> {
154 #[inline(always)]
156 pub fn new(bindings: StackEnvironment<'a>) -> Self {
157 MutableStackEnvironment {
158 backing: bindings,
159 updates: Vec::new(),
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_stack_bindings() {
170 {
171 let env: StackEnvironment = &[("a", 1), ("b", 2)];
173
174 assert_eq!(env.lookup("a"), Some(1));
175 assert_eq!(env.lookup("b"), Some(2));
176 assert_eq!(env.lookup("c"), None);
177 }
178 {
179 static ENV: StackEnvironment = &[("a", 1), ("b", 2)];
181
182 assert_eq!(ENV.lookup("a"), Some(1));
183 assert_eq!(ENV.lookup("b"), Some(2));
184 assert_eq!(ENV.lookup("c"), None);
185
186 let keys = ["b", "a"];
188 assert_eq!(ENV.export_key_values(&keys), [2, 1]);
189 }
190 }
191
192 #[should_panic(expected = "No value for key \"d\"")]
193 #[test]
194 fn test_stack_env_export_key_values_panic() {
195 let env: StackEnvironment = &[("a", 1), ("b", 2)];
196 let keys = ["a", "b", "d"]; let _ = env.export_key_values(&keys); }
199
200 #[test]
201 fn test_mutable_stack_bindings() {
202 let mut env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
203
204 assert_eq!(env.lookup("a"), Some(1));
205 assert_eq!(env.lookup("b"), Some(2));
206 assert_eq!(env.lookup("c"), None);
207
208 env.bind("c", 3);
209 assert_eq!(env.lookup("c"), Some(3));
210
211 let keys = ["a", "b", "c"];
213 let values = env.export_key_values(&keys);
214 assert_eq!(values, [1, 2, 3]);
215 }
216
217 #[should_panic(expected = "No value for key \"d\"")]
218 #[test]
219 fn test_muttable_stack_env_export_key_values_panic() {
220 let env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
221 let keys = ["a", "b", "d"]; let _ = env.export_key_values(&keys); }
224
225 #[should_panic(expected = "double-bind: a")]
226 #[test]
227 #[cfg(debug_assertions)]
228 fn test_double_bind_panic() {
229 let mut env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
230 env.bind("a", 3);
231 }
232}