Repository: mitsuhiko/minijinja (rust)

Issue:
Serialized Value cannot Deserialize
## Description

I'm using Value::from_serialize pass context to template. Then using `ViaDeserialize<Type>` deserialize the value. however, it failed.

here are some log:

<details>

```console
called `Result::unwrap()` on an `Err` value: Error { kind: CannotDeserialize, detail: "invalid type: map, expected enum Type", name: "op.idl", line: 24 }

----------------------------------- op.idl ------------------------------------
  22 |         {% for param in params %}
  24 >                 {{ param.ty | to_ty }} {{ param.ident }};
     i                               ^^^^^ cannot deserialize
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Referenced variables: {
    base_name: <macro base_name>,
    in_params: 0,
    loop: <loop 0/1>,
    param: {
        "ident": "com",
        "ty": {
            "Path": [
                "Command",
            ],
        },
    }
}

```
</details>

here is my enum defination:

```rs
enum Type {
    Array(TypeArray),
    Path(TypePath),
    Primative(PrimativeType),
}
```

as far as I know, plain enum, unit struct cannot be deserialize. It seems enum would be serialized to &str?

Additional helpful information:

- Version of minijinja: v2.1.1
- Version of rustc: 1.80.0
- Operating system and version: macos 14.5

## What did you expect

Serialization and deserialization operations should be symmetric


Pull request:
Fix a bug with deserializating enums
This fixes some bugs with the deserialize trait on `Value`.  I'm not sure if this covers all cases, but it fixes the cases reported.

Fixes #553

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index de8083d..d27b06b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
 
 All notable changes to MiniJinja are documented here.
 
+## 2.1.3
+
+- Fixes a bug where some enums did not deserialize correctly when
+  used with `ViaDeserialize`.  #554
+
 ## 2.1.2
 
 - Flush filter and test cache when processing extended template.
diff --git a/minijinja/src/value/deserialize.rs b/minijinja/src/value/deserialize.rs
index bdaae73..4672df1 100644
--- a/minijinja/src/value/deserialize.rs
+++ b/minijinja/src/value/deserialize.rs
@@ -246,10 +246,30 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer {
         visitor.visit_enum(EnumDeserializer { variant, value })
     }
 
+    #[inline]
+    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value, Error>
+    where
+        V: Visitor<'de>,
+    {
+        self.deserialize_unit(visitor)
+    }
+
+    #[inline]
+    fn deserialize_newtype_struct<V>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Error>
+    where
+        V: Visitor<'de>,
+    {
+        visitor.visit_newtype_struct(self)
+    }
+
     forward_to_deserialize_any! {
         bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit
-        seq bytes byte_buf map unit_struct
-        tuple_struct struct tuple ignored_any identifier newtype_struct
+        seq bytes byte_buf map
+        tuple_struct struct tuple ignored_any identifier
     }
 }
 
@@ -403,11 +423,31 @@ impl<'de, 'v> de::Deserializer<'de> for &'v Value {
         ValueDeserializer::new(self.clone()).deserialize_any(visitor)
     }
 
+    fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
+        ValueDeserializer::new(self.clone()).deserialize_option(visitor)
+    }
+
+    fn deserialize_enum<V: de::Visitor<'de>>(
+        self,
+        name: &'static str,
+        variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value, Error> {
+        ValueDeserializer::new(self.clone()).deserialize_enum(name, variants, visitor)
+    }
+
+    fn deserialize_newtype_struct<V: de::Visitor<'de>>(
+        self,
+        name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value, Error> {
+        ValueDeserializer::new(self.clone()).deserialize_newtype_struct(name, visitor)
+    }
+
     forward_to_deserialize_any! {
         bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit
         seq bytes byte_buf map unit_struct
         tuple_struct struct tuple ignored_any identifier
-        option enum newtype_struct
     }
 }
 


Test patch:
diff --git a/minijinja/tests/test_value.rs b/minijinja/tests/test_value.rs
index a8d887f..ad432bf 100644
--- a/minijinja/tests/test_value.rs
+++ b/minijinja/tests/test_value.rs
@@ -560,6 +560,7 @@ fn test_complex_key() {
 #[test]
 #[cfg(feature = "deserialization")]
 fn test_deserialize() {
+    use minijinja::value::{from_args, ViaDeserialize};
     use serde::Deserialize;
 
     #[derive(Deserialize, Debug, PartialEq, Eq)]
@@ -572,6 +573,34 @@ fn test_deserialize() {
     let point = Point::deserialize(point_value).unwrap();
 
     assert_eq!(point, Point { x: 42, y: -23 });
+
+    #[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
+    enum SimpleEnum {
+        B,
+        C,
+        D,
+    }
+
+    #[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
+    enum TaggedUnion {
+        V(String),
+    }
+
+    #[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
+    struct UnitStruct(String);
+
+    let spe = Value::from_serialize(SimpleEnum::B);
+    let spu = Value::from_serialize(UnitStruct("hello".into()));
+    let spt = Value::from_serialize(TaggedUnion::V("workd".into()));
+
+    let a: (
+        ViaDeserialize<SimpleEnum>,
+        ViaDeserialize<UnitStruct>,
+        ViaDeserialize<TaggedUnion>,
+    ) = from_args(args!(spe, spu, spt)).unwrap();
+    assert_eq!((a.0).0, SimpleEnum::B);
+    assert_eq!((a.1).0, UnitStruct("hello".into()));
+    assert_eq!((a.2).0, TaggedUnion::V("workd".into()));
 }
 
 #[test]