gtmpl_value/
from.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3
4use crate::value::{Func, Function, Value};
5
6macro_rules! from_num {
7    ($($ty:ident)*) => {
8        $(
9            impl From<$ty> for Value {
10                fn from(n: $ty) -> Self {
11                    Value::Number(n.into())
12                }
13            }
14        )*
15    };
16}
17
18from_num! {
19    i8 i16 i32 i64 isize
20    u8 u16 u32 u64 usize
21    f32 f64
22}
23
24impl From<bool> for Value {
25    /// Convert boolean to `Value`
26    ///
27    /// # Examples
28    ///
29    /// ```rust
30    /// use gtmpl_value::Value;
31    ///
32    /// let b = false;
33    /// let x: Value = b.into();
34    /// ```
35    fn from(b: bool) -> Self {
36        Value::Bool(b)
37    }
38}
39
40impl<'a> From<&'a String> for Value {
41    /// Convert &String to `Value`
42    ///
43    /// # Examples
44    ///
45    /// ```rust
46    /// use gtmpl_value::Value;
47    ///
48    /// let s: &String = &"foobar".to_owned();
49    /// let x: Value = s.into();
50    /// ```
51    fn from(s: &'a String) -> Self {
52        Value::String(s.clone())
53    }
54}
55
56impl From<String> for Value {
57    /// Convert String to `Value`
58    ///
59    /// # Examples
60    ///
61    /// ```rust
62    /// use gtmpl_value::Value;
63    ///
64    /// let s: String = "foobar".to_owned();
65    /// let x: Value = s.into();
66    /// ```
67    fn from(s: String) -> Self {
68        Value::String(s)
69    }
70}
71
72impl<'a> From<&'a str> for Value {
73    /// Convert &str to `Value`
74    ///
75    /// # Examples
76    ///
77    /// ```rust
78    /// use gtmpl_value::Value;
79    ///
80    /// let s = "foobar";
81    /// let x: Value = s.into();
82    /// ```
83    fn from(f: &str) -> Self {
84        Value::String(f.to_string())
85    }
86}
87
88impl<'a> From<Cow<'a, str>> for Value {
89    /// Convert Cow<str> to `Value`
90    ///
91    /// # Examples
92    ///
93    /// ```rust
94    /// use gtmpl_value::Value;
95    /// use std::borrow::Cow;
96    ///
97    /// let s: Cow<str> = Cow::Borrowed("foobar");
98    /// let x: Value = s.into();
99    /// ```
100    fn from(f: Cow<'a, str>) -> Self {
101        Value::String(f.to_string())
102    }
103}
104
105impl From<Func> for Value {
106    /// Convert Func to `Value`
107    ///
108    /// # Examples
109    ///
110    /// ```rust
111    /// use gtmpl_value::{Func, FuncError, Value};
112    ///
113    /// fn f(a: &[Value]) -> Result<Value, FuncError> {
114    ///     Ok(a[0].clone())
115    /// };
116    /// let x: Value = (f as Func).into();
117    /// ```
118    fn from(f: Func) -> Self {
119        Value::Function(Function { f })
120    }
121}
122
123impl<T> From<Vec<T>> for Value
124where
125    T: Into<Value> + Clone,
126{
127    /// Convert Vec to `Value`
128    ///
129    /// # Examples
130    ///
131    /// ```rust
132    /// use gtmpl_value::Value;
133    ///
134    /// let v = vec!(1, 2, 3);
135    /// let x: Value = v.into();
136    /// ```
137    fn from(f: Vec<T>) -> Self {
138        Value::Array(f.iter().cloned().map(|x| x.into()).collect())
139    }
140}
141
142impl<'a, T> From<&'a [T]> for Value
143where
144    T: Into<Value> + Clone,
145{
146    /// Convert Slice to `Value`
147    ///
148    /// # Examples
149    ///
150    /// ```rust
151    /// use gtmpl_value::Value;
152    ///
153    /// let v: &[i32] = &[1, 2, 3];
154    /// let x: Value = v.into();
155    /// ```
156    fn from(f: &'a [T]) -> Self {
157        Value::Array(f.iter().cloned().map(|x| x.into()).collect())
158    }
159}
160
161impl<T> From<HashMap<String, T>> for Value
162where
163    T: Into<Value> + Clone,
164{
165    /// Convert HashMap<String, T> to `Value`
166    ///
167    /// # Examples
168    ///
169    /// ```rust
170    /// use gtmpl_value::Value;
171    /// use std::collections::HashMap;
172    ///
173    /// let mut m = HashMap::new();
174    /// m.insert("hello".to_owned(), 123);
175    /// let x: Value = m.into();
176    /// ```
177    fn from(f: HashMap<String, T>) -> Self {
178        Value::Map(
179            f.iter()
180                .map(|(s, x)| (s.clone(), x.clone().into()))
181                .collect(),
182        )
183    }
184}
185
186impl<T> From<Option<T>> for Value
187where
188    T: Into<Value> + Clone,
189{
190    /// Convert Option<T> to `Value`
191    ///
192    /// # Examples
193    ///
194    /// ```rust
195    /// use gtmpl_value::Value;
196    ///
197    /// let i = Some(1);
198    /// let x: Value = i.into();
199    /// ```
200    fn from(f: Option<T>) -> Self {
201        match f {
202            Some(x) => x.into(),
203            _ => Value::NoValue,
204        }
205    }
206}
207
208/// Convert Value into something.
209pub trait FromValue<T> {
210    /// Tries to retrieve `T` from `Value.`
211    fn from_value(val: &Value) -> Option<T>;
212}
213
214impl FromValue<i64> for i64 {
215    /// Tries to retrieve `i64` from `Value.`
216    ///
217    /// # Examples:
218    ///
219    /// ```rust
220    /// use gtmpl_value::{FromValue, Value};
221    ///
222    /// let v: Value = 23i64.into();
223    /// let i = i64::from_value(&v);
224    /// assert_eq!(i, Some(23i64));
225    /// ```
226    fn from_value(val: &Value) -> Option<i64> {
227        if let Value::Number(ref n) = *val {
228            n.as_i64()
229        } else {
230            None
231        }
232    }
233}
234
235impl FromValue<u64> for u64 {
236    /// Tries to retrieve `u64` from `Value.`
237    ///
238    /// # Examples:
239    ///
240    /// ```rust
241    /// use gtmpl_value::{FromValue, Value};
242    ///
243    /// let v: Value = 23u64.into();
244    /// let i = u64::from_value(&v);
245    /// assert_eq!(i, Some(23u64));
246    /// ```
247    fn from_value(val: &Value) -> Option<u64> {
248        if let Value::Number(ref n) = *val {
249            n.as_u64()
250        } else {
251            None
252        }
253    }
254}
255
256impl FromValue<f64> for f64 {
257    /// Tries to retrieve `f64` from `Value.`
258    ///
259    /// # Examples:
260    ///
261    /// ```rust
262    /// use gtmpl_value::{FromValue, Value};
263    ///
264    /// let v: Value = 23.1f64.into();
265    /// let i = f64::from_value(&v);
266    /// assert_eq!(i, Some(23.1f64));
267    /// ```
268    fn from_value(val: &Value) -> Option<f64> {
269        if let Value::Number(ref n) = *val {
270            n.as_f64()
271        } else {
272            None
273        }
274    }
275}
276
277impl FromValue<String> for String {
278    /// Tries to retrieve `String` from `Value.`
279    ///
280    /// # Examples:
281    ///
282    /// ```rust
283    /// use gtmpl_value::{FromValue, Value};
284    ///
285    /// let v: Value = "foobar".into();
286    /// let s = String::from_value(&v);
287    /// assert_eq!(s, Some("foobar".to_owned()));
288    /// ```
289    fn from_value(val: &Value) -> Option<String> {
290        if let Value::String(ref s) = *val {
291            Some(s.clone())
292        } else {
293            None
294        }
295    }
296}
297
298impl<T> FromValue<Vec<T>> for Vec<T>
299where
300    T: FromValue<T>,
301{
302    /// Tries to retrieve `Vec<T>` from `Value.`
303    ///
304    /// # Examples:
305    ///
306    /// ```rust
307    /// use gtmpl_value::{FromValue, Value};
308    ///
309    /// let v: Value = vec!(1, 2, 3).into();
310    /// let v: Option<Vec<i64>> = Vec::from_value(&v);
311    /// assert_eq!(v, Some(vec!(1, 2, 3)));
312    /// ```
313    fn from_value(val: &Value) -> Option<Vec<T>> {
314        if let Value::Array(ref a) = *val {
315            let v: Vec<T> = a.iter().flat_map(|v| T::from_value(v)).collect();
316            if v.len() == a.len() {
317                return Some(v);
318            }
319        }
320        None
321    }
322}
323
324#[allow(clippy::implicit_hasher)]
325impl<T> FromValue<HashMap<String, T>> for HashMap<String, T>
326where
327    T: FromValue<T>,
328{
329    /// Tries to retrieve `HashMap<String, T>` from `Value.`
330    ///
331    /// # Examples:
332    ///
333    /// ```rust
334    /// use gtmpl_value::{FromValue, Value};
335    /// use std::collections::HashMap;
336    ///
337    /// let mut m = HashMap::new();
338    /// m.insert("a".to_owned(), 1);
339    /// let v: Value = m.into();
340    /// let m: Option<HashMap<String, i64>> = HashMap::from_value(&v);
341    /// assert!(m.is_some());
342    /// if let Some(m) = m {
343    ///   assert_eq!(m.get("a"), Some(&1));
344    /// }
345    /// ```
346    fn from_value(val: &Value) -> Option<HashMap<String, T>> {
347        match *val {
348            Value::Object(ref o) | Value::Map(ref o) => {
349                let m: HashMap<String, T> = o
350                    .iter()
351                    .map(|(s, v)| (s.clone(), T::from_value(v)))
352                    .flat_map(|(s, t)| t.map(|t| (s, t)))
353                    .collect();
354                if m.len() == o.len() {
355                    Some(m)
356                } else {
357                    None
358                }
359            }
360            _ => None,
361        }
362    }
363}
364
365/// `FromValue` wrapped in a macro (required for `gtmpl_fn!` macro).
366///
367/// # Examples:
368///
369/// ```rust
370/// use gtmpl_value::{from_value, Value};
371///
372/// let v: Value = 1.into();
373/// let s: Option<i64> = from_value(&v);
374/// assert_eq!(s, Some(1));
375/// ```
376pub fn from_value<T>(val: &Value) -> Option<T>
377where
378    T: FromValue<T>,
379{
380    T::from_value(val)
381}
382
383#[cfg(test)]
384mod test {
385    use super::*;
386
387    #[test]
388    fn test_vec() {
389        let val: Value = vec![1, 2, 3].into();
390        if let Value::Array(array) = val {
391            assert_eq!(array[0], 1.into());
392            assert_eq!(array[1], 2.into());
393            assert_eq!(array[2], 3.into());
394        } else {
395            panic!();
396        }
397
398        let val: Value = vec!["foo", "bar"].into();
399        if let Value::Array(array) = val {
400            assert_eq!(array[0], "foo".into());
401            assert_eq!(array[1], "bar".into());
402        } else {
403            panic!();
404        }
405    }
406
407    #[test]
408    fn test_slice() {
409        let slice: &[u8] = &[1, 2, 3];
410        let val: Value = slice.into();
411        if let Value::Array(array) = val {
412            assert_eq!(array[0], 1.into());
413            assert_eq!(array[1], 2.into());
414            assert_eq!(array[2], 3.into());
415        } else {
416            panic!();
417        }
418    }
419
420    #[test]
421    fn test_map() {
422        let mut m = HashMap::new();
423        m.insert("a".to_owned(), 1);
424        m.insert("b".to_owned(), 2);
425        let val: Value = m.into();
426        if let Value::Map(obj) = val {
427            assert_eq!(obj.get("a"), Some(&(1.into())));
428            assert_eq!(obj.get("b"), Some(&(2.into())));
429        } else {
430            panic!();
431        }
432    }
433}