-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot deserialize with Struct without fields #461
Comments
How would you specify that in a configuration file? |
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct A {
b: Option<B>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct B {}
impl Default for A {
fn default() -> Self {
Self { b: Some(B {}) }
}
}
let a = A::default();
let toml_str = toml::to_string(&a).unwrap();
println!("toml str: {}", toml_str);
// let de_from_toml = toml::from_str::<A>(&toml_str).unwrap();
// assert_eq!(a, de_from_toml); // Passed
let de_from_toml: A = Config::builder()
.add_source(File::from_str(&toml_str, FileFormat::Toml))
.build()
.unwrap()
.try_deserialize()
.unwrap();
assert_eq!(a, de_from_toml); // Passed
let de_from_default_object: A = Config::builder()
.add_source(Config::try_from(&a).unwrap())
.build()
.unwrap()
.try_deserialize()
.unwrap();
assert_eq!(a, de_from_default_object); // Failed Output:
|
And again I ask: How would you specify a instance of |
Just like the previous example, for toml file, I specify it like this: [b] |
Ah, I missed that bit. Hnm, indeed that's an issue. Thanks for reporting! |
Adds a test for an empty inner object as reported in rust-cli#461. Reported-by: Zhenchi <[email protected]> Signed-off-by: Matthias Beyer <[email protected]>
I opened #463 with a testcase for this issue. If you have an idea solving that problem, you're of course very much welcome! |
The scenarios that cause #[derive(Debug, Serialize, Deserialize, PartialEq)]
struct A {
b_option: Option<B>,
b_vec: Vec<B>,
b_set: HashSet<B>,
b_map: HashMap<String, B>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
struct B {}
let a = A {
b_option: Some(B {}),
b_vec: vec![B {}],
b_set: HashSet::from([B {}]),
b_map: HashMap::from([("".to_owned(), B {})]),
};
// Serialize that `a` with `ConfigSerializer` will produce an empty config
let config = Config::try_from(&a).unwrap(); |
TL;DR: Looks like this can be resolved easily enough with the below bolded fixes. NOTE: Depending on when this is acted on, the referenced snippets below may change due to #465 (suggested fixes remain compatible, other referenced snippets may be refactored) Note that there is two ways to define a unit-like struct (technically more?): // Officially documented way:
// https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
// https://learning-rust.github.io/docs/structs/
struct B;
// RFC:
// https://rust-lang.github.io/rfcs/0218-empty-struct-with-braces.html
// Previously not supported: https://github.com/rust-lang/rfcs/pull/147#issuecomment-47589168
// Accepted 2015: https://github.com/rust-lang/rfcs/pull/218#issuecomment-91558974
// Stabilized 2016: https://github.com/rust-lang/rust/issues/29720#issuecomment-189523437
struct B {} These are roughly the same but have some differences. If you omit the
Even though it does reach Fix: Instead of // Call this instead:
self.serialize_primitive(Value::from(crate::value::Table::new())) EDIT: This fails to deserialize the unit struct properly with error: It requires adding an additional deserialize method for #[inline]
fn deserialize_unit_struct<V: de::Visitor<'de>>(self, _name: &'static str, visitor: V) -> Result<V::Value> {
visitor.visit_unit()
}
This is also Fix: A similar fix here is to also create a table, presumably only when // Struct is empty (unit struct with empty braces):
if len == 0 {
self.serialize_primitive(Value::from(crate::value::Table::new()))?;
}
// Keep the original call:
self.serialize_map(Some(len)) In both cases, I assume the expected serialization is what I've observed the deserialized format to Applying either fix for that as suggested above now serializes the unit struct type option successfully, which will properly deserialize the option (since Deserialization isn't an issue without the Option wrapping type, since The value prior to calling
I assume directly after this call it's converted to the unit struct, but I'm not sure how that works 😅 |
The text was updated successfully, but these errors were encountered: