-
Notifications
You must be signed in to change notification settings - Fork 237
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
Option<bool> doesn't (de)serialize properly with serde #497
Comments
Test case minimized from djkoloski/rust_serialization_benchmark#34 |
This is using the current master branch ^^ |
This bug is not specific to <root/> <!-- (1) None -->
<root><element/></root> <!-- (2) ? -->
<root><element>$DATA</element></root> <!-- (3) Some(...) --> While result for (1) and (3) are pretty obvious, that is hard to say for (2). The JSON equivalent of that structs is {}
{ "element": null }
{ "element": $DATA } How we should map the case (2)? quick-xml currently does the opposite: it always deserializes to Fixing that likely will have a consequence, that |
Would it be possible to use a special attribute value, e.g. |
I would try to avoid that and use |
Actually, that case is much more complex then I thought initially. It is unclear, how to process cases like <element attribute="..."/> At time of deciding if we should return struct Struct {
#[serde(rename = "@attribute")]
attribute: (),
} then this XML snippet are definitely not Because of the nature of XML we like to keep ability to deserialize things like <element attribute="...">
content
</element> into a String {
"@attribute": "...",
"$text": "content"
} and could not be deserialized into a <element attribute="..."/> into an <element/> which suggested to be |
Is there any update on this, or maybe some kind of workaraound? Currently the only way I cound get the serialization of an optional value to work is when the target type is |
The simplest workaround I found if you control both the serializing and de-serializing parts is to use the following serde attributes: This problem is still quite bothersome though... |
To me this is not a good solution because I rely on multiple storage solutions (eg. Json, Ron, Sled) with the same (de)-serialization. I am mostly concerned with round-trips |
You have problems in round-trips in JSON too, and I think in any other format, they just different. If take JSON as a base point, at least |
Yes I am aware that perfect round-trips are problematic in json as well. However, this MWE does work: use serde::{Deserialize, Serialize};
fn main() {
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
struct Identifier {
parent: Option<u64>,
}
let ident = Identifier { parent: None, };
let json_string = serde_json::to_string(&ident).unwrap();
let ident2: Identifier = serde_json::from_str(&json_string).unwrap();
assert_eq!(ident, ident2);
} which is my main concern at this point in time. |
Hello, I had a similar issue and would like to share my solution if it is of help to anyone in the future. I wanted an element like ExampleInitial Content: <MyStruct>
<some_field>123</some_field>
<my_flag/>
</MyStruct> Deserialized Struct: MyStruct {
some_field: 123,
my_flag: true,
} Reserialized XML: <MyStruct>
<some_field>123</some_field>
<my_flag/>
</MyStruct> Initial Content: <MyStruct>
<some_field>123</some_field>
</MyStruct> Deserialized Struct: MyStruct {
some_field: 123,
my_flag: false,
} Reserialized XML: <MyStruct>
<some_field>123</some_field>
</MyStruct> Codeuse serde::{Deserialize, Serialize};
/// Used to skip adding boolean flag, such as `<some_boolean_flag/>`, when `false`
/// ```no_run
/// #[serde(skip_serializing_if = "is_false")]
/// ```
fn is_false(value: &bool) -> bool {
!value
}
/// When a flag, such as `<some_boolean_flag/>`, is present, return `true`, else, return `false`
/// ```no_run
/// #[serde(deserialize_with = "deserialize_flag")]
/// ```
fn deserialize_flag<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
D: serde::Deserializer<'de>,
{
let opt: Option<()> = Option::deserialize(deserializer)?;
Ok(opt.is_some())
}
/// Will output an XML element, such as `<some_boolean_flag/>`, when `true` and nothing when `false`
/// ```no_run
/// #[serde(serialize_with = "serialize_flag")]
/// ```
/// Note: Output may look different based upon XML parser
/// - serde_xml_rs: `<some_boolean_flag />`
/// - quick_xml: `<some_boolean_flag/>`
fn serialize_flag<S>(flag: &bool, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if *flag {
serializer.serialize_unit()
} else {
serializer.serialize_none()
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct MyStruct {
some_field: i32,
#[serde(
default, // set to `false` when Deserialize errors because flag is absent
deserialize_with = "deserialize_flag",
serialize_with = "serialize_flag",
skip_serializing_if = "is_false"
)]
my_flag: bool,
} |
Hummm I find it very disturbing that roundtrip is not ensured by default. +1 for fixing this. |
So I may be a bit naive, but to summarize my thoughts: I think it's extremely important (a fundamental use case of any serialization library) to support roundtrips of the form assert_eq!(
x,
quick_xml::de::from_str(&quick_xml::se::to_string(&x).unwrap()).unwrap()
); Importantly, we do NOT need to support roundtrips of the form |
I agree with the round-trips However this is just my feedback. My current solution has been to deprecate xml for my application but I would like to introduce it again later if possible. |
Using the following code:
The code crashes during the deserialize step
If instead
spawn_forced
is set toSome(true)
orSome(false)
, it works fine. OnlyNone
, which serializes to<spawn_forced/>
, panics upon deserialization.The text was updated successfully, but these errors were encountered: