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