Skip to content
This repository has been archived by the owner on Jan 29, 2023. It is now read-only.

serde deserializer fails for structs using serde(default) #11

Closed
wez opened this issue Nov 22, 2019 · 6 comments
Closed

serde deserializer fails for structs using serde(default) #11

wez opened this issue Nov 22, 2019 · 6 comments

Comments

@wez
Copy link
Contributor

wez commented Nov 22, 2019

#[test]
fn hocon_and_serde_default() {
    #[derive(Deserialize, Debug)]
    struct MyStruct {
        #[serde(default)]
        size: f64,
    }

    let s: MyStruct = hocon::HoconLoader::new()
        .load_str("")
        .unwrap()
        .resolve()
        .unwrap();
    eprintln!("s: {:?}", s);
}

yields:

failures:

---- config::hocon_and_serde_default stdout ----
thread 'config::hocon_and_serde_default' panicked at 'called `Result::unwrap()` on an `Err` value: Deserialization { message: "missing float for
field String(\"size\")" }', src/libcore/result.rs:1165:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.


failures:
    config::hocon_and_serde_default

What should happen is the serde machinery will compute a default value and that should be used instead of generating an error.

@wez
Copy link
Contributor Author

wez commented Nov 22, 2019

The workaround is a little unpleasant but not the worst thing ever:

fn hocon_to_json(hocon: hocon::Hocon) -> Fallible<serde_json::Value> {
    use serde_json::{Map, Number, Value};
    match hocon {
        Hocon::Boolean(b) => Ok(Value::Bool(b)),
        Hocon::Integer(i) => Ok(Value::Number(Number::from(i))),
        Hocon::Real(f) => Ok(Value::Number(Number::from_f64(f).ok_or_else(|| {
            format_err!("{} cannot be converted to serde_json::Number", f)
        })?)),
        Hocon::String(s) => Ok(Value::String(s)),
        Hocon::Array(vec) => {
            let mut res = vec![];
            for v in vec.into_iter() {
                res.push(hocon_to_json(v)?);
            }
            Ok(Value::Array(res))
        }
        Hocon::Hash(map) => {
            let mut res = Map::new();
            for (k, v) in map.into_iter() {
                res.insert(k, hocon_to_json(v)?);
            }
            Ok(Value::Object(res))
        }
        Hocon::Null => Ok(Value::Null),
        Hocon::BadValue(err) => bail!("bad hocon value: {}", err),
    }
}

let hocon = file
    .hocon()
    .map_err(|e| format_err!("Error parsing HOCON from {}: {}", p.display(), e))?;

// convert to json
let json = hocon_to_json(hocon)?;
let json_text = serde_json::to_string(&json)?;
// use the json deserialize implementation to populate the struct
let cfg: MyStruct = serde_json::from_str(&json_text)
    .map_err(|e| format_err!("Error parsing HOCON from {}: {}", p.display(), e))?;

@mockersf
Copy link
Owner

thank you, that's fixed for the next release

@wez
Copy link
Contributor Author

wez commented Nov 23, 2019

Thanks!

FWIW, I tried this against my Config type and encountered one of the unimplemented! cases in src/serde/de.rs; that's technically a separate issue from this one, and I can write that up separately.

@mockersf
Copy link
Owner

mockersf commented Nov 23, 2019

I actually know now how to remove all the remaining unimplemented! in deserialisation but I forgot about them.

I'll get them fixed in the next few days, thanks for reminding me

@mockersf
Copy link
Owner

Only unimplemented!()remaining are in deserialize_bytes and deserialize_byte_buf which I think are not really useful for configuration or in hocon...

@wez
Copy link
Contributor Author

wez commented Nov 25, 2019

Thanks this is better!

@wez wez closed this as completed Nov 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants