1use std::any::Any;
21use std::collections::hash_map::{HashMap, Iter, IterMut};
22
23#[derive(Debug, Default)]
25pub struct Options(HashMap<Name, Value>);
26
27pub type Name = String;
29
30#[derive(Debug)]
32pub struct Value(Box<dyn Any>);
33
34pub struct Parameters<'l> {
36 iterator: Iter<'l, Name, Value>,
37}
38
39pub struct ParametersMut<'l> {
41 iterator: IterMut<'l, Name, Value>,
42}
43
44pub 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 #[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 #[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 #[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 #[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 #[inline]
78 pub fn has(&self, name: &str) -> bool {
79 self.0.contains_key(name)
80 }
81
82 pub fn iter(&self) -> Parameters<'_> {
84 Parameters {
85 iterator: self.0.iter(),
86 }
87 }
88
89 pub fn iter_mut(&mut self) -> ParametersMut<'_> {
91 ParametersMut {
92 iterator: self.0.iter_mut(),
93 }
94 }
95
96 #[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 #[inline]
111 pub fn get<T: Any + Clone>(&self) -> Option<T> {
112 self.0.downcast_ref::<T>().cloned()
113 }
114
115 #[inline]
117 pub fn get_ref<T: Any>(&self) -> Option<&T> {
118 self.0.downcast_ref::<T>()
119 }
120
121 #[inline]
123 pub fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
124 self.0.downcast_mut::<T>()
125 }
126
127 #[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}