xprs/
context.rs

1/* Built-in imports */
2use std::collections::{HashMap, HashSet};
3/* Crate imports */
4use crate::token::Function;
5
6/// Represents a symbol in the context.
7#[derive(Debug, PartialEq, PartialOrd, Clone)]
8#[non_exhaustive]
9pub enum Symbol {
10    /// A variable.
11    Variable(f64),
12    /// A function.
13    Function(Function),
14}
15
16impl From<f64> for Symbol {
17    #[inline]
18    fn from(value: f64) -> Self {
19        Self::Variable(value)
20    }
21}
22
23impl From<Function> for Symbol {
24    #[inline]
25    fn from(value: Function) -> Self {
26        Self::Function(value)
27    }
28}
29
30/// Represents the context for the mathematical expression parser.
31///
32/// # Examples
33///
34/// ```
35/// use xprs::{Context, Symbol, xprs_fn};
36///
37/// let sin_xprs_func = xprs_fn!("sin", f64::sin, 1);
38/// let mut context = Context::default()
39///     .with_expected_vars(["y"].into())
40///     .with_var("x", 42.0)
41///     // clone because assert_eq! is used later
42///     .with_fn(sin_xprs_func.clone());
43///
44/// let x_var = context.get("x");
45/// assert_eq!(x_var, Some(&Symbol::Variable(42.0)));
46///
47/// let sin_func = context.get("sin");
48/// assert_eq!(sin_func, Some(&Symbol::Function(sin_xprs_func)));
49///
50/// let expected_vars = context.get_expected_vars();
51/// assert_eq!(expected_vars, Some(&["y"].into()));
52/// ```
53#[derive(Debug, Default, PartialEq, Clone)]
54pub struct Context<'names> {
55    /// The symbols that are available in the context.
56    symbols: HashMap<&'names str, Symbol>,
57    /// Optional set of expected variables.
58    expected_vars: Option<HashSet<&'names str>>,
59}
60
61impl<'names> Context<'names> {
62    /// Sets the value of a variable in the context.
63    #[inline]
64    pub fn set_var<T: Into<f64>>(&mut self, name: &'names str, value: T) {
65        self.symbols.insert(name, value.into().into());
66    }
67
68    /// Sets the value of a variable in the context, returning the context.
69    #[inline]
70    #[must_use]
71    pub fn with_var<T: Into<f64>>(
72        mut self,
73        name: &'names str,
74        value: T,
75    ) -> Self {
76        self.symbols.insert(name, value.into().into());
77        self
78    }
79
80    /// Sets a function in the context.
81    #[inline]
82    pub fn set_fn(&mut self, func: Function) {
83        self.symbols.insert(func.name, func.into());
84    }
85
86    /// Sets a function in the context, returning the context.
87    #[inline]
88    #[must_use]
89    pub fn with_fn(mut self, func: Function) -> Self {
90        self.symbols.insert(func.name, func.into());
91        self
92    }
93
94    /// Sets the expected variables for the context.
95    #[inline]
96    pub fn set_expected_vars(&mut self, expected_vars: HashSet<&'names str>) {
97        self.expected_vars = Some(expected_vars);
98    }
99
100    /// Sets the expected variables for the context, returning the context.
101    #[inline]
102    #[must_use]
103    pub fn with_expected_vars(
104        mut self,
105        expected_vars: HashSet<&'names str>,
106    ) -> Self {
107        self.expected_vars = Some(expected_vars);
108        self
109    }
110
111    /// Sets the symbols for the context.
112    #[inline]
113    #[must_use]
114    pub fn with_symbols(
115        mut self,
116        symbols: HashMap<&'names str, Symbol>,
117    ) -> Self {
118        self.symbols = symbols;
119        self
120    }
121
122    /// Returns the value of a symbol in the context.
123    #[inline]
124    #[must_use]
125    pub fn get(&self, name: &str) -> Option<&Symbol> {
126        self.symbols.get(name)
127    }
128
129    /// Retrieves the set of expected variables from the context.
130    #[inline]
131    #[must_use]
132    pub const fn get_expected_vars(&self) -> Option<&HashSet<&str>> {
133        self.expected_vars.as_ref()
134    }
135}