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}