minijinja/value/
deserialize.rs

1use std::ops::{Deref, DerefMut};
2
3use serde::de::value::{MapDeserializer, SeqDeserializer};
4use serde::de::{
5    self, Deserialize, DeserializeOwned, DeserializeSeed, Deserializer, EnumAccess,
6    IntoDeserializer, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor,
7};
8use serde::forward_to_deserialize_any;
9
10use crate::value::{ArgType, ObjectRepr, Value, ValueKind, ValueMap, ValueRepr};
11use crate::{Error, ErrorKind};
12
13#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
14impl<'de> Deserialize<'de> for Value {
15    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
16        deserializer.deserialize_any(ValueVisitor)
17    }
18}
19
20struct ValueVisitor;
21
22macro_rules! visit_value_primitive {
23    ($name:ident, $ty:ty) => {
24        fn $name<E: de::Error>(self, v: $ty) -> Result<Value, E> {
25            Ok(Value::from(v))
26        }
27    };
28}
29
30impl<'de> Visitor<'de> for ValueVisitor {
31    type Value = Value;
32
33    fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
34        fmt.write_str("any MiniJinja compatible value")
35    }
36
37    visit_value_primitive!(visit_bool, bool);
38    visit_value_primitive!(visit_i8, i8);
39    visit_value_primitive!(visit_i16, i16);
40    visit_value_primitive!(visit_i32, i32);
41    visit_value_primitive!(visit_i64, i64);
42    visit_value_primitive!(visit_i128, i128);
43    visit_value_primitive!(visit_u16, u16);
44    visit_value_primitive!(visit_u32, u32);
45    visit_value_primitive!(visit_u64, u64);
46    visit_value_primitive!(visit_u128, u128);
47    visit_value_primitive!(visit_f32, f32);
48    visit_value_primitive!(visit_f64, f64);
49    visit_value_primitive!(visit_char, char);
50    visit_value_primitive!(visit_str, &str);
51    visit_value_primitive!(visit_string, String);
52    visit_value_primitive!(visit_bytes, &[u8]);
53    visit_value_primitive!(visit_byte_buf, Vec<u8>);
54
55    fn visit_none<E: de::Error>(self) -> Result<Value, E> {
56        Ok(Value::from(()))
57    }
58
59    fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
60        Deserialize::deserialize(deserializer)
61    }
62
63    fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
64        Ok(Value::from(()))
65    }
66
67    fn visit_newtype_struct<D: Deserializer<'de>>(
68        self,
69        deserializer: D,
70    ) -> Result<Value, D::Error> {
71        Deserialize::deserialize(deserializer)
72    }
73
74    fn visit_seq<A: SeqAccess<'de>>(self, mut visitor: A) -> Result<Value, A::Error> {
75        let mut rv = Vec::<Value>::new();
76        while let Some(e) = ok!(visitor.next_element()) {
77            rv.push(e);
78        }
79        Ok(Value::from(rv))
80    }
81
82    fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
83        let mut rv = ValueMap::default();
84        while let Some((k, v)) = ok!(map.next_entry()) {
85            rv.insert(k, v);
86        }
87        Ok(Value::from_object(rv))
88    }
89}
90
91/// Utility type to deserialize an argument.
92///
93/// This allows you to directly accept a type that implements [`Deserialize`] as an
94/// argument to a filter or test.  The type dereferences into the inner type and
95/// it also lets you move out the inner type.
96///
97/// ```rust
98/// # use minijinja::Environment;
99/// use std::path::PathBuf;
100/// use minijinja::value::ViaDeserialize;
101///
102/// fn dirname(path: ViaDeserialize<PathBuf>) -> String {
103///     match path.parent() {
104///         Some(parent) => parent.display().to_string(),
105///         None => "".to_string()
106///     }
107/// }
108///
109/// # let mut env = Environment::new();
110/// env.add_filter("dirname", dirname);
111/// ```
112#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
113pub struct ViaDeserialize<T: DeserializeOwned>(pub T);
114
115impl<'a, T: DeserializeOwned> ArgType<'a> for ViaDeserialize<T> {
116    type Output = Self;
117
118    fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
119        match value {
120            Some(value) => {
121                if value.is_kwargs() {
122                    return Err(Error::new(
123                        ErrorKind::InvalidOperation,
124                        "cannot deserialize from kwargs",
125                    ));
126                }
127                T::deserialize(value).map(ViaDeserialize)
128            }
129            None => Err(Error::from(ErrorKind::MissingArgument)),
130        }
131    }
132}
133
134impl<T: DeserializeOwned> Deref for ViaDeserialize<T> {
135    type Target = T;
136
137    fn deref(&self) -> &T {
138        &self.0
139    }
140}
141
142impl<T: DeserializeOwned> DerefMut for ViaDeserialize<T> {
143    fn deref_mut(&mut self) -> &mut T {
144        &mut self.0
145    }
146}
147
148// this is a macro so that we don't accidentally diverge between
149// the Value and &Value deserializer
150macro_rules! common_forward {
151    () => {
152        forward_to_deserialize_any! {
153            bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit
154            seq bytes byte_buf map
155            tuple_struct struct tuple ignored_any identifier
156        }
157    };
158}
159
160#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
161impl IntoDeserializer<'_, Error> for Value {
162    type Deserializer = Value;
163
164    fn into_deserializer(self) -> Value {
165        self
166    }
167}
168
169#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
170impl<'de> Deserializer<'de> for Value {
171    type Error = Error;
172
173    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
174        match self.0 {
175            ValueRepr::Invalid(ref error) => Err(de::Error::custom(error)),
176            ValueRepr::Bool(v) => visitor.visit_bool(v),
177            ValueRepr::U64(v) => visitor.visit_u64(v),
178            ValueRepr::I64(v) => visitor.visit_i64(v),
179            ValueRepr::I128(v) => visitor.visit_i128(v.0),
180            ValueRepr::U128(v) => visitor.visit_u128(v.0),
181            ValueRepr::F64(v) => visitor.visit_f64(v),
182            ValueRepr::String(ref v, _) => visitor.visit_str(v),
183            ValueRepr::SmallStr(v) => visitor.visit_str(v.as_str()),
184            ValueRepr::Undefined(_) | ValueRepr::None => visitor.visit_unit(),
185            ValueRepr::Bytes(ref v) => visitor.visit_bytes(v),
186            ValueRepr::Object(o) => match o.repr() {
187                ObjectRepr::Plain => Err(de::Error::custom("cannot deserialize plain objects")),
188                ObjectRepr::Seq | ObjectRepr::Iterable => {
189                    visitor.visit_seq(SeqDeserializer::new(o.try_iter().into_iter().flatten()))
190                }
191                ObjectRepr::Map => visitor.visit_map(MapDeserializer::new(
192                    o.try_iter_pairs().into_iter().flatten(),
193                )),
194            },
195        }
196    }
197
198    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
199        match self.0 {
200            ValueRepr::None | ValueRepr::Undefined(_) => visitor.visit_unit(),
201            _ => visitor.visit_some(self),
202        }
203    }
204
205    fn deserialize_enum<V: Visitor<'de>>(
206        self,
207        _name: &'static str,
208        _variants: &'static [&'static str],
209        visitor: V,
210    ) -> Result<V::Value, Error> {
211        let (variant, value) = match self.kind() {
212            ValueKind::Map => {
213                let mut iter = ok!(self.try_iter());
214                let variant = match iter.next() {
215                    Some(v) => v,
216                    None => {
217                        return Err(de::Error::invalid_value(
218                            Unexpected::Map,
219                            &"map with a single key",
220                        ))
221                    }
222                };
223                if iter.next().is_some() {
224                    return Err(de::Error::invalid_value(
225                        Unexpected::Map,
226                        &"map with a single key",
227                    ));
228                }
229                let val = self.get_item_opt(&variant);
230                (variant, val)
231            }
232            ValueKind::String => (self, None),
233            _ => {
234                return Err(de::Error::invalid_type(
235                    value_to_unexpected(&self),
236                    &"string or map",
237                ))
238            }
239        };
240
241        visitor.visit_enum(EnumDeserializer { variant, value })
242    }
243
244    #[inline]
245    fn deserialize_unit_struct<V: Visitor<'de>>(
246        self,
247        _name: &'static str,
248        visitor: V,
249    ) -> Result<V::Value, Error> {
250        self.deserialize_unit(visitor)
251    }
252
253    #[inline]
254    fn deserialize_newtype_struct<V: Visitor<'de>>(
255        self,
256        _name: &'static str,
257        visitor: V,
258    ) -> Result<V::Value, Error> {
259        visitor.visit_newtype_struct(self)
260    }
261
262    common_forward!();
263}
264
265struct EnumDeserializer {
266    variant: Value,
267    value: Option<Value>,
268}
269
270impl<'de> EnumAccess<'de> for EnumDeserializer {
271    type Error = Error;
272    type Variant = VariantDeserializer;
273
274    fn variant_seed<V: DeserializeSeed<'de>>(
275        self,
276        seed: V,
277    ) -> Result<(V::Value, VariantDeserializer), Error> {
278        seed.deserialize(self.variant)
279            .map(|v| (v, VariantDeserializer { value: self.value }))
280    }
281}
282
283struct VariantDeserializer {
284    value: Option<Value>,
285}
286
287impl<'de> VariantAccess<'de> for VariantDeserializer {
288    type Error = Error;
289
290    fn unit_variant(self) -> Result<(), Error> {
291        match self.value {
292            Some(value) => Deserialize::deserialize(value),
293            None => Ok(()),
294        }
295    }
296
297    fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value, Error> {
298        match self.value {
299            Some(value) => seed.deserialize(value),
300            None => Err(de::Error::invalid_type(
301                Unexpected::UnitVariant,
302                &"newtype variant",
303            )),
304        }
305    }
306
307    fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value, Error> {
308        match self.value.as_ref().and_then(|x| x.as_object()) {
309            Some(obj) if matches!(obj.repr(), ObjectRepr::Seq) => Deserializer::deserialize_any(
310                SeqDeserializer::new(obj.try_iter().into_iter().flatten()),
311                visitor,
312            ),
313            _ => Err(de::Error::invalid_type(
314                self.value
315                    .as_ref()
316                    .map_or(Unexpected::Unit, value_to_unexpected),
317                &"tuple variant",
318            )),
319        }
320    }
321
322    fn struct_variant<V: Visitor<'de>>(
323        self,
324        _fields: &'static [&'static str],
325        visitor: V,
326    ) -> Result<V::Value, Error> {
327        match self.value.as_ref().map(|x| (x.kind(), x)) {
328            Some((ValueKind::Map, val)) => Deserializer::deserialize_any(
329                MapDeserializer::new(
330                    ok!(val.try_iter())
331                        .map(|ref k| (k.clone(), val.get_item(k).unwrap_or_default())),
332                ),
333                visitor,
334            ),
335            _ => Err(de::Error::invalid_type(
336                self.value
337                    .as_ref()
338                    .map_or(Unexpected::Unit, value_to_unexpected),
339                &"struct variant",
340            )),
341        }
342    }
343}
344
345#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
346impl<'de> Deserializer<'de> for &Value {
347    type Error = Error;
348
349    #[inline]
350    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
351        self.clone().deserialize_any(visitor)
352    }
353
354    #[inline]
355    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
356        self.clone().deserialize_option(visitor)
357    }
358
359    #[inline]
360    fn deserialize_enum<V: Visitor<'de>>(
361        self,
362        name: &'static str,
363        variants: &'static [&'static str],
364        visitor: V,
365    ) -> Result<V::Value, Error> {
366        self.clone().deserialize_enum(name, variants, visitor)
367    }
368
369    #[inline]
370    fn deserialize_unit_struct<V: Visitor<'de>>(
371        self,
372        name: &'static str,
373        visitor: V,
374    ) -> Result<V::Value, Error> {
375        self.clone().deserialize_unit_struct(name, visitor)
376    }
377
378    #[inline]
379    fn deserialize_newtype_struct<V: Visitor<'de>>(
380        self,
381        name: &'static str,
382        visitor: V,
383    ) -> Result<V::Value, Error> {
384        self.clone().deserialize_newtype_struct(name, visitor)
385    }
386
387    common_forward!();
388}
389
390#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
391impl<'de> IntoDeserializer<'de, Error> for &'de Value {
392    type Deserializer = &'de Value;
393
394    fn into_deserializer(self) -> &'de Value {
395        self
396    }
397}
398
399#[cfg_attr(docsrs, doc(cfg(feature = "deserialization")))]
400impl de::Error for Error {
401    fn custom<T: std::fmt::Display>(msg: T) -> Self {
402        Error::new(ErrorKind::CannotDeserialize, msg.to_string())
403    }
404}
405
406fn value_to_unexpected(value: &Value) -> Unexpected {
407    match value.0 {
408        ValueRepr::Undefined(_) | ValueRepr::None => Unexpected::Unit,
409        ValueRepr::Bool(val) => Unexpected::Bool(val),
410        ValueRepr::U64(val) => Unexpected::Unsigned(val),
411        ValueRepr::I64(val) => Unexpected::Signed(val),
412        ValueRepr::F64(val) => Unexpected::Float(val),
413        ValueRepr::Invalid(_) => Unexpected::Other("<invalid value>"),
414        ValueRepr::U128(val) => {
415            let unsigned = val.0 as u64;
416            if unsigned as u128 == val.0 {
417                Unexpected::Unsigned(unsigned)
418            } else {
419                Unexpected::Other("u128")
420            }
421        }
422        ValueRepr::I128(val) => {
423            let signed = val.0 as i64;
424            if signed as i128 == val.0 {
425                Unexpected::Signed(signed)
426            } else {
427                Unexpected::Other("u128")
428            }
429        }
430        ValueRepr::String(ref s, _) => Unexpected::Str(s),
431        ValueRepr::SmallStr(ref s) => Unexpected::Str(s.as_str()),
432        ValueRepr::Bytes(ref b) => Unexpected::Bytes(b),
433        ValueRepr::Object(..) => Unexpected::Other("<dynamic value>"),
434    }
435}