jonasbb / serde_with

This crate provides custom de/serialization helpers to use in combination with serde's `with`-annotation and with the improved `serde_as`-annotation.
https://docs.rs/serde_with
Apache License 2.0
667 stars 72 forks source link

`DefaultOnError` falls back to default unexpectedly #756

Closed Skgland closed 5 months ago

Skgland commented 5 months ago

Attempting to roundtrip a value fails for the Bug struct in the reduced example below while it works for Working, the only difference being the DefaultOnError on the field field in Bug.

I would have expected both tests to pass but only test_working does.

use serde_with::{serde_as, DefaultOnError};

#[derive(Debug, Default, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Enum {
    #[default]
    A,
    B,
}

#[serde_as]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
pub struct Bug {
    #[serde_as(as = "DefaultOnError")]
    #[serde(default)]
    pub field: Enum,
}

#[serde_as]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
pub struct Working {
    #[serde(default)]
    pub field: Enum,
}

#[test]
fn test_bug() {
    let val = Bug{
        field: Enum::B,
    };
    let data = ron::to_string(&val).unwrap();
    let nval = ron::from_str(&data).unwrap();
    assert_eq!(val, nval)
}

#[test]
fn test_working() {
    let val = Working{
        field: Enum::B,
    };
    let data = ron::to_string(&val).unwrap();
    let nval = ron::from_str(&data).unwrap();
    assert_eq!(val, nval)
}
[package]
name = "serde_with_bug"
version = "0.1.0"
edition = "2021"

[dependencies]
ron = "0.8.1"
serde = { version = "1.0.203", features = ["derive"] }
serde_with = "3.8.1"
jonasbb commented 5 months ago

ron doesn't support round when a Value type is involved (e.g., for buffering). https://github.com/ron-rs/ron/issues/397 That is a general issue with serde https://github.com/serde-rs/serde/issues/1183. Unfortunately, internal buffering is necessary for DefaultOnError to work. You cannot recover from Deserializer errors, as the Deserializer might be in an indeterminate state. The way around that is to deserialize into a type that will not fail, and then attempt to deserialize that into the target type.

Skgland commented 5 months ago

Ah, ok, looks like this is a known issue with serde/ron then.