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

            
3
212
#[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
68
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
12
#[serde(deny_unknown_fields)]
13
struct Container {
14
    field: InnerEnum,
15
}
16

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

            
23
52
#[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
84
#[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
36
#[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_eq!(
47
4
        std::any::type_name::<serde::__private::de::Content>(),
48
4
        "serde::__private::de::content::Content"
49
4
    );
50
4
}
51

            
52
#[test]
53
4
fn test_serde_internally_tagged_hack() {
54
    const SERDE_CONTENT_CANARY: &str = "serde::__private::de::content::Content";
55
    const SERDE_TAG_KEY_CANARY: &str = "serde::__private::de::content::TagOrContent";
56

            
57
    struct Deserializer {
58
        tag_key: Option<String>,
59
        tag_value: String,
60
        field_key: Option<String>,
61
        field_value: i32,
62
    }
63

            
64
    impl<'de> serde::Deserializer<'de> for Deserializer {
65
        type Error = ron::Error;
66

            
67
4
        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
68
4
        where
69
4
            V: serde::de::Visitor<'de>,
70
4
        {
71
4
            visitor.visit_map(self)
72
4
        }
73

            
74
        // GRCOV_EXCL_START
75
        serde::forward_to_deserialize_any! {
76
            bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
77
            bytes byte_buf option unit unit_struct newtype_struct seq tuple
78
            tuple_struct map struct enum identifier ignored_any
79
        }
80
        // GRCOV_EXCL_STOP
81
    }
82

            
83
    impl<'de> serde::de::MapAccess<'de> for Deserializer {
84
        type Error = ron::Error;
85

            
86
12
        fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
87
12
        where
88
12
            K: serde::de::DeserializeSeed<'de>,
89
12
        {
90
12
            assert_eq!(std::any::type_name::<K::Value>(), SERDE_TAG_KEY_CANARY);
91

            
92
12
            if let Some(tag_key) = self.tag_key.take() {
93
4
                return seed
94
4
                    .deserialize(serde::de::value::StringDeserializer::new(tag_key))
95
4
                    .map(Some);
96
8
            }
97

            
98
8
            if let Some(field_key) = self.field_key.take() {
99
4
                return seed
100
4
                    .deserialize(serde::de::value::StringDeserializer::new(field_key))
101
4
                    .map(Some);
102
4
            }
103
4

            
104
4
            Ok(None)
105
12
        }
106

            
107
8
        fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
108
8
        where
109
8
            V: serde::de::DeserializeSeed<'de>,
110
8
        {
111
8
            if self.field_key.is_some() {
112
4
                assert_ne!(std::any::type_name::<V::Value>(), SERDE_CONTENT_CANARY);
113
4
                return seed.deserialize(serde::de::value::StrDeserializer::new(&self.tag_value));
114
4
            }
115
4

            
116
4
            assert_eq!(std::any::type_name::<V::Value>(), SERDE_CONTENT_CANARY);
117

            
118
4
            seed.deserialize(serde::de::value::I32Deserializer::new(self.field_value))
119
8
        }
120
    }
121

            
122
12
    #[derive(PartialEq, Debug, Deserialize)]
123
    #[serde(tag = "tag")]
124
    enum InternallyTagged {
125
        A { hi: i32 },
126
    }
127

            
128
4
    assert_eq!(
129
4
        InternallyTagged::deserialize(Deserializer {
130
4
            tag_key: Some(String::from("tag")),
131
4
            tag_value: String::from("A"),
132
4
            field_key: Some(String::from("hi")),
133
4
            field_value: 42,
134
4
        }),
135
4
        Ok(InternallyTagged::A { hi: 42 })
136
4
    );
137
4
}
138

            
139
#[test]
140
4
fn test_enum_in_enum_roundtrip() {
141
4
    let outer = OuterEnum::Variant(Container {
142
4
        field: InnerEnum::Unit,
143
4
    });
144
4

            
145
4
    let ron = ron::to_string(&outer).unwrap();
146
4

            
147
4
    assert_eq!(ron, "Variant((field:Unit))");
148

            
149
4
    let de = ron::from_str::<OuterEnum>(&ron);
150
4

            
151
4
    assert_eq!(de, Ok(outer));
152

            
153
4
    let outer = OuterEnum::Sum {
154
4
        field: InnerEnum::Newtype(true),
155
4
        value: 42,
156
4
    };
157
4

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

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

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

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

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

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

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

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

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

            
179
4
    let outer = OuterEnum::Sum {
180
4
        field: InnerEnum::Struct { field: '🦀' },
181
4
        value: 42,
182
4
    };
183
4

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

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

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

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

            
193
#[test]
194
4
fn test_enum_in_internally_tagged_roundtrip() {
195
4
    let outer = OuterEnumInternal::Variant(Container {
196
4
        field: InnerEnum::Unit,
197
4
    });
198
4

            
199
4
    let ron = ron::to_string(&outer).unwrap();
200
4

            
201
4
    assert_eq!(ron, "(tag:\"Variant\",field:Unit)");
202

            
203
4
    let de = ron::from_str::<OuterEnumInternal>(&ron);
204
4

            
205
4
    assert_eq!(de, Ok(outer));
206

            
207
4
    let outer = OuterEnumInternal::Sum {
208
4
        field: InnerEnum::Newtype(true),
209
4
        value: 42,
210
4
    };
211
4

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

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

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

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

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

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

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

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

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

            
233
4
    let outer = OuterEnumInternal::Sum {
234
4
        field: InnerEnum::Struct { field: '🦀' },
235
4
        value: 42,
236
4
    };
237
4

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

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

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

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

            
247
#[test]
248
4
fn test_enum_in_adjacently_tagged_roundtrip() {
249
4
    let outer = OuterEnumAdjacent::Variant(Container {
250
4
        field: InnerEnum::Unit,
251
4
    });
252
4

            
253
4
    let ron = ron::to_string(&outer).unwrap();
254
4

            
255
4
    assert_eq!(ron, "(tag:Variant,c:(field:Unit))");
256

            
257
4
    let de = ron::from_str::<OuterEnumAdjacent>(&ron);
258
4

            
259
4
    assert_eq!(de, Ok(outer));
260

            
261
4
    let outer = OuterEnumAdjacent::Sum {
262
4
        field: InnerEnum::Newtype(true),
263
4
        value: 42,
264
4
    };
265
4

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

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

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

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

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

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

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

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

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

            
287
4
    let outer = OuterEnumAdjacent::Sum {
288
4
        field: InnerEnum::Struct { field: '🦀' },
289
4
        value: 42,
290
4
    };
291
4

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

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

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

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

            
301
#[test]
302
4
fn test_enum_in_untagged_roundtrip() {
303
4
    let outer = OuterEnumUntagged::Variant(Container {
304
4
        field: InnerEnum::Unit,
305
4
    });
306
4

            
307
4
    let ron = ron::to_string(&outer).unwrap();
308
4

            
309
4
    assert_eq!(ron, "(field:Unit)");
310

            
311
4
    let de = ron::from_str::<OuterEnumUntagged>(&ron);
312
4

            
313
4
    assert_eq!(de, Ok(outer));
314

            
315
4
    let outer = OuterEnumUntagged::Sum {
316
4
        field: InnerEnum::Newtype(true),
317
4
        value: 42,
318
4
    };
319
4

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

            
322
4
    assert_eq!(ron, "(field:Newtype(true),value:42)");
323

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

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

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

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

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

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

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

            
341
4
    let outer = OuterEnumUntagged::Sum {
342
4
        field: InnerEnum::Struct { field: '🦀' },
343
4
        value: 42,
344
4
    };
345
4

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

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

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

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