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