1
use serde::{Deserialize, Serialize};
2

            
3
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
4
enum InnerEnum {
5
    Unit,
6
    Newtype(bool),
7
    Tuple(bool, i32),
8
    Struct { field: char },
9
}
10

            
11
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
12
#[serde(deny_unknown_fields)]
13
struct Container {
14
    field: InnerEnum,
15
}
16

            
17
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
18
enum OuterEnum {
19
    Variant(Container),
20
    Sum { field: InnerEnum, value: i32 },
21
}
22

            
23
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
24
#[serde(tag = "tag")]
25
enum OuterEnumInternal {
26
    Variant(Container),
27
    Sum { field: InnerEnum, value: i32 },
28
}
29

            
30
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
31
#[serde(tag = "tag", content = "c")]
32
enum OuterEnumAdjacent {
33
    Variant(Container),
34
    Sum { field: InnerEnum, value: i32 },
35
}
36

            
37
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
38
#[serde(untagged)]
39
enum OuterEnumUntagged {
40
    Variant(Container),
41
    Sum { field: InnerEnum, value: i32 },
42
}
43

            
44
#[test]
45
4
fn test_serde_content_hack() {
46
4
    assert!(matches!(
47
4
        std::any::type_name::<serde::__private::de::Content>(),
48
4
        "serde::__private::de::content::Content" | "serde::__private::de::content::Content<'_>"
49
    ));
50
4
}
51

            
52
#[test]
53
4
fn test_serde_internally_tagged_hack() {
54
    // ensure that these are the same as in ron::de module
55
8
    fn is_serde_content<T>() -> bool {
56
4
        matches!(
57
8
            core::any::type_name::<T>(),
58
8
            "serde::__private::de::content::Content" | "serde::__private::de::content::Content<'_>"
59
        )
60
8
    }
61

            
62
12
    fn is_serde_tag_or_content<T>() -> bool {
63
12
        matches!(
64
12
            core::any::type_name::<T>(),
65
12
            "serde::__private::de::content::TagOrContent"
66
                | "serde::__private::de::content::TagOrContent<'_>"
67
        )
68
12
    }
69

            
70
    struct Deserializer {
71
        tag_key: Option<String>,
72
        tag_value: String,
73
        field_key: Option<String>,
74
        field_value: i32,
75
    }
76

            
77
    impl<'de> serde::Deserializer<'de> for Deserializer {
78
        type Error = ron::Error;
79

            
80
4
        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
81
4
        where
82
4
            V: serde::de::Visitor<'de>,
83
        {
84
4
            visitor.visit_map(self)
85
4
        }
86

            
87
        // GRCOV_EXCL_START
88
        serde::forward_to_deserialize_any! {
89
            bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
90
            bytes byte_buf option unit unit_struct newtype_struct seq tuple
91
            tuple_struct map struct enum identifier ignored_any
92
        }
93
        // GRCOV_EXCL_STOP
94
    }
95

            
96
    impl<'de> serde::de::MapAccess<'de> for Deserializer {
97
        type Error = ron::Error;
98

            
99
12
        fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
100
12
        where
101
12
            K: serde::de::DeserializeSeed<'de>,
102
        {
103
12
            assert!(is_serde_tag_or_content::<K::Value>());
104

            
105
12
            if let Some(tag_key) = self.tag_key.take() {
106
4
                return seed
107
4
                    .deserialize(serde::de::value::StringDeserializer::new(tag_key))
108
4
                    .map(Some);
109
8
            }
110

            
111
8
            if let Some(field_key) = self.field_key.take() {
112
4
                return seed
113
4
                    .deserialize(serde::de::value::StringDeserializer::new(field_key))
114
4
                    .map(Some);
115
4
            }
116

            
117
4
            Ok(None)
118
12
        }
119

            
120
8
        fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
121
8
        where
122
8
            V: serde::de::DeserializeSeed<'de>,
123
        {
124
8
            if self.field_key.is_some() {
125
4
                assert!(!is_serde_content::<V::Value>());
126
4
                return seed.deserialize(serde::de::value::StrDeserializer::new(&self.tag_value));
127
4
            }
128

            
129
4
            assert!(is_serde_content::<V::Value>());
130

            
131
4
            seed.deserialize(serde::de::value::I32Deserializer::new(self.field_value))
132
8
        }
133
    }
134

            
135
    #[derive(PartialEq, Debug, Deserialize)]
136
    #[serde(tag = "tag")]
137
    enum InternallyTagged {
138
        A { hi: i32 },
139
    }
140

            
141
4
    assert_eq!(
142
4
        InternallyTagged::deserialize(Deserializer {
143
4
            tag_key: Some(String::from("tag")),
144
4
            tag_value: String::from("A"),
145
4
            field_key: Some(String::from("hi")),
146
4
            field_value: 42,
147
4
        }),
148
        Ok(InternallyTagged::A { hi: 42 })
149
    );
150
4
}
151

            
152
#[test]
153
4
fn test_enum_in_enum_roundtrip() {
154
4
    let outer = OuterEnum::Variant(Container {
155
4
        field: InnerEnum::Unit,
156
4
    });
157

            
158
4
    let ron = ron::to_string(&outer).unwrap();
159

            
160
4
    assert_eq!(ron, "Variant((field:Unit))");
161

            
162
4
    let de = ron::from_str::<OuterEnum>(&ron);
163

            
164
4
    assert_eq!(de, Ok(outer));
165

            
166
4
    let outer = OuterEnum::Sum {
167
4
        field: InnerEnum::Newtype(true),
168
4
        value: 42,
169
4
    };
170

            
171
4
    let ron = ron::to_string(&outer).unwrap();
172

            
173
4
    assert_eq!(ron, "Sum(field:Newtype(true),value:42)");
174

            
175
4
    let de = ron::from_str::<OuterEnum>(&ron);
176

            
177
4
    assert_eq!(de, Ok(outer));
178

            
179
4
    let outer = OuterEnum::Sum {
180
4
        field: InnerEnum::Tuple(true, 24),
181
4
        value: 42,
182
4
    };
183

            
184
4
    let ron = ron::to_string(&outer).unwrap();
185

            
186
4
    assert_eq!(ron, "Sum(field:Tuple(true,24),value:42)");
187

            
188
4
    let de = ron::from_str::<OuterEnum>(&ron);
189

            
190
4
    assert_eq!(de, Ok(outer));
191

            
192
4
    let outer = OuterEnum::Sum {
193
4
        field: InnerEnum::Struct { field: '🦀' },
194
4
        value: 42,
195
4
    };
196

            
197
4
    let ron = ron::to_string(&outer).unwrap();
198

            
199
4
    assert_eq!(ron, "Sum(field:Struct(field:'🦀'),value:42)");
200

            
201
4
    let de = ron::from_str::<OuterEnum>(&ron);
202

            
203
4
    assert_eq!(de, Ok(outer));
204
4
}
205

            
206
#[test]
207
4
fn test_enum_in_internally_tagged_roundtrip() {
208
4
    let outer = OuterEnumInternal::Variant(Container {
209
4
        field: InnerEnum::Unit,
210
4
    });
211

            
212
4
    let ron = ron::to_string(&outer).unwrap();
213

            
214
4
    assert_eq!(ron, "(tag:\"Variant\",field:Unit)");
215

            
216
4
    let de = ron::from_str::<OuterEnumInternal>(&ron);
217

            
218
4
    assert_eq!(de, Ok(outer));
219

            
220
4
    let outer = OuterEnumInternal::Sum {
221
4
        field: InnerEnum::Newtype(true),
222
4
        value: 42,
223
4
    };
224

            
225
4
    let ron = ron::to_string(&outer).unwrap();
226

            
227
4
    assert_eq!(ron, "(tag:\"Sum\",field:Newtype(true),value:42)");
228

            
229
4
    let de = ron::from_str::<OuterEnumInternal>(&ron);
230

            
231
4
    assert_eq!(de, Ok(outer));
232

            
233
4
    let outer = OuterEnumInternal::Sum {
234
4
        field: InnerEnum::Tuple(true, 24),
235
4
        value: 42,
236
4
    };
237

            
238
4
    let ron = ron::to_string(&outer).unwrap();
239

            
240
4
    assert_eq!(ron, "(tag:\"Sum\",field:Tuple(true,24),value:42)");
241

            
242
4
    let de = ron::from_str::<OuterEnumInternal>(&ron);
243

            
244
4
    assert_eq!(de, Ok(outer));
245

            
246
4
    let outer = OuterEnumInternal::Sum {
247
4
        field: InnerEnum::Struct { field: '🦀' },
248
4
        value: 42,
249
4
    };
250

            
251
4
    let ron = ron::to_string(&outer).unwrap();
252

            
253
4
    assert_eq!(ron, "(tag:\"Sum\",field:Struct(field:'🦀'),value:42)");
254

            
255
4
    let de = ron::from_str::<OuterEnumInternal>(&ron);
256

            
257
4
    assert_eq!(de, Ok(outer));
258
4
}
259

            
260
#[test]
261
4
fn test_enum_in_adjacently_tagged_roundtrip() {
262
4
    let outer = OuterEnumAdjacent::Variant(Container {
263
4
        field: InnerEnum::Unit,
264
4
    });
265

            
266
4
    let ron = ron::to_string(&outer).unwrap();
267

            
268
4
    assert_eq!(ron, "(tag:Variant,c:(field:Unit))");
269

            
270
4
    let de = ron::from_str::<OuterEnumAdjacent>(&ron);
271

            
272
4
    assert_eq!(de, Ok(outer));
273

            
274
4
    let outer = OuterEnumAdjacent::Sum {
275
4
        field: InnerEnum::Newtype(true),
276
4
        value: 42,
277
4
    };
278

            
279
4
    let ron = ron::to_string(&outer).unwrap();
280

            
281
4
    assert_eq!(ron, "(tag:Sum,c:(field:Newtype(true),value:42))");
282

            
283
4
    let de = ron::from_str::<OuterEnumAdjacent>(&ron);
284

            
285
4
    assert_eq!(de, Ok(outer));
286

            
287
4
    let outer = OuterEnumAdjacent::Sum {
288
4
        field: InnerEnum::Tuple(true, 24),
289
4
        value: 42,
290
4
    };
291

            
292
4
    let ron = ron::to_string(&outer).unwrap();
293

            
294
4
    assert_eq!(ron, "(tag:Sum,c:(field:Tuple(true,24),value:42))");
295

            
296
4
    let de = ron::from_str::<OuterEnumAdjacent>(&ron);
297

            
298
4
    assert_eq!(de, Ok(outer));
299

            
300
4
    let outer = OuterEnumAdjacent::Sum {
301
4
        field: InnerEnum::Struct { field: '🦀' },
302
4
        value: 42,
303
4
    };
304

            
305
4
    let ron = ron::to_string(&outer).unwrap();
306

            
307
4
    assert_eq!(ron, "(tag:Sum,c:(field:Struct(field:'🦀'),value:42))");
308

            
309
4
    let de = ron::from_str::<OuterEnumAdjacent>(&ron);
310

            
311
4
    assert_eq!(de, Ok(outer));
312
4
}
313

            
314
#[test]
315
4
fn test_enum_in_untagged_roundtrip() {
316
4
    let outer = OuterEnumUntagged::Variant(Container {
317
4
        field: InnerEnum::Unit,
318
4
    });
319

            
320
4
    let ron = ron::to_string(&outer).unwrap();
321

            
322
4
    assert_eq!(ron, "(field:Unit)");
323

            
324
4
    let de = ron::from_str::<OuterEnumUntagged>(&ron);
325

            
326
4
    assert_eq!(de, Ok(outer));
327

            
328
4
    let outer = OuterEnumUntagged::Sum {
329
4
        field: InnerEnum::Newtype(true),
330
4
        value: 42,
331
4
    };
332

            
333
4
    let ron = ron::to_string(&outer).unwrap();
334

            
335
4
    assert_eq!(ron, "(field:Newtype(true),value:42)");
336

            
337
4
    let de = ron::from_str::<OuterEnumUntagged>(&ron);
338

            
339
4
    assert_eq!(de, Ok(outer));
340

            
341
4
    let outer = OuterEnumUntagged::Sum {
342
4
        field: InnerEnum::Tuple(true, 24),
343
4
        value: 42,
344
4
    };
345

            
346
4
    let ron = ron::to_string(&outer).unwrap();
347

            
348
4
    assert_eq!(ron, "(field:Tuple(true,24),value:42)");
349

            
350
4
    let de = ron::from_str::<OuterEnumUntagged>(&ron);
351

            
352
4
    assert_eq!(de, Ok(outer));
353

            
354
4
    let outer = OuterEnumUntagged::Sum {
355
4
        field: InnerEnum::Struct { field: '🦀' },
356
4
        value: 42,
357
4
    };
358

            
359
4
    let ron = ron::to_string(&outer).unwrap();
360

            
361
4
    assert_eq!(ron, "(field:Struct(field:'🦀'),value:42)");
362

            
363
4
    let de = ron::from_str::<OuterEnumUntagged>(&ron);
364

            
365
4
    assert_eq!(de, Ok(outer));
366
4
}