bimm_contracts/
bindings.rs1pub trait StackMap<'a, V>
3where
4 V: Default + Copy,
5{
6 #[must_use]
16 fn lookup(
17 &self,
18 key: &'a str,
19 ) -> Option<V>;
20
21 #[must_use]
35 fn export_key_values<const K: usize>(
36 &self,
37 keys: &'a [&str; K],
38 ) -> [V; K] {
39 let mut values: [V; K] = [Default::default(); K];
40 for i in 0..K {
41 let key = keys[i];
42 values[i] = match self.lookup(key) {
43 Some(v) => v,
44 None => panic!("No value for key \"{key}\""),
45 };
46 }
47 values
48 }
49}
50
51pub type StackEnvironment<'a> = &'a [(&'a str, usize)];
53
54impl<'a> StackMap<'a, usize> for StackEnvironment<'a> {
55 #[inline]
56 fn lookup(
57 &self,
58 key: &'a str,
59 ) -> Option<usize> {
60 for &(k, v) in self.iter() {
61 if k == key {
62 return Some(v);
63 }
64 }
65 None
66 }
67}
68
69pub trait MutableStackMap<'a, V>: StackMap<'a, V>
73where
74 V: Default + Copy,
75{
76 fn bind(
91 &mut self,
92 key: &'a str,
93 value: V,
94 );
95}
96
97pub struct MutableStackEnvironment<'a> {
99 pub backing: StackEnvironment<'a>,
101
102 pub updates: Vec<(&'a str, usize)>,
104}
105
106impl<'a> MutableStackEnvironment<'a> {
107 #[inline]
121 #[must_use]
122 fn updates_first_lookup(
123 &self,
124 key: &'a str,
125 ) -> Option<usize> {
126 self.updates
127 .as_slice()
128 .lookup(key)
129 .or_else(|| self.backing.lookup(key))
130 }
131}
132
133impl<'a> StackMap<'a, usize> for MutableStackEnvironment<'a> {
134 #[inline]
135 fn lookup(
136 &self,
137 key: &str,
138 ) -> Option<usize> {
139 self.backing
140 .lookup(key)
141 .or_else(|| self.updates.as_slice().lookup(key))
142 }
143
144 #[inline]
145 fn export_key_values<const K: usize>(
146 &self,
147 keys: &'a [&str; K],
148 ) -> [usize; K] {
149 let mut values: [usize; K] = [Default::default(); K];
150 for i in 0..K {
151 let key = keys[i];
152 values[i] = match self.updates_first_lookup(key) {
153 Some(v) => v,
154 None => panic!("No value for key \"{key}\""),
155 };
156 }
157 values
158 }
159}
160
161impl<'a> MutableStackMap<'a, usize> for MutableStackEnvironment<'a> {
162 #[inline]
163 fn bind(
164 &mut self,
165 key: &'a str,
166 value: usize,
167 ) {
168 #[cfg(debug_assertions)]
169 assert!(self.lookup(key).is_none(), "double-bind: {key}");
170
171 self.updates.push((key, value))
172 }
173}
174
175impl<'a> MutableStackEnvironment<'a> {
176 #[inline(always)]
178 pub fn new(bindings: StackEnvironment<'a>) -> Self {
179 MutableStackEnvironment {
180 backing: bindings,
181 updates: Vec::new(),
182 }
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_stack_bindings() {
192 {
193 let env: StackEnvironment = &[("a", 1), ("b", 2)];
195
196 assert_eq!(env.lookup("a"), Some(1));
197 assert_eq!(env.lookup("b"), Some(2));
198 assert_eq!(env.lookup("c"), None);
199 }
200 {
201 static ENV: StackEnvironment = &[("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 let keys = ["b", "a"];
210 assert_eq!(ENV.export_key_values(&keys), [2, 1]);
211 }
212 }
213
214 #[should_panic(expected = "No value for key \"d\"")]
215 #[test]
216 fn test_stack_env_export_key_values_panic() {
217 let env: StackEnvironment = &[("a", 1), ("b", 2)];
218 let keys = ["a", "b", "d"]; let _ = env.export_key_values(&keys); }
221
222 #[test]
223 fn test_mutable_stack_bindings() {
224 let mut env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
225
226 assert_eq!(env.lookup("a"), Some(1));
227 assert_eq!(env.lookup("b"), Some(2));
228 assert_eq!(env.lookup("c"), None);
229
230 env.bind("c", 3);
231 assert_eq!(env.lookup("c"), Some(3));
232
233 let keys = ["a", "b", "c"];
235 let values = env.export_key_values(&keys);
236 assert_eq!(values, [1, 2, 3]);
237 }
238
239 #[should_panic(expected = "No value for key \"d\"")]
240 #[test]
241 fn test_muttable_stack_env_export_key_values_panic() {
242 let env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
243 let keys = ["a", "b", "d"]; let _ = env.export_key_values(&keys); }
246
247 #[should_panic(expected = "double-bind: a")]
248 #[test]
249 #[cfg(debug_assertions)]
250 fn test_double_bind_panic() {
251 let mut env = MutableStackEnvironment::new(&[("a", 1), ("b", 2)]);
252 env.bind("a", 3);
253 }
254}