Skip to main content

options/
lib.rs

1//! Data structure for managing named parameters.
2//!
3//! ## Example
4//!
5//! ```
6//! use options::Options;
7//!
8//! let mut options = Options::default();
9//!
10//! options
11//!     .set("foo", 42)
12//!     .set("bar", "To be or not to be?")
13//!     .set("baz", "Hello, world!".to_string());
14//!
15//! println!("foo = {}", options.get::<i32>("foo").unwrap());
16//! println!("bar = {}", options.get::<&str>("bar").unwrap());
17//! println!("baz = {}", options.get::<String>("baz").unwrap());
18//! ```
19
20use std::any::Any;
21use std::collections::hash_map::{HashMap, Iter, IterMut};
22
23/// A collection of named parameters.
24#[derive(Debug, Default)]
25pub struct Options(HashMap<Name, Value>);
26
27/// A parameter name.
28pub type Name = String;
29
30/// A parameter value.
31#[derive(Debug)]
32pub struct Value(Box<dyn Any>);
33
34/// An iterator over parameters.
35pub struct Parameters<'l> {
36    iterator: Iter<'l, Name, Value>,
37}
38
39/// An iterator over mutable parameters.
40pub struct ParametersMut<'l> {
41    iterator: IterMut<'l, Name, Value>,
42}
43
44/// An iterator over names.
45pub struct Names<'l> {
46    #[allow(clippy::type_complexity)]
47    iterator: std::iter::Map<Iter<'l, Name, Value>, fn((&'l Name, &'l Value)) -> &'l Name>,
48}
49
50impl Options {
51    /// Get the value of a parameter.
52    #[inline]
53    pub fn get<T: Any + Clone>(&self, name: &str) -> Option<T> {
54        self.0.get(name).and_then(|value| value.get())
55    }
56
57    /// Get a reference to the value of a parameter.
58    #[inline]
59    pub fn get_ref<T: Any>(&self, name: &str) -> Option<&T> {
60        self.0.get(name).and_then(|value| value.get_ref())
61    }
62
63    /// Get a mutable reference to the value of a parameter.
64    #[inline]
65    pub fn get_mut<T: Any>(&mut self, name: &str) -> Option<&mut T> {
66        self.0.get_mut(name).and_then(|value| value.get_mut())
67    }
68
69    /// Set the value of a parameter.
70    #[inline]
71    pub fn set<T: Into<String>, U: Any>(&mut self, name: T, value: U) -> &mut Options {
72        self.0.insert(name.into(), Value(Box::new(value)));
73        self
74    }
75
76    /// Check the presence of a parameter.
77    #[inline]
78    pub fn has(&self, name: &str) -> bool {
79        self.0.contains_key(name)
80    }
81
82    /// Return an iterator over parameters.
83    pub fn iter(&self) -> Parameters<'_> {
84        Parameters {
85            iterator: self.0.iter(),
86        }
87    }
88
89    /// Return an iterator over mutable parameters.
90    pub fn iter_mut(&mut self) -> ParametersMut<'_> {
91        ParametersMut {
92            iterator: self.0.iter_mut(),
93        }
94    }
95
96    /// Return an iterator over names.
97    #[inline]
98    pub fn names(&self) -> Names<'_> {
99        fn first<'l>((name, _): (&'l Name, &'l Value)) -> &'l Name {
100            name
101        }
102        Names {
103            iterator: self.0.iter().map(first),
104        }
105    }
106}
107
108impl Value {
109    /// Get the value.
110    #[inline]
111    pub fn get<T: Any + Clone>(&self) -> Option<T> {
112        self.0.downcast_ref::<T>().cloned()
113    }
114
115    /// Get a reference to the value.
116    #[inline]
117    pub fn get_ref<T: Any>(&self) -> Option<&T> {
118        self.0.downcast_ref::<T>()
119    }
120
121    /// Get a mutable reference to the value.
122    #[inline]
123    pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
124        self.0.downcast_mut::<T>()
125    }
126
127    /// Set the value.
128    #[inline]
129    pub fn set<T: Any>(&mut self, value: T) {
130        self.0 = Box::new(value);
131    }
132}
133
134impl<'l> IntoIterator for &'l Options {
135    type Item = (&'l Name, &'l Value);
136    type IntoIter = Parameters<'l>;
137
138    #[inline]
139    fn into_iter(self) -> Parameters<'l> {
140        self.iter()
141    }
142}
143
144impl<'l> IntoIterator for &'l mut Options {
145    type Item = (&'l Name, &'l mut Value);
146    type IntoIter = ParametersMut<'l>;
147
148    #[inline]
149    fn into_iter(self) -> ParametersMut<'l> {
150        self.iter_mut()
151    }
152}
153
154impl<'l> Iterator for Parameters<'l> {
155    type Item = (&'l Name, &'l Value);
156
157    #[inline]
158    fn next(&mut self) -> Option<(&'l Name, &'l Value)> {
159        self.iterator.next()
160    }
161}
162
163impl<'l> Iterator for ParametersMut<'l> {
164    type Item = (&'l Name, &'l mut Value);
165
166    #[inline]
167    fn next(&mut self) -> Option<(&'l Name, &'l mut Value)> {
168        self.iterator.next()
169    }
170}
171
172impl<'l> Iterator for Names<'l> {
173    type Item = &'l Name;
174
175    #[inline]
176    fn next(&mut self) -> Option<&'l Name> {
177        self.iterator.next()
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::Options;
184
185    #[test]
186    fn get() {
187        let options = setup();
188
189        macro_rules! test(
190            ($name:expr, $value:expr, $kind:ty) => (
191                assert_eq!(options.get::<$kind>($name).unwrap(), $value)
192            );
193        );
194
195        test!("a", 42, i32);
196        test!("b", true, bool);
197        test!("c", "Hi, there!", &str);
198        test!("d", "Hello, world!".to_string(), String);
199        test!("e", vec![4u8, 2u8], Vec<u8>);
200    }
201
202    #[test]
203    fn get_ref() {
204        let options = setup();
205
206        macro_rules! test(
207            ($name:expr, $value:expr, $kind:ty) => (
208                assert_eq!(options.get_ref::<$kind>($name).unwrap(), $value)
209            );
210        );
211
212        test!("a", &42, i32);
213        test!("b", &true, bool);
214        test!("c", &"Hi, there!", &str);
215        test!("d", "Hello, world!", String);
216        test!("e", &vec![4u8, 2u8], Vec<u8>);
217    }
218
219    #[test]
220    fn get_mut() {
221        let mut options = setup();
222
223        macro_rules! test(
224            ($name:expr, $value:expr, $kind:ty) => ({
225                *options.get_mut::<$kind>($name).unwrap() = $value;
226                assert_eq!(options.get::<$kind>($name).unwrap(), $value);
227            });
228        );
229
230        test!("a", 24, i32);
231        test!("b", false, bool);
232        test!("c", "Hi, here!", &str);
233        test!("d", "Bye, world!".to_string(), String);
234        test!("e", vec![2u8, 4u8], Vec<u8>);
235    }
236
237    #[test]
238    fn iter_mut() {
239        let mut options = setup();
240        for (_, value) in &mut options {
241            value.set(69);
242        }
243
244        macro_rules! test(
245            ($name:expr) => (assert_eq!(options.get_ref::<i32>($name).unwrap(), &69));
246        );
247
248        test!("a");
249        test!("b");
250        test!("c");
251        test!("d");
252        test!("e");
253    }
254
255    #[test]
256    fn has() {
257        let options = setup();
258        assert_eq!(options.has("a"), true);
259        assert_eq!(options.has("z"), false);
260    }
261
262    #[test]
263    fn names() {
264        let options = setup();
265        let mut names = options.names().collect::<Vec<_>>();
266        names.sort();
267        assert_eq!(names, &["a", "b", "c", "d", "e"]);
268    }
269
270    fn setup() -> Options {
271        let mut options = Options::default();
272
273        options
274            .set("a", 42)
275            .set("b", true)
276            .set("c", "Hi, there!")
277            .set("d", "Hello, world!".to_string())
278            .set("e", vec![4u8, 2u8]);
279
280        options
281    }
282}