serde_qs: Cannot use derived Deserialize impl for enums
When trying to deserialize a query string containing enum values encoded as strings, it fails with an “enum expected” error message.
Here’s a repro code (with deserialization via serde_json thrown in for comparison):
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate serde_qs;
#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
enum TestEnum { Foo, Bar }
#[derive(Deserialize, Debug)]
struct TestStruct {
e: TestEnum,
}
fn main() {
println!("serde_json: {:?}", serde_json::from_str::<TestStruct>(r#"{"e": "foo"}"#));
println!("serde_qs: {:?}", serde_qs::from_str::<TestStruct>("e=foo"));
}
This produces:
serde_json: Ok(TestStruct { e: Foo })
serde_qs: Err(Error { err: "invalid type: string \"foo\", expected enum TestEnum" })
If we don’t use #[derive(Deserialize)]
however, and implement it manually for the enum type (like here), the enums will be correctly deserialized.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 28 (14 by maintainers)
Commits related to this issue
- Finish refactor work. Allows serializing/deserializing enums as requested in issue #6. — committed to samscott89/serde_qs by samscott89 7 years ago
It seems like there is a misunderstanding about what the various Deserializer methods mean. In particular, in this code https://github.com/Xion/rofld/commit/dca9e0e40f15c7998dc2421cf5dcbf19b6df4eda#diff-362ff1d9014c27059ccc2de11400e306 neither the “before” nor “after” code makes sense to me.
In the “before” code, the
deserialize_tuple_struct
method means that the type’s representation in the Serde data model is a tuple struct, i.e. the Deserializer should follow up with a call tovisit_seq
. The bug in the original code is thatvisit_seq
is not implemented on the relevant Visitor.In the “after” code, I don’t understand the lookhead enum thing. It is equivalent to calling
deserializer.deserialize_any(ColorVisitor)
.Basically if your Deserialize implementation knows the Serde data model representation of the type that the input contains, call the right Deserializer method. If the Deserializer needs to figure it out, call
deserialize_any
.I skimmed the discussion and it sounds like
serde_qs
had the correct behavior all along since the first refactor in https://github.com/samscott89/serde_qs/issues/6#issuecomment-302934235, and the user’s Deserialize impl was badly behaved.Ah, it may very well be that this is in fact the correct way. I remember reading through the custom deserializers’ examples in Serde docs and thinking “wait, this is doing it in a roundabout way, I can make it shorter”, so it’s likely I have taken some (too radical) shortcuts 😃
I’ll try this when I get home.
Hey, Currently we only support tagged enums (see the example: https://github.com/samscott89/serde_qs/blob/master/examples/introduction.rs#L135).
So you could have the following:
I will revisit the logic though, because it should at least be possible to deserialize UnitVariants as in your example.