arithmetic_eval/values/
env.rs

1//! Environment containing named `Value`s.
2
3use hashbrown::{hash_map, HashMap};
4
5use core::{
6    iter::{self, FromIterator},
7    ops,
8};
9
10use crate::{
11    alloc::{String, ToOwned},
12    fns, NativeFn, Value,
13};
14
15/// Environment containing named `Value`s.
16///
17/// Note that the environment implements the [`Index`](ops::Index) trait, which allows to eloquently
18/// access or modify environment. Similarly, [`IntoIterator`] / [`FromIterator`] / [`Extend`] traits
19/// allow to construct environments.
20///
21/// # Examples
22///
23/// ```
24/// use arithmetic_eval::{Environment, Comparisons, Prelude, Value};
25///
26/// // Load environment from the standard containers.
27/// let mut env: Environment<'_, f64> = Prelude.iter()
28///     .chain(Comparisons.iter())
29///     // Add a custom variable for a good measure.
30///     .chain(vec![("x", Value::Prim(1.0))])
31///     .collect();
32///
33/// assert_eq!(env["true"], Value::Bool(true));
34/// assert_eq!(env["x"], Value::Prim(1.0));
35/// for (name, value) in &env {
36///     println!("{} -> {:?}", name, value);
37/// }
38///
39/// // It's possible to base an environment on other env, as well.
40/// let other_env: Environment<'_, _> = env.into_iter()
41///     .filter(|(_, val)| val.is_function())
42///     .collect();
43/// assert!(other_env.get("x").is_none());
44/// ```
45#[derive(Debug)]
46pub struct Environment<'a, T> {
47    variables: HashMap<String, Value<'a, T>>,
48}
49
50impl<T> Default for Environment<'_, T> {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56impl<T: Clone> Clone for Environment<'_, T> {
57    fn clone(&self) -> Self {
58        Self {
59            variables: self.variables.clone(),
60        }
61    }
62}
63
64impl<T: PartialEq> PartialEq for Environment<'_, T> {
65    fn eq(&self, other: &Self) -> bool {
66        self.variables == other.variables
67    }
68}
69
70impl<'a, T> Environment<'a, T> {
71    /// Creates a new environment.
72    pub fn new() -> Self {
73        Self {
74            variables: HashMap::new(),
75        }
76    }
77
78    /// Gets a variable by name.
79    pub fn get(&self, name: &str) -> Option<&Value<'a, T>> {
80        self.variables.get(name)
81    }
82
83    /// Iterates over variables.
84    pub fn iter(&self) -> impl Iterator<Item = (&str, &Value<'a, T>)> + '_ {
85        self.variables
86            .iter()
87            .map(|(name, value)| (name.as_str(), value))
88    }
89
90    /// Inserts a variable with the specified name.
91    pub fn insert(&mut self, name: &str, value: Value<'a, T>) -> &mut Self {
92        self.variables.insert(name.to_owned(), value);
93        self
94    }
95
96    /// Inserts a native function with the specified name.
97    pub fn insert_native_fn(
98        &mut self,
99        name: &str,
100        native_fn: impl NativeFn<T> + 'static,
101    ) -> &mut Self {
102        self.insert(name, Value::native_fn(native_fn))
103    }
104
105    /// Inserts a [wrapped function](fns::FnWrapper) with the specified name.
106    ///
107    /// Calling this method is equivalent to [`wrap`](fns::wrap)ping a function and calling
108    /// [`insert_native_fn()`](Self::insert_native_fn) on it. Thanks to type inference magic,
109    /// the Rust compiler will usually be able to extract the `Args` type param
110    /// from the function definition, provided that type of function arguments and its return type
111    /// are defined explicitly or can be unequivocally inferred from the declaration.
112    pub fn insert_wrapped_fn<Args, F>(&mut self, name: &str, fn_to_wrap: F) -> &mut Self
113    where
114        fns::FnWrapper<Args, F>: NativeFn<T> + 'static,
115    {
116        let wrapped = fns::wrap::<Args, _>(fn_to_wrap);
117        self.insert(name, Value::native_fn(wrapped))
118    }
119}
120
121impl<'a, T> ops::Index<&str> for Environment<'a, T> {
122    type Output = Value<'a, T>;
123
124    fn index(&self, index: &str) -> &Self::Output {
125        self.get(index)
126            .unwrap_or_else(|| panic!("Variable `{}` is not defined", index))
127    }
128}
129
130impl<'a, T> IntoIterator for Environment<'a, T> {
131    type Item = (String, Value<'a, T>);
132    type IntoIter = IntoIter<'a, T>;
133
134    fn into_iter(self) -> Self::IntoIter {
135        IntoIter {
136            inner: self.variables.into_iter(),
137        }
138    }
139}
140
141/// Result of converting `Environment` into an iterator.
142#[derive(Debug)]
143pub struct IntoIter<'a, T> {
144    inner: hash_map::IntoIter<String, Value<'a, T>>,
145}
146
147impl<'a, T> Iterator for IntoIter<'a, T> {
148    type Item = (String, Value<'a, T>);
149
150    fn next(&mut self) -> Option<Self::Item> {
151        self.inner.next()
152    }
153
154    fn size_hint(&self) -> (usize, Option<usize>) {
155        self.inner.size_hint()
156    }
157}
158
159impl<T> ExactSizeIterator for IntoIter<'_, T> {
160    fn len(&self) -> usize {
161        self.inner.len()
162    }
163}
164
165impl<'r, 'a, T> IntoIterator for &'r Environment<'a, T> {
166    type Item = (&'r str, &'r Value<'a, T>);
167    type IntoIter = Iter<'r, 'a, T>;
168
169    fn into_iter(self) -> Self::IntoIter {
170        Iter {
171            inner: self
172                .variables
173                .iter()
174                .map(|(name, value)| (name.as_str(), value)),
175        }
176    }
177}
178
179type MapFn<'r, 'a, T> = fn((&'r String, &'r Value<'a, T>)) -> (&'r str, &'r Value<'a, T>);
180
181/// Iterator over references of the `Environment` entries.
182#[derive(Debug)]
183pub struct Iter<'r, 'a, T> {
184    inner: iter::Map<hash_map::Iter<'r, String, Value<'a, T>>, MapFn<'r, 'a, T>>,
185}
186
187impl<'r, 'a, T> Iterator for Iter<'r, 'a, T> {
188    type Item = (&'r str, &'r Value<'a, T>);
189
190    fn next(&mut self) -> Option<Self::Item> {
191        self.inner.next()
192    }
193
194    fn size_hint(&self) -> (usize, Option<usize>) {
195        self.inner.size_hint()
196    }
197}
198
199impl<T> ExactSizeIterator for Iter<'_, '_, T> {
200    fn len(&self) -> usize {
201        self.inner.len()
202    }
203}
204
205impl<'a, T, S, V> FromIterator<(S, V)> for Environment<'a, T>
206where
207    S: Into<String>,
208    V: Into<Value<'a, T>>,
209{
210    fn from_iter<I: IntoIterator<Item = (S, V)>>(iter: I) -> Self {
211        let variables = iter
212            .into_iter()
213            .map(|(var_name, value)| (var_name.into(), value.into()));
214        Self {
215            variables: variables.collect(),
216        }
217    }
218}
219
220impl<'a, T, S, V> Extend<(S, V)> for Environment<'a, T>
221where
222    S: Into<String>,
223    V: Into<Value<'a, T>>,
224{
225    fn extend<I: IntoIterator<Item = (S, V)>>(&mut self, iter: I) {
226        let variables = iter
227            .into_iter()
228            .map(|(var_name, value)| (var_name.into(), value.into()));
229        self.variables.extend(variables);
230    }
231}