bc_envelope/extension/expressions/
parameters_store.rs

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