Skip to content

Commit 928e089

Browse files
committed
deserialize enums
1 parent 4bb9a5f commit 928e089

File tree

2 files changed

+162
-2
lines changed

2 files changed

+162
-2
lines changed

serde-systemd-unit/src/de.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,29 @@ impl<'de, 'a> serde::de::Deserializer<'de> for OptStringDeserializer<'a> {
2828
visitor.visit_str(self.0)
2929
}
3030

31+
fn deserialize_enum<V>(
32+
self,
33+
name: &'static str,
34+
variants: &'static [&'static str],
35+
visitor: V,
36+
) -> Result<V::Value, Self::Error>
37+
where
38+
V: serde::de::Visitor<'de>,
39+
{
40+
EnumDeserializer(self.0).deserialize_enum(name, variants, visitor)
41+
}
42+
3143
serde::forward_to_deserialize_any! {
3244
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char string
3345
bytes byte_buf unit unit_struct newtype_struct seq tuple
34-
tuple_struct struct enum identifier ignored_any map
46+
tuple_struct struct ignored_any map
47+
}
48+
49+
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
50+
where
51+
V: serde::de::Visitor<'de>,
52+
{
53+
visitor.visit_str(self.0)
3554
}
3655
}
3756

@@ -69,7 +88,10 @@ impl<'de> serde::de::Deserializer<'de> for OptVecDeserializer {
6988
where
7089
T: serde::de::DeserializeSeed<'de>,
7190
{
72-
self.0.next().map_or_else(|| Ok(None), |val| seed.deserialize(OptStringDeserializer(&val)).map(Some))
91+
self.0.next().map_or_else(
92+
|| Ok(None),
93+
|val| seed.deserialize(OptStringDeserializer(&val)).map(Some),
94+
)
7395
}
7496
}
7597

@@ -83,6 +105,91 @@ impl<'de> serde::de::Deserializer<'de> for OptVecDeserializer {
83105
}
84106
}
85107

108+
/// Deserializer for converting strings to enum variants
109+
pub struct EnumDeserializer<'a>(&'a str);
110+
111+
impl<'de, 'a> serde::de::Deserializer<'de> for EnumDeserializer<'a> {
112+
type Error = serde::de::value::Error;
113+
114+
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
115+
where
116+
V: serde::de::Visitor<'de>,
117+
{
118+
self.deserialize_enum("", &[], visitor)
119+
}
120+
121+
fn deserialize_enum<V>(
122+
self,
123+
_name: &str,
124+
_variants: &'static [&'static str],
125+
visitor: V,
126+
) -> Result<V::Value, Self::Error>
127+
where
128+
V: serde::de::Visitor<'de>,
129+
{
130+
visitor.visit_enum(self)
131+
}
132+
133+
serde::forward_to_deserialize_any! {
134+
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
135+
bytes byte_buf unit unit_struct newtype_struct seq tuple
136+
tuple_struct struct map option identifier ignored_any
137+
}
138+
}
139+
140+
impl<'de, 'a> serde::de::EnumAccess<'de> for EnumDeserializer<'a> {
141+
type Error = serde::de::value::Error;
142+
type Variant = UnitOnlyVariantAccess;
143+
144+
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
145+
where
146+
V: serde::de::DeserializeSeed<'de>,
147+
{
148+
let variant = seed.deserialize(self.0.into_deserializer())?;
149+
Ok((variant, UnitOnlyVariantAccess))
150+
}
151+
}
152+
153+
/// Helper struct for unit-only enum variants
154+
pub struct UnitOnlyVariantAccess;
155+
156+
impl<'de> serde::de::VariantAccess<'de> for UnitOnlyVariantAccess {
157+
type Error = serde::de::value::Error;
158+
159+
fn unit_variant(self) -> Result<(), Self::Error> {
160+
Ok(())
161+
}
162+
163+
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
164+
where
165+
T: serde::de::DeserializeSeed<'de>,
166+
{
167+
Err(serde::de::Error::custom(
168+
"newtype variants are not supported",
169+
))
170+
}
171+
172+
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
173+
where
174+
V: serde::de::Visitor<'de>,
175+
{
176+
Err(serde::de::Error::custom("tuple variants are not supported"))
177+
}
178+
179+
fn struct_variant<V>(
180+
self,
181+
_fields: &'static [&'static str],
182+
_visitor: V,
183+
) -> Result<V::Value, Self::Error>
184+
where
185+
V: serde::de::Visitor<'de>,
186+
{
187+
Err(serde::de::Error::custom(
188+
"struct variants are not supported",
189+
))
190+
}
191+
}
192+
86193
pub struct SectionDeserializer<'a> {
87194
pub map: &'a std::collections::BTreeMap<String, Value>,
88195
}

serde-systemd-unit/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,4 +360,57 @@ key3=value2
360360
assert_eq!(test.section.optional, Some("optvalue".to_owned()));
361361
assert_eq!(test.section.missing, None);
362362
}
363+
364+
#[test]
365+
fn test_deserialize_enum() {
366+
#[derive(Debug, serde::Deserialize, PartialEq)]
367+
enum Mode {
368+
Read,
369+
Write,
370+
ReadWrite,
371+
}
372+
373+
#[derive(Debug, serde::Deserialize)]
374+
struct TestEnum {
375+
section: SectionWithEnum,
376+
}
377+
378+
#[derive(Debug, serde::Deserialize)]
379+
struct SectionWithEnum {
380+
mode: Mode,
381+
}
382+
383+
let ini = "[section]\nmode=ReadWrite\n";
384+
let test: TestEnum = from_str(ini).unwrap();
385+
assert_eq!(test.section.mode, Mode::ReadWrite);
386+
}
387+
388+
#[test]
389+
fn test_deserialize_enum_array() {
390+
#[derive(Debug, serde::Deserialize, PartialEq)]
391+
enum Mode {
392+
Read,
393+
Write,
394+
ReadWrite,
395+
}
396+
397+
#[derive(Debug, serde::Deserialize)]
398+
struct TestEnum {
399+
section: SectionWithEnum,
400+
}
401+
402+
#[derive(Debug, serde::Deserialize)]
403+
struct SectionWithEnum {
404+
mode: Mode,
405+
modes: Vec<Mode>,
406+
}
407+
408+
let ini = "[section]\nmode=ReadWrite\nmodes=Read\nmodes=Write\n";
409+
let test: TestEnum = from_str(ini).unwrap();
410+
assert_eq!(test.section.mode, Mode::ReadWrite);
411+
assert_eq!(
412+
test.section.modes,
413+
vec![Mode::Read, Mode::Write]
414+
);
415+
}
363416
}

0 commit comments

Comments
 (0)