1 //! Coerce a `Value` into some concrete types.
2 //!
3 //! These operations are cheap when the captured value is a simple primitive,
4 //! but may end up executing arbitrary caller code if the value is complex.
5 //! They will also attempt to downcast erased types into a primitive where possible.
6 
7 use std::any::TypeId;
8 use std::fmt;
9 
10 use super::{Erased, Inner, Primitive, Visitor};
11 use crate::kv::value::{Error, Value};
12 
13 impl<'v> Value<'v> {
14     /// Try get a `usize` from this value.
15     ///
16     /// This method is cheap for primitive types, but may call arbitrary
17     /// serialization implementations for complex ones.
to_usize(&self) -> Option<usize>18     pub fn to_usize(&self) -> Option<usize> {
19         self.inner
20             .cast()
21             .into_primitive()
22             .into_u64()
23             .map(|v| v as usize)
24     }
25 
26     /// Try get a `u8` from this value.
27     ///
28     /// This method is cheap for primitive types, but may call arbitrary
29     /// serialization implementations for complex ones.
to_u8(&self) -> Option<u8>30     pub fn to_u8(&self) -> Option<u8> {
31         self.inner
32             .cast()
33             .into_primitive()
34             .into_u64()
35             .map(|v| v as u8)
36     }
37 
38     /// Try get a `u16` from this value.
39     ///
40     /// This method is cheap for primitive types, but may call arbitrary
41     /// serialization implementations for complex ones.
to_u16(&self) -> Option<u16>42     pub fn to_u16(&self) -> Option<u16> {
43         self.inner
44             .cast()
45             .into_primitive()
46             .into_u64()
47             .map(|v| v as u16)
48     }
49 
50     /// Try get a `u32` from this value.
51     ///
52     /// This method is cheap for primitive types, but may call arbitrary
53     /// serialization implementations for complex ones.
to_u32(&self) -> Option<u32>54     pub fn to_u32(&self) -> Option<u32> {
55         self.inner
56             .cast()
57             .into_primitive()
58             .into_u64()
59             .map(|v| v as u32)
60     }
61 
62     /// Try get a `u64` from this value.
63     ///
64     /// This method is cheap for primitive types, but may call arbitrary
65     /// serialization implementations for complex ones.
to_u64(&self) -> Option<u64>66     pub fn to_u64(&self) -> Option<u64> {
67         self.inner.cast().into_primitive().into_u64()
68     }
69 
70     /// Try get a `isize` from this value.
71     ///
72     /// This method is cheap for primitive types, but may call arbitrary
73     /// serialization implementations for complex ones.
to_isize(&self) -> Option<isize>74     pub fn to_isize(&self) -> Option<isize> {
75         self.inner
76             .cast()
77             .into_primitive()
78             .into_i64()
79             .map(|v| v as isize)
80     }
81 
82     /// Try get a `i8` from this value.
83     ///
84     /// This method is cheap for primitive types, but may call arbitrary
85     /// serialization implementations for complex ones.
to_i8(&self) -> Option<i8>86     pub fn to_i8(&self) -> Option<i8> {
87         self.inner
88             .cast()
89             .into_primitive()
90             .into_i64()
91             .map(|v| v as i8)
92     }
93 
94     /// Try get a `i16` from this value.
95     ///
96     /// This method is cheap for primitive types, but may call arbitrary
97     /// serialization implementations for complex ones.
to_i16(&self) -> Option<i16>98     pub fn to_i16(&self) -> Option<i16> {
99         self.inner
100             .cast()
101             .into_primitive()
102             .into_i64()
103             .map(|v| v as i16)
104     }
105 
106     /// Try get a `i32` from this value.
107     ///
108     /// This method is cheap for primitive types, but may call arbitrary
109     /// serialization implementations for complex ones.
to_i32(&self) -> Option<i32>110     pub fn to_i32(&self) -> Option<i32> {
111         self.inner
112             .cast()
113             .into_primitive()
114             .into_i64()
115             .map(|v| v as i32)
116     }
117 
118     /// Try get a `i64` from this value.
119     ///
120     /// This method is cheap for primitive types, but may call arbitrary
121     /// serialization implementations for complex ones.
to_i64(&self) -> Option<i64>122     pub fn to_i64(&self) -> Option<i64> {
123         self.inner.cast().into_primitive().into_i64()
124     }
125 
126     /// Try get a `f32` from this value.
127     ///
128     /// This method is cheap for primitive types, but may call arbitrary
129     /// serialization implementations for complex ones.
to_f32(&self) -> Option<f32>130     pub fn to_f32(&self) -> Option<f32> {
131         self.inner
132             .cast()
133             .into_primitive()
134             .into_f64()
135             .map(|v| v as f32)
136     }
137 
138     /// Try get a `f64` from this value.
139     ///
140     /// This method is cheap for primitive types, but may call arbitrary
141     /// serialization implementations for complex ones.
to_f64(&self) -> Option<f64>142     pub fn to_f64(&self) -> Option<f64> {
143         self.inner.cast().into_primitive().into_f64()
144     }
145 
146     /// Try get a `bool` from this value.
147     ///
148     /// This method is cheap for primitive types, but may call arbitrary
149     /// serialization implementations for complex ones.
to_bool(&self) -> Option<bool>150     pub fn to_bool(&self) -> Option<bool> {
151         self.inner.cast().into_primitive().into_bool()
152     }
153 
154     /// Try get a `char` from this value.
155     ///
156     /// This method is cheap for primitive types, but may call arbitrary
157     /// serialization implementations for complex ones.
to_char(&self) -> Option<char>158     pub fn to_char(&self) -> Option<char> {
159         self.inner.cast().into_primitive().into_char()
160     }
161 
162     /// Try get a `str` from this value.
163     ///
164     /// This method is cheap for primitive types. It won't allocate an owned
165     /// `String` if the value is a complex type.
to_borrowed_str(&self) -> Option<&str>166     pub fn to_borrowed_str(&self) -> Option<&str> {
167         self.inner.cast().into_primitive().into_borrowed_str()
168     }
169 }
170 
171 impl<'v> Inner<'v> {
172     /// Cast the inner value to another type.
cast(self) -> Cast<'v>173     fn cast(self) -> Cast<'v> {
174         struct CastVisitor<'v>(Cast<'v>);
175 
176         impl<'v> Visitor<'v> for CastVisitor<'v> {
177             fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> {
178                 Ok(())
179             }
180 
181             fn u64(&mut self, v: u64) -> Result<(), Error> {
182                 self.0 = Cast::Primitive(Primitive::Unsigned(v));
183                 Ok(())
184             }
185 
186             fn i64(&mut self, v: i64) -> Result<(), Error> {
187                 self.0 = Cast::Primitive(Primitive::Signed(v));
188                 Ok(())
189             }
190 
191             fn f64(&mut self, v: f64) -> Result<(), Error> {
192                 self.0 = Cast::Primitive(Primitive::Float(v));
193                 Ok(())
194             }
195 
196             fn bool(&mut self, v: bool) -> Result<(), Error> {
197                 self.0 = Cast::Primitive(Primitive::Bool(v));
198                 Ok(())
199             }
200 
201             fn char(&mut self, v: char) -> Result<(), Error> {
202                 self.0 = Cast::Primitive(Primitive::Char(v));
203                 Ok(())
204             }
205 
206             fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
207                 self.0 = Cast::Primitive(Primitive::Str(v));
208                 Ok(())
209             }
210 
211             #[cfg(not(feature = "std"))]
212             fn str(&mut self, _: &str) -> Result<(), Error> {
213                 Ok(())
214             }
215 
216             #[cfg(feature = "std")]
217             fn str(&mut self, v: &str) -> Result<(), Error> {
218                 self.0 = Cast::String(v.into());
219                 Ok(())
220             }
221 
222             fn none(&mut self) -> Result<(), Error> {
223                 self.0 = Cast::Primitive(Primitive::None);
224                 Ok(())
225             }
226 
227             #[cfg(feature = "kv_unstable_sval")]
228             fn sval(&mut self, v: &dyn super::sval::Value) -> Result<(), Error> {
229                 self.0 = super::sval::cast(v);
230                 Ok(())
231             }
232         }
233 
234         // Try downcast an erased value first
235         // It also lets us avoid the Visitor infrastructure for simple primitives
236         let primitive = match self {
237             Inner::Primitive(value) => Some(value),
238             Inner::Fill(value) => value.downcast_primitive(),
239             Inner::Debug(value) => value.downcast_primitive(),
240             Inner::Display(value) => value.downcast_primitive(),
241 
242             #[cfg(feature = "sval")]
243             Inner::Sval(value) => value.downcast_primitive(),
244         };
245 
246         primitive.map(Cast::Primitive).unwrap_or_else(|| {
247             // If the erased value isn't a primitive then we visit it
248             let mut cast = CastVisitor(Cast::Primitive(Primitive::None));
249             let _ = self.visit(&mut cast);
250             cast.0
251         })
252     }
253 }
254 
255 pub(super) enum Cast<'v> {
256     Primitive(Primitive<'v>),
257     #[cfg(feature = "std")]
258     String(String),
259 }
260 
261 impl<'v> Cast<'v> {
into_primitive(self) -> Primitive<'v>262     fn into_primitive(self) -> Primitive<'v> {
263         match self {
264             Cast::Primitive(value) => value,
265             #[cfg(feature = "std")]
266             _ => Primitive::None,
267         }
268     }
269 }
270 
271 impl<'v> Primitive<'v> {
into_borrowed_str(self) -> Option<&'v str>272     fn into_borrowed_str(self) -> Option<&'v str> {
273         if let Primitive::Str(value) = self {
274             Some(value)
275         } else {
276             None
277         }
278     }
279 
into_u64(self) -> Option<u64>280     fn into_u64(self) -> Option<u64> {
281         match self {
282             Primitive::Unsigned(value) => Some(value),
283             Primitive::Signed(value) => Some(value as u64),
284             Primitive::Float(value) => Some(value as u64),
285             _ => None,
286         }
287     }
288 
into_i64(self) -> Option<i64>289     fn into_i64(self) -> Option<i64> {
290         match self {
291             Primitive::Signed(value) => Some(value),
292             Primitive::Unsigned(value) => Some(value as i64),
293             Primitive::Float(value) => Some(value as i64),
294             _ => None,
295         }
296     }
297 
into_f64(self) -> Option<f64>298     fn into_f64(self) -> Option<f64> {
299         match self {
300             Primitive::Float(value) => Some(value),
301             Primitive::Unsigned(value) => Some(value as f64),
302             Primitive::Signed(value) => Some(value as f64),
303             _ => None,
304         }
305     }
306 
into_char(self) -> Option<char>307     fn into_char(self) -> Option<char> {
308         if let Primitive::Char(value) = self {
309             Some(value)
310         } else {
311             None
312         }
313     }
314 
into_bool(self) -> Option<bool>315     fn into_bool(self) -> Option<bool> {
316         if let Primitive::Bool(value) = self {
317             Some(value)
318         } else {
319             None
320         }
321     }
322 }
323 
324 impl<'v, T: ?Sized + 'static> Erased<'v, T> {
325     // NOTE: This function is a perfect candidate for memoization
326     // The outcome could be stored in a `Cell<Primitive>`
downcast_primitive(self) -> Option<Primitive<'v>>327     fn downcast_primitive(self) -> Option<Primitive<'v>> {
328         macro_rules! type_ids {
329             ($($value:ident : $ty:ty => $cast:expr,)*) => {{
330                 struct TypeIds;
331 
332                 impl TypeIds {
333                     fn downcast_primitive<'v, T: ?Sized>(&self, value: Erased<'v, T>) -> Option<Primitive<'v>> {
334                         $(
335                             if TypeId::of::<$ty>() == value.type_id {
336                                 let $value = unsafe { value.downcast_unchecked::<$ty>() };
337                                 return Some(Primitive::from($cast));
338                             }
339                         )*
340 
341                         None
342                     }
343                 }
344 
345                 TypeIds
346             }};
347         }
348 
349         let type_ids = type_ids![
350             value: usize => *value as u64,
351             value: u8 => *value as u64,
352             value: u16 => *value as u64,
353             value: u32 => *value as u64,
354             value: u64 => *value,
355 
356             value: isize => *value as i64,
357             value: i8 => *value as i64,
358             value: i16 => *value as i64,
359             value: i32 => *value as i64,
360             value: i64 => *value,
361 
362             value: f32 => *value as f64,
363             value: f64 => *value,
364 
365             value: char => *value,
366             value: bool => *value,
367 
368             value: &str => *value,
369         ];
370 
371         type_ids.downcast_primitive(self)
372     }
373 }
374 
375 #[cfg(feature = "std")]
376 mod std_support {
377     use super::*;
378 
379     use std::borrow::Cow;
380 
381     impl<'v> Value<'v> {
382         /// Try get a `usize` from this value.
383         ///
384         /// This method is cheap for primitive types, but may call arbitrary
385         /// serialization implementations for complex ones. If the serialization
386         /// implementation produces a short lived string it will be allocated.
to_str(&self) -> Option<Cow<str>>387         pub fn to_str(&self) -> Option<Cow<str>> {
388             self.inner.cast().into_str()
389         }
390     }
391 
392     impl<'v> Cast<'v> {
into_str(self) -> Option<Cow<'v, str>>393         pub(super) fn into_str(self) -> Option<Cow<'v, str>> {
394             match self {
395                 Cast::Primitive(Primitive::Str(value)) => Some(value.into()),
396                 Cast::String(value) => Some(value.into()),
397                 _ => None,
398             }
399         }
400     }
401 
402     #[cfg(test)]
403     mod tests {
404         use crate::kv::ToValue;
405 
406         #[test]
primitive_cast()407         fn primitive_cast() {
408             assert_eq!(
409                 "a string",
410                 "a string"
411                     .to_owned()
412                     .to_value()
413                     .to_borrowed_str()
414                     .expect("invalid value")
415             );
416             assert_eq!(
417                 "a string",
418                 &*"a string".to_value().to_str().expect("invalid value")
419             );
420             assert_eq!(
421                 "a string",
422                 &*"a string"
423                     .to_owned()
424                     .to_value()
425                     .to_str()
426                     .expect("invalid value")
427             );
428         }
429     }
430 }
431 
432 #[cfg(test)]
433 mod tests {
434     use crate::kv::ToValue;
435 
436     #[test]
primitive_cast()437     fn primitive_cast() {
438         assert_eq!(
439             "a string",
440             "a string"
441                 .to_value()
442                 .to_borrowed_str()
443                 .expect("invalid value")
444         );
445         assert_eq!(
446             "a string",
447             Some("a string")
448                 .to_value()
449                 .to_borrowed_str()
450                 .expect("invalid value")
451         );
452 
453         assert_eq!(1u8, 1u64.to_value().to_u8().expect("invalid value"));
454         assert_eq!(1u16, 1u64.to_value().to_u16().expect("invalid value"));
455         assert_eq!(1u32, 1u64.to_value().to_u32().expect("invalid value"));
456         assert_eq!(1u64, 1u64.to_value().to_u64().expect("invalid value"));
457         assert_eq!(1usize, 1u64.to_value().to_usize().expect("invalid value"));
458 
459         assert_eq!(-1i8, -1i64.to_value().to_i8().expect("invalid value"));
460         assert_eq!(-1i16, -1i64.to_value().to_i16().expect("invalid value"));
461         assert_eq!(-1i32, -1i64.to_value().to_i32().expect("invalid value"));
462         assert_eq!(-1i64, -1i64.to_value().to_i64().expect("invalid value"));
463         assert_eq!(-1isize, -1i64.to_value().to_isize().expect("invalid value"));
464 
465         assert!(1f32.to_value().to_f32().is_some(), "invalid value");
466         assert!(1f64.to_value().to_f64().is_some(), "invalid value");
467 
468         assert_eq!(1u32, 1i64.to_value().to_u32().expect("invalid value"));
469         assert_eq!(1i32, 1u64.to_value().to_i32().expect("invalid value"));
470         assert!(1f32.to_value().to_i32().is_some(), "invalid value");
471 
472         assert_eq!('a', 'a'.to_value().to_char().expect("invalid value"));
473         assert_eq!(true, true.to_value().to_bool().expect("invalid value"));
474     }
475 }
476