bc_envelope/extension/expressions/
functions_store.rs

1use std::collections::HashMap;
2
3use super::Function;
4
5/// A store that maps functions to their assigned names.
6///
7/// `FunctionsStore` maintains a registry of functions and their human-readable names,
8/// which is useful for displaying and debugging expression functions. The store
9/// allows for consistent name resolution of functions used in expressions.
10///
11/// # Examples
12///
13/// ```
14/// use bc_envelope::prelude::*;
15/// use bc_envelope::extension::expressions::{FunctionsStore, functions};
16///
17/// // Create a store with some known functions
18/// let store = FunctionsStore::new([
19///     functions::ADD,
20///     functions::SUB,
21///     functions::MUL
22/// ]);
23///
24/// // Look up the name of a function
25/// assert_eq!(store.name(&functions::ADD), "add");
26/// ```
27#[derive(Clone, Debug)]
28pub struct FunctionsStore {
29    dict: HashMap<Function, String>,
30}
31
32impl FunctionsStore {
33    /// Creates a new `FunctionsStore` with the given functions.
34    ///
35    /// # Parameters
36    ///
37    /// * `functions` - An iterable of `Function` instances to store
38    ///
39    /// # Returns
40    ///
41    /// A new `FunctionsStore` containing the functions
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use bc_envelope::prelude::*;
47    /// use bc_envelope::extension::expressions::{FunctionsStore, functions};
48    ///
49    /// // Create a store with standard arithmetic functions
50    /// let store = FunctionsStore::new([
51    ///     functions::ADD,
52    ///     functions::SUB,
53    ///     functions::MUL,
54    ///     functions::DIV
55    /// ]);
56    /// ```
57    pub fn new<T>(functions: T) -> Self
58    where
59        T: IntoIterator<Item = Function>,
60    {
61        let mut dict = HashMap::new();
62        for function in functions {
63            Self::_insert(function, &mut dict);
64        }
65        Self { dict }
66    }
67
68    /// Inserts a function into the store.
69    ///
70    /// # Parameters
71    ///
72    /// * `function` - The function to insert
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use bc_envelope::prelude::*;
78    /// use bc_envelope::extension::expressions::{FunctionsStore, Function, functions};
79    ///
80    /// let mut store = FunctionsStore::default();
81    /// store.insert(functions::ADD);
82    /// store.insert(Function::new_with_static_name(100, "myCustomFunction"));
83    /// ```
84    pub fn insert(&mut self, function: Function) {
85        Self::_insert(function, &mut self.dict);
86    }
87
88    /// Returns the assigned name for a function, if it exists in the store.
89    ///
90    /// # Parameters
91    ///
92    /// * `function` - The function to look up
93    ///
94    /// # Returns
95    ///
96    /// Some string slice with the function name if found, or None if not found
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use bc_envelope::prelude::*;
102    /// use bc_envelope::extension::expressions::{FunctionsStore, functions};
103    ///
104    /// let store = FunctionsStore::new([functions::ADD]);
105    /// assert_eq!(store.assigned_name(&functions::ADD), Some("add"));
106    /// assert_eq!(store.assigned_name(&functions::SUB), None);
107    /// ```
108    pub fn assigned_name(&self, function: &Function) -> Option<&str> {
109        self.dict.get(function).map(|name| name.as_str())
110    }
111
112    /// Returns the name for a function, either from this store or from the function itself.
113    ///
114    /// If the function exists in the store, returns its assigned name.
115    /// Otherwise, returns the function's own name.
116    ///
117    /// # Parameters
118    ///
119    /// * `function` - The function to look up
120    ///
121    /// # Returns
122    ///
123    /// The name of the function as a String
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use bc_envelope::prelude::*;
129    /// use bc_envelope::extension::expressions::{FunctionsStore, functions};
130    ///
131    /// let store = FunctionsStore::new([functions::ADD]);
132    /// assert_eq!(store.name(&functions::ADD), "add");
133    /// // Not in store, so uses function's own name
134    /// assert_eq!(store.name(&functions::SUB), "sub");
135    /// ```
136    pub fn name(&self, function: &Function) -> String {
137        self.assigned_name(function)
138            .map(|name| name.to_string())
139            .unwrap_or_else(|| function.name())
140    }
141
142    /// A static method that returns the name of a function, using an optional store.
143    ///
144    /// This utility method is useful when you have an optional store and want to
145    /// get a function name without additional unwrapping logic.
146    ///
147    /// # Parameters
148    ///
149    /// * `function` - The function to look up
150    /// * `functions` - An optional reference to a FunctionsStore
151    ///
152    /// # Returns
153    ///
154    /// The name of the function as a String
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use bc_envelope::prelude::*;
160    /// use bc_envelope::extension::expressions::{FunctionsStore, functions};
161    ///
162    /// let store = FunctionsStore::new([functions::ADD]);
163    /// 
164    /// // Using the store
165    /// assert_eq!(
166    ///     FunctionsStore::name_for_function(&functions::ADD, Some(&store)),
167    ///     "add"
168    /// );
169    ///
170    /// // Without a store
171    /// assert_eq!(
172    ///     FunctionsStore::name_for_function(&functions::ADD, None),
173    ///     "add"
174    /// );
175    /// ```
176    pub fn name_for_function(function: &Function, functions: Option<&Self>) -> String {
177        functions
178            .and_then(|functions| functions.assigned_name(function))
179            .map(|name| name.to_string())
180            .unwrap_or_else(|| function.name())
181    }
182
183    /// Private helper method to insert a function into the dictionary.
184    ///
185    /// This handles the validation and naming logic for function insertion.
186    fn _insert(function: Function, dict: &mut HashMap<Function, String>) {
187        match function {
188            Function::Known(_, _) => {
189                let name = function.name();
190                dict.insert(function, name);
191            }
192            _ => panic!(),
193        }
194    }
195}
196
197/// Provides a default empty store.
198impl Default for FunctionsStore {
199    fn default() -> Self {
200        Self::new([])
201    }
202}