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}