-
Notifications
You must be signed in to change notification settings - Fork 123
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
Nested untagged and externally tagged enums fail to deserialize #217
Comments
I've tracked this down to relate to the implementation of /// Called from `deserialze_any` when a struct was detected. Decides if
/// there is a unit, tuple or usual struct and deserializes it
/// accordingly.
///
/// This method assumes there is no identifier left.
fn handle_any_struct<V>(&mut self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
// Create a working copy
let mut bytes = self.bytes;
match bytes.consume("(") {
true => {
bytes.skip_ws()?;
match bytes.check_tuple_struct()? {
// first argument is technically incorrect, but ignored anyway
true => self.deserialize_tuple(0, visitor),
// first two arguments are technically incorrect, but ignored anyway
false => self.deserialize_struct("", &[], visitor),
}
}
false => visitor.visit_unit(),
}
} This function (through I'm having trouble correcting the implementation, however. I'm not able to determine whether the value is an enum variant or a unit struct without additional context, and my knowledge of Edit: I believe it's not possible to correctly fix this bug with the current way |
Thank you, this is great investigation! Please consider filing an issue on Serde for clarification or tracking of making this possible, if it's not filed yet. |
I found a possibly related weirdness: The following code fails to deserialize the CountUnit case but if you replace I was able to reproduce this on the newest master. use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
pub enum UnitType {
Explorer,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum CardTextNumberFlat {
JustNum(u8),
RangeW(Range_),
CountUnitW(CountUnit_),
PowerCardsPlayedW(PowerCardsPlayed),
}
#[derive(Serialize, Deserialize, Debug)]
struct Range_{ Range: u8 }
#[derive(Serialize, Deserialize, Debug)]
struct CountUnit_{ CountUnit: Vec<UnitType> }
#[derive(Serialize, Deserialize, Debug)]
struct PowerCardsPlayed;
fn main() {
let x = ron::to_string(&CardTextNumberFlat::CountUnitW(CountUnit_{CountUnit: vec![UnitType::Explorer]}));
let y = ron::to_string(&CardTextNumberFlat::RangeW(Range_{Range: 1}));
println!("{} {}", x.unwrap(), y.unwrap());
let x: CardTextNumberFlat = ron::from_str("Range(1)").unwrap();
let y: CardTextNumberFlat = ron::from_str("CountUnit([Explorer])").unwrap();
println!("{:?} {:?}", x, y);
} |
It seems that serde translates maps gotten from deserialize_any into almost anything... I was unable to find documentation on this. The documentation on untagged enums says that serde tries each variant. That is not true. I went through it with gdb and found that it only deserializes once, which is why it needs to use deserialize_any. I think that ron should return maps instead of structs, as there is no way to know if "A(B)" is a struct or an enum variant. The below code shows how you can write maps instead of enums. use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
pub enum UnitType {
Explorer,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum CardTextNumber {
Constant(u8),
Range(u8),
CountUnit(Vec<UnitType>),
PowerCardsPlayed,
}
use CardTextNumber::*;
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum CardTextNumberFlat {
JustNum(u8),
Fancy(CardTextNumber),
}
fn main() {
let x: CardTextNumberFlat = ron::from_str("{\"CountUnit\": [\"Explorer\"]}").unwrap();
println!("{:?}", x);
} |
Any update on this? |
Thank you @caelunshun and @joonazan for providing very good test cases - I just stumbled across the issue and added a test and it seems like #451 fixed the issue.
That is very true but, unfortunately, I don't think RON can do anything about this "serde-backdoor" for transforming a map into almost anything if it goes through |
Add a test to confirm that #217 is fixed
The following example deserializes an untagged enum with two variants using
ron
,serde_json
, andserde_yaml
. The latter two libraries output the expected result, but RON fails with a "data did not match any variant of untagged enum Either" error.The text was updated successfully, but these errors were encountered: