1use core::any::Any;
2use core::borrow::Borrow;
3
4use crate::Error;
5
6pub const NO_VALUES: &dyn Values = &();
8
9#[inline]
11pub fn get_value<T: Any>(values: &dyn Values, key: impl AsRef<str>) -> Result<&T, Error> {
12 values
13 .get_value(key.as_ref())
14 .ok_or(Error::ValueMissing)
15 .and_then(convert_value)
16}
17
18fn convert_value<T: Any>(src: &dyn Any) -> Result<&T, Error> {
19 if let Some(value) = src.downcast_ref::<T>() {
20 return Ok(value);
21 } else if let Some(value) = src.downcast_ref::<&T>() {
22 return Ok(value);
23 }
24
25 #[cfg(feature = "alloc")]
26 if let Some(value) = src.downcast_ref::<alloc::boxed::Box<T>>() {
27 return Ok(value);
28 } else if let Some(value) = src.downcast_ref::<alloc::rc::Rc<T>>() {
29 return Ok(value);
30 } else if let Some(value) = src.downcast_ref::<alloc::sync::Arc<T>>() {
31 return Ok(value);
32 }
33
34 Err(Error::ValueType)
35}
36
37pub trait Values {
39 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any>;
41}
42
43crate::impl_for_ref! {
44 impl Values for T {
45 #[inline]
46 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
47 T::get_value(self, key)
48 }
49 }
50}
51
52impl Values for () {
53 #[inline]
54 fn get_value<'a>(&'a self, _: &str) -> Option<&'a dyn Any> {
55 None
56 }
57}
58
59impl<K, V> Values for (K, V)
60where
61 K: Borrow<str>,
62 V: Value,
63{
64 #[inline]
65 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
66 if self.0.borrow() == key {
67 self.1.ref_any()
68 } else {
69 None
70 }
71 }
72}
73
74impl<T: Values> Values for Option<T> {
75 #[inline]
76 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
77 self.as_ref()?.get_value(key)
78 }
79}
80
81impl<K, V, const N: usize> Values for [(K, V); N]
82where
83 K: Borrow<str>,
84 V: Value,
85{
86 #[inline]
87 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
88 find_value_linear(self.iter(), key)
89 }
90}
91
92impl<K, V> Values for [(K, V)]
93where
94 K: Borrow<str>,
95 V: Value,
96{
97 #[inline]
98 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
99 find_value_linear(self.iter(), key)
100 }
101}
102
103#[cfg(feature = "alloc")]
104impl<K, V> Values for alloc::vec::Vec<(K, V)>
105where
106 K: Borrow<str>,
107 V: Value,
108{
109 #[inline]
110 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
111 find_value_linear(self.iter(), key)
112 }
113}
114
115#[cfg(feature = "alloc")]
116impl<K, V> Values for alloc::collections::VecDeque<(K, V)>
117where
118 K: Borrow<str>,
119 V: Value,
120{
121 #[inline]
122 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
123 find_value_linear(self.iter(), key)
124 }
125}
126
127#[cfg(feature = "alloc")]
128impl<K, V> Values for alloc::collections::LinkedList<(K, V)>
129where
130 K: Borrow<str>,
131 V: Value,
132{
133 #[inline]
134 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
135 find_value_linear(self.iter(), key)
136 }
137}
138
139fn find_value_linear<'a, K, V, I>(it: I, key: &str) -> Option<&'a dyn Any>
140where
141 K: Borrow<str> + 'a,
142 V: Value + 'a,
143 I: Iterator<Item = &'a (K, V)>,
144{
145 for (k, v) in it {
146 if k.borrow() == key {
147 return v.ref_any();
148 }
149 }
150 None
151}
152
153#[cfg(feature = "alloc")]
154impl<K, V> Values for alloc::collections::BTreeMap<K, V>
155where
156 K: Borrow<str> + core::cmp::Ord,
157 V: Value,
158{
159 #[inline]
160 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
161 self.get(key)?.ref_any()
162 }
163}
164
165#[cfg(feature = "std")]
166impl<K, V, S> Values for std::collections::HashMap<K, V, S>
167where
168 K: Borrow<str> + Eq + core::hash::Hash,
169 V: Value,
170 S: core::hash::BuildHasher,
171{
172 #[inline]
173 fn get_value<'a>(&'a self, key: &str) -> Option<&'a dyn Any> {
174 self.get(key)?.ref_any()
175 }
176}
177
178pub trait Value {
183 fn ref_any(&self) -> Option<&dyn Any>;
185}
186
187crate::impl_for_ref! {
188 impl Value for T {
189 #[inline]
190 fn ref_any(&self) -> Option<&dyn Any> {
191 T::ref_any(self)
192 }
193 }
194}
195
196impl Value for dyn Any {
197 #[inline]
198 fn ref_any(&self) -> Option<&dyn Any> {
199 Some(self)
200 }
201}
202
203impl<T: Value> Value for Option<T> {
204 #[inline]
205 fn ref_any(&self) -> Option<&dyn Any> {
206 T::ref_any(self.as_ref()?)
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use assert_matches::assert_matches;
213
214 use super::*;
215
216 #[track_caller]
217 fn assert_a_10_c_blam(values: &dyn Values) {
218 assert_matches!(get_value::<u32>(values, "a"), Ok(10u32));
219 assert_matches!(get_value::<&str>(values, "c"), Ok(&"blam"));
220 assert_matches!(get_value::<u8>(values, "a"), Err(Error::ValueType));
221 assert_matches!(get_value::<u8>(values, "d"), Err(Error::ValueMissing));
222 }
223
224 #[track_caller]
225 fn assert_a_12_c_blam(values: &dyn Values) {
226 assert_matches!(get_value::<u32>(values, "a"), Ok(12u32));
227 assert_matches!(get_value::<&str>(values, "c"), Ok(&"blam"));
228 assert_matches!(get_value::<u8>(values, "a"), Err(Error::ValueType));
229 assert_matches!(get_value::<u8>(values, "d"), Err(Error::ValueMissing));
230 }
231
232 #[cfg(feature = "std")]
233 #[test]
234 fn values_on_hashmap() {
235 use alloc::boxed::Box;
236 use alloc::string::String;
237 use std::collections::HashMap;
238
239 let mut values: HashMap<String, Box<dyn Any>> = HashMap::new();
240 values.insert("a".into(), Box::new(12u32));
241 values.insert("c".into(), Box::new("blam"));
242 assert_a_12_c_blam(&values);
243
244 let mut values: HashMap<&str, Box<dyn Any>> = HashMap::new();
245 values.insert("a", Box::new(10u32));
246 assert_matches!(get_value::<u32>(&values, "a"), Ok(&10u32));
247 }
248
249 #[cfg(feature = "alloc")]
250 #[test]
251 fn values_on_btreemap() {
252 use alloc::boxed::Box;
253 use alloc::collections::BTreeMap;
254 use alloc::string::String;
255
256 let mut values: BTreeMap<String, Box<dyn Any>> = BTreeMap::new();
257 values.insert("a".into(), Box::new(12u32));
258 values.insert("c".into(), Box::new("blam"));
259 assert_a_12_c_blam(&values);
260
261 let mut values: BTreeMap<&str, Box<dyn Any>> = BTreeMap::new();
262 values.insert("a", Box::new(10u32));
263 assert_matches!(get_value::<u32>(&values, "a"), Ok(&10u32));
264 }
265
266 #[test]
267 fn values_on_slice() {
268 let slice: &[(&str, &dyn Any)] = &[("a", &12u32), ("c", &"blam")];
269 assert_a_12_c_blam(&slice);
270 }
271
272 #[cfg(feature = "alloc")]
273 #[test]
274 fn values_vec() {
275 let vec: alloc::vec::Vec<(&str, &dyn Any)> = alloc::vec![("a", &12u32), ("c", &"blam")];
276 assert_a_12_c_blam(&vec);
277 }
278
279 #[cfg(feature = "alloc")]
280 #[test]
281 fn values_deque() {
282 let mut deque = alloc::collections::VecDeque::<(&str, &dyn Any)>::new();
283 deque.push_back(("a", &12u32));
284 deque.push_back(("c", &"blam"));
285 assert_a_12_c_blam(&deque);
286 deque.pop_front();
287 deque.push_back(("a", &10u32));
288 assert_a_10_c_blam(&deque);
289 }
290
291 #[cfg(feature = "alloc")]
292 #[test]
293 fn values_list() {
294 let mut list = alloc::collections::LinkedList::<(&str, &dyn Any)>::new();
295 list.push_back(("a", &12u32));
296 list.push_back(("c", &"blam"));
297 assert_a_12_c_blam(&list);
298 list.pop_front();
299 list.push_back(("a", &10u32));
300 assert_a_10_c_blam(&list);
301 }
302
303 #[test]
304 fn values_on_tuple() {
305 let tuple: (&str, &dyn Any) = ("a", &10u32);
306
307 assert_matches!(get_value::<u32>(&tuple, "a"), Ok(10u32));
308 assert_matches!(get_value::<i32>(&tuple, "a"), Err(Error::ValueType));
309 assert_matches!(get_value::<i32>(&tuple, "b"), Err(Error::ValueMissing));
310 }
311}