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}