Skip to content

Commit 2ddf40f

Browse files
authored
fix: implement deserialize_option for ValueDeserializer (#45)
Fixes #44 Deserialization into custom struct with `Option<T>` fields caused an error: ``` Message { msg: "invalid type: string \"./test.spec\", expected option", location: None } ```
1 parent cd19180 commit 2ddf40f

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/de/tests.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,57 @@ fn deserialize_terraform() {
269269

270270
assert_eq!(expected, body);
271271
}
272+
273+
// https://github.com/martinohmann/hcl-rs/issues/44
274+
#[test]
275+
fn issue_44() {
276+
use std::collections::HashMap;
277+
use std::path::PathBuf;
278+
279+
#[derive(Deserialize, Debug, PartialEq)]
280+
pub struct Config {
281+
#[serde(rename = "project")]
282+
pub projects: HashMap<String, Project>,
283+
}
284+
285+
#[derive(Deserialize, Debug, PartialEq)]
286+
pub struct Project {
287+
pub proj_type: String,
288+
pub spec: Option<PathBuf>,
289+
pub dockerfile: Option<PathBuf>,
290+
pub scripts: Option<Vec<Script>>,
291+
}
292+
293+
#[derive(Deserialize, Debug, PartialEq)]
294+
pub struct Script {
295+
pub name: String,
296+
pub command: String,
297+
}
298+
299+
let input = r#"
300+
project "a" {
301+
proj_type = "generic"
302+
spec = "./test.spec"
303+
}
304+
"#;
305+
306+
let config: Config = crate::from_str(input).unwrap();
307+
308+
let expected = Config {
309+
projects: {
310+
let mut map = HashMap::new();
311+
map.insert(
312+
"a".into(),
313+
Project {
314+
proj_type: "generic".into(),
315+
spec: Some(PathBuf::from("./test.spec")),
316+
dockerfile: None,
317+
scripts: None,
318+
},
319+
);
320+
map
321+
},
322+
};
323+
324+
assert_eq!(config, expected);
325+
}

src/value/de.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ impl<'de, 'a> de::Deserializer<'de> for ValueDeserializer {
131131
}
132132
}
133133

134+
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
135+
where
136+
V: Visitor<'de>,
137+
{
138+
match self.value {
139+
Value::Null => visitor.visit_none(),
140+
_ => visitor.visit_some(self),
141+
}
142+
}
143+
134144
fn deserialize_enum<V>(
135145
self,
136146
_name: &'static str,
@@ -149,7 +159,7 @@ impl<'de, 'a> de::Deserializer<'de> for ValueDeserializer {
149159

150160
forward_to_deserialize_any! {
151161
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
152-
bytes byte_buf option unit unit_struct newtype_struct seq tuple
162+
bytes byte_buf unit unit_struct newtype_struct seq tuple
153163
tuple_struct map struct identifier ignored_any
154164
}
155165
}

0 commit comments

Comments
 (0)