1use core::{iter, ops};
4
5pub use self::variable_map::{Assertions, Comparisons, Prelude};
6use crate::{
7 NativeFn, Value,
8 alloc::{Arc, HashMap, String, ToOwned, hash_map},
9 arith::{OrdArithmetic, StdArithmetic},
10 exec::Operations,
11 fns,
12};
13
14mod variable_map;
15
16#[derive(Debug, Clone)]
47pub struct Environment<T> {
48 variables: HashMap<String, Value<T>>,
49 arithmetic: Arc<dyn OrdArithmetic<T>>,
50}
51
52impl<T> Default for Environment<T>
53where
54 StdArithmetic: OrdArithmetic<T>,
55{
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl<T: PartialEq> PartialEq for Environment<T> {
63 fn eq(&self, other: &Self) -> bool {
64 self.variables == other.variables
65 }
66}
67
68impl<T> Environment<T>
69where
70 StdArithmetic: OrdArithmetic<T>,
71{
72 pub fn new() -> Self {
74 Self {
75 variables: HashMap::new(),
76 arithmetic: Arc::new(StdArithmetic),
77 }
78 }
79}
80
81impl<T> Environment<T> {
82 pub fn with_arithmetic<A>(arithmetic: A) -> Self
84 where
85 A: OrdArithmetic<T> + 'static,
86 {
87 Self {
88 variables: HashMap::new(),
89 arithmetic: Arc::new(arithmetic),
90 }
91 }
92
93 pub(crate) fn operations(&self) -> Operations<'_, T> {
94 Operations::from(&*self.arithmetic)
95 }
96
97 pub fn get(&self, name: &str) -> Option<&Value<T>> {
99 self.variables.get(name)
100 }
101
102 pub fn contains(&self, name: &str) -> bool {
104 self.variables.contains_key(name)
105 }
106
107 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value<T>)> + '_ {
109 self.variables
110 .iter()
111 .map(|(name, value)| (name.as_str(), value))
112 }
113
114 pub fn insert(&mut self, name: &str, value: Value<T>) -> &mut Self {
116 self.variables.insert(name.to_owned(), value);
117 self
118 }
119
120 pub fn insert_native_fn(
122 &mut self,
123 name: &str,
124 native_fn: impl NativeFn<T> + 'static,
125 ) -> &mut Self {
126 self.insert(name, Value::native_fn(native_fn))
127 }
128
129 pub fn insert_wrapped_fn<const CTX: bool, Args, F>(
137 &mut self,
138 name: &str,
139 fn_to_wrap: F,
140 ) -> &mut Self
141 where
142 fns::FnWrapper<Args, F, CTX>: NativeFn<T> + 'static,
143 {
144 let wrapped = fns::wrap::<CTX, Args, _>(fn_to_wrap);
145 self.insert(name, Value::native_fn(wrapped))
146 }
147}
148
149impl<T> ops::Index<&str> for Environment<T> {
150 type Output = Value<T>;
151
152 fn index(&self, index: &str) -> &Self::Output {
153 self.get(index)
154 .unwrap_or_else(|| panic!("Variable `{index}` is not defined"))
155 }
156}
157
158impl<T> IntoIterator for Environment<T> {
159 type Item = (String, Value<T>);
160 type IntoIter = IntoIter<T>;
161
162 fn into_iter(self) -> Self::IntoIter {
163 IntoIter {
164 inner: self.variables.into_iter(),
165 }
166 }
167}
168
169#[derive(Debug)]
171pub struct IntoIter<T> {
172 inner: hash_map::IntoIter<String, Value<T>>,
173}
174
175impl<T> Iterator for IntoIter<T> {
176 type Item = (String, Value<T>);
177
178 fn next(&mut self) -> Option<Self::Item> {
179 self.inner.next()
180 }
181
182 fn size_hint(&self) -> (usize, Option<usize>) {
183 self.inner.size_hint()
184 }
185}
186
187impl<T> ExactSizeIterator for IntoIter<T> {
188 fn len(&self) -> usize {
189 self.inner.len()
190 }
191}
192
193impl<'r, T> IntoIterator for &'r Environment<T> {
194 type Item = (&'r str, &'r Value<T>);
195 type IntoIter = Iter<'r, T>;
196
197 fn into_iter(self) -> Self::IntoIter {
198 Iter {
199 inner: self
200 .variables
201 .iter()
202 .map(|(name, value)| (name.as_str(), value)),
203 }
204 }
205}
206
207type MapFn<'r, T> = fn((&'r String, &'r Value<T>)) -> (&'r str, &'r Value<T>);
208
209#[derive(Debug)]
211pub struct Iter<'r, T> {
212 inner: iter::Map<hash_map::Iter<'r, String, Value<T>>, MapFn<'r, T>>,
213}
214
215impl<'r, T> Iterator for Iter<'r, T> {
216 type Item = (&'r str, &'r Value<T>);
217
218 fn next(&mut self) -> Option<Self::Item> {
219 self.inner.next()
220 }
221
222 fn size_hint(&self) -> (usize, Option<usize>) {
223 self.inner.size_hint()
224 }
225}
226
227impl<T> ExactSizeIterator for Iter<'_, T> {
228 fn len(&self) -> usize {
229 self.inner.len()
230 }
231}
232
233impl<T, S, V> Extend<(S, V)> for Environment<T>
234where
235 S: Into<String>,
236 V: Into<Value<T>>,
237{
238 fn extend<I: IntoIterator<Item = (S, V)>>(&mut self, iter: I) {
239 let variables = iter
240 .into_iter()
241 .map(|(var_name, value)| (var_name.into(), value.into()));
242 self.variables.extend(variables);
243 }
244}