Skip to content
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

#[serde(flatten)] broken when field isn't String #112

Closed
Bindernews opened this issue Sep 10, 2019 · 6 comments
Closed

#[serde(flatten)] broken when field isn't String #112

Bindernews opened this issue Sep 10, 2019 · 6 comments
Labels

Comments

@Bindernews
Copy link

Problem

I'm trying to deserialize TMX files both from JSON and XML, so I made a struct of common fields and used #[serde(flatten)] to include the common fields in both my JSON and XML structures. It works fine for JSON, but I get the error Error(Custom("invalid type: string \"3\", expected isize"), State { next_error: None, backtrace: None }). It's not correctly detecting that the string "3" is an isize. It DOES work when I'm not using flatten and the field is in the main object.

Investigation

I stepped through it in a debugger, and although it wasn't perfect, I believe I narrowed down the issue a bit. deserialize_struct calls visit_map to do all the work. I believe what's happening is that deserialize_map for the flattened struct is being called assuming it's trying to deserialize to a HashMap or BTreeMap, as opposed to a struct.

I'm not fully certain this is the issue as the macros and compiler optimizations (even in debug mode) interfered with my debugging.

Improvement

I'm willing to work on fixing this, but I'll probably need to have a chat with someone to help me understand how the code is organized, as I'm having a little trouble following it.

Misc

Probably related to #83

@punkstarman
Copy link
Collaborator

Without at least a minimal example of code showing what you are trying to accomplish, I will have a hard time helping.

I can suggest that you investigate whether the problem is on the side of this crate or of serde-derive. One thing that I have found helpful is printing the code that serde-derive generates.

cargo +nightly rustc -- -Z unstable-options --pretty=expanded

Using the --test, --bin or --lib options restricts compiling to only certain parts.

@Bindernews
Copy link
Author

I'll post a minimal example once I have some time to trim down the code. I'll also take a look at the generated derive code, you may be correct.

@Bindernews
Copy link
Author

Alright I've gotten it down to a minimal example (see attached). If you unzip the project and run cargo test, the "working" test should succeed and the "broken" test should fail.

I'm trying to track down if there's a difference in the serde_derive generated code that might cause the issue.

serde-xml-debug.zip

@Bindernews
Copy link
Author

After some digging it seems that serde generates a deserialize_map call when including #[serde(flatten)] fields. Since all XML fields are strings by default and serde-xml-rs doesn't try to parse any attributes into integers, floats, etc., it builds a map of names to String values, which then causes errors when it calls visit_string.

If serde-xml-rs were to try to guess the attribute type (e.g. test if the string parses as an integer), then that would probably fix my problem, but on the whole the issue lies more on the side of serde-derive.

@punkstarman
Copy link
Collaborator

Guessing datatypes doesn't seem appropriate since XML itself only specifies character based literals: strings, character references, entity references. Unlike YAML or JSON, in XML the only way to distinguish the string 12345 from the number 12345 is to apply a schema.

@andrey-yantsen
Copy link

For future generations: you can use serde_aux::field_attributes::deserialize_number_from_string as creepy workaround for numeric types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants