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