conch_runtime_pshaw/env/
func.rs1use crate::env::SubEnvironment;
2use std::collections::HashMap;
3use std::fmt;
4use std::hash::Hash;
5use std::sync::Arc;
6
7pub trait FunctionEnvironment {
9 type FnName;
11 type Fn;
13
14 fn function(&self, name: &Self::FnName) -> Option<&Self::Fn>;
16 fn set_function(&mut self, name: Self::FnName, func: Self::Fn);
18
19 fn has_function(&self, name: &Self::FnName) -> bool {
21 self.function(name).is_some()
22 }
23}
24
25impl<'a, T: ?Sized + FunctionEnvironment> FunctionEnvironment for &'a mut T {
26 type FnName = T::FnName;
27 type Fn = T::Fn;
28
29 fn function(&self, name: &Self::FnName) -> Option<&Self::Fn> {
30 (**self).function(name)
31 }
32
33 fn set_function(&mut self, name: Self::FnName, func: Self::Fn) {
34 (**self).set_function(name, func);
35 }
36
37 fn has_function(&self, name: &Self::FnName) -> bool {
38 (**self).has_function(name)
39 }
40}
41
42pub trait UnsetFunctionEnvironment: FunctionEnvironment {
44 fn unset_function(&mut self, name: &Self::FnName);
46}
47
48impl<'a, T: ?Sized + UnsetFunctionEnvironment> UnsetFunctionEnvironment for &'a mut T {
49 fn unset_function(&mut self, name: &Self::FnName) {
50 (**self).unset_function(name);
51 }
52}
53
54pub trait FunctionFrameEnvironment {
56 fn push_fn_frame(&mut self);
58 fn pop_fn_frame(&mut self);
60 fn is_fn_running(&self) -> bool;
62}
63
64impl<'a, T: ?Sized + FunctionFrameEnvironment> FunctionFrameEnvironment for &'a mut T {
65 fn push_fn_frame(&mut self) {
66 (**self).push_fn_frame()
67 }
68
69 fn pop_fn_frame(&mut self) {
70 (**self).pop_fn_frame()
71 }
72
73 fn is_fn_running(&self) -> bool {
74 (**self).is_fn_running()
75 }
76}
77
78#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
80pub struct FnFrameEnv {
81 num_frames: usize,
82}
83
84impl FnFrameEnv {
85 pub fn new() -> Self {
87 Self { num_frames: 0 }
88 }
89}
90
91impl FunctionFrameEnvironment for FnFrameEnv {
92 fn push_fn_frame(&mut self) {
98 self.num_frames = self
99 .num_frames
100 .checked_add(1)
101 .expect("function frame overflow");
102 }
103
104 fn pop_fn_frame(&mut self) {
105 self.num_frames = self.num_frames.saturating_sub(1);
106 }
107
108 fn is_fn_running(&self) -> bool {
109 self.num_frames > 0
110 }
111}
112
113impl SubEnvironment for FnFrameEnv {
114 fn sub_env(&self) -> Self {
115 *self
116 }
117}
118
119#[derive(PartialEq, Eq)]
121pub struct FnEnv<N: Hash + Eq, F> {
122 functions: Arc<HashMap<N, F>>,
123}
124
125impl<N: Hash + Eq, F> FnEnv<N, F> {
126 pub fn new() -> Self {
128 Self {
129 functions: HashMap::new().into(),
130 }
131 }
132
133 pub(crate) fn fn_names(&self) -> ::std::collections::hash_map::Keys<'_, N, F> {
134 self.functions.keys()
135 }
136}
137
138impl<N, F> fmt::Debug for FnEnv<N, F>
139where
140 N: Hash + Eq + fmt::Debug + Ord,
141 F: fmt::Debug,
142{
143 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
144 use std::collections::BTreeMap;
145 use std::iter::FromIterator;
146
147 fmt.debug_struct(stringify!(FnEnv))
148 .field("functions", &BTreeMap::from_iter(self.functions.iter()))
149 .finish()
150 }
151}
152
153impl<N: Hash + Eq, F> Default for FnEnv<N, F> {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159impl<N: Hash + Eq, F> Clone for FnEnv<N, F> {
160 fn clone(&self) -> Self {
161 Self {
162 functions: self.functions.clone(),
163 }
164 }
165}
166
167impl<N: Hash + Eq, F> SubEnvironment for FnEnv<N, F> {
168 fn sub_env(&self) -> Self {
169 self.clone()
170 }
171}
172
173impl<N, F> FunctionEnvironment for FnEnv<N, F>
174where
175 N: Clone + Hash + Eq,
176 F: Clone,
177{
178 type FnName = N;
179 type Fn = F;
180
181 fn function(&self, name: &Self::FnName) -> Option<&Self::Fn> {
182 self.functions.get(name)
183 }
184
185 fn set_function(&mut self, name: Self::FnName, func: Self::Fn) {
186 Arc::make_mut(&mut self.functions).insert(name, func);
187 }
188}
189
190impl<N, F> UnsetFunctionEnvironment for FnEnv<N, F>
191where
192 N: Clone + Hash + Eq,
193 F: Clone,
194{
195 fn unset_function(&mut self, name: &Self::FnName) {
196 if self.has_function(name) {
197 Arc::make_mut(&mut self.functions).remove(name);
198 }
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::env::SubEnvironment;
206 use crate::RefCounted;
207
208 #[test]
209 fn test_set_get_unset_function() {
210 let name = "var";
211 let func = "some func";
212 let mut env = FnEnv::new();
213 assert_eq!(env.function(&name), None);
214 env.set_function(name, func);
215 assert_eq!(env.function(&name), Some(&func));
216 env.unset_function(&name);
217 assert_eq!(env.function(&name), None);
218 }
219
220 #[test]
221 fn test_sub_env_no_needless_clone() {
222 let not_set = "not set";
223 let name = "var";
224 let func = "some function";
225 let mut env = FnEnv::new();
226 env.set_function(name, func);
227
228 let mut env = env.sub_env();
229
230 env.unset_function(¬_set);
231 if env.functions.get_mut().is_some() {
232 panic!("needles clone!");
233 }
234 }
235
236 #[test]
237 fn test_set_function_in_parent_visible_in_child() {
238 let fn_name = "foo";
239 let func = 42;
240 let mut parent = FnEnv::new();
241 parent.set_function(fn_name, func);
242
243 {
244 let child = parent.sub_env();
245 assert_eq!(child.has_function(&fn_name), true);
246 assert_eq!(child.function(&fn_name), Some(&func));
247 }
248 }
249
250 #[test]
251 fn test_set_and_unset_function_in_child_should_not_affect_parent() {
252 let fn_name_parent = "parent fn";
253 let fn_name_child = "child fn";
254
255 let fn_parent = 42;
256 let fn_child = 5;
257
258 let mut parent = FnEnv::new();
259 parent.set_function(fn_name_parent, fn_parent);
260
261 {
262 let mut child = parent.sub_env();
263 child.set_function(fn_name_parent, fn_child);
264 child.set_function(fn_name_child, fn_child);
265
266 assert_eq!(child.has_function(&fn_name_parent), true);
267 assert_eq!(child.has_function(&fn_name_child), true);
268 assert_eq!(child.function(&fn_name_parent), Some(&fn_child));
269 assert_eq!(child.function(&fn_name_child), Some(&fn_child));
270 }
271
272 assert_eq!(parent.has_function(&fn_name_parent), true);
273 assert_eq!(parent.has_function(&fn_name_child), false);
274 assert_eq!(parent.function(&fn_name_parent), Some(&fn_parent));
275 assert_eq!(parent.function(&fn_name_child), None);
276 }
277
278 #[test]
279 fn test_fn_frame_smoke() {
280 let mut env = FnFrameEnv::new();
281 assert_eq!(env.is_fn_running(), false);
282
283 env.pop_fn_frame();
285 assert_eq!(env.is_fn_running(), false);
286
287 env.push_fn_frame();
288 assert_eq!(env.is_fn_running(), true);
289
290 env.push_fn_frame();
291 assert_eq!(env.is_fn_running(), true);
292
293 env.pop_fn_frame();
294 assert_eq!(env.is_fn_running(), true);
295
296 env.pop_fn_frame();
297 assert_eq!(env.is_fn_running(), false);
298 }
299
300 #[test]
301 #[should_panic(expected = "function frame overflow")]
302 fn test_fn_frame_overflow() {
303 let mut env = FnFrameEnv::new();
304 env.num_frames = usize::max_value();
305
306 env.push_fn_frame();
307 }
308}