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(default) does not apply for empty fields in csv format #2478

Closed
ronniec95 opened this issue Jun 17, 2023 · 2 comments
Closed

serde(default) does not apply for empty fields in csv format #2478

ronniec95 opened this issue Jun 17, 2023 · 2 comments
Labels

Comments

@ronniec95
Copy link

    #[derive(Debug, serde::Deserialize)]
    struct Test {
        symbol: String,
        #[serde(default)]
        up: f64,
    }

    #[test]
    fn deserialise_empty_up() {
        let s = "symbol,up\ndfsdfws,";

        let mut rdr = csv::Reader::from_reader(s.as_bytes());
        for row in rdr.deserialize() {
            let option: Test = row.expect("Failure");
            dbg!(&option);
        }
    }

The field up is empty in the string; this should default to 0.0; but instead it fails with

thread 'tests::deserialise' panicked at 'Failure: Error(Deserialize { pos: Some(Position { byte: 10, line: 2, record: 1 }), err: DeserializeError { field: Some(1), kind: ParseFloat(ParseFloatError { kind: Empty }) } })', data_model\examples\upload_options.rs:89:36

Setting it to 0.0 works fine

Using
serde = { version = "^1.0", features = ["derive"] }

@Mingun
Copy link
Contributor

Mingun commented Jun 18, 2023

I think, this is mostly rust-csv issue. #[serde(default)] applied only to missed fields. It is up to rust-csv to say whether field exist or not in CSV data. It decides that if field is declared in the header it is exist.

It could be hard to fix this error only on rust-csv side, because proper solution dependent also on the deserialized type. For example, for String empty string is a valid data and you probably does not want, that you will not be able to deserialize empty strings without #[serde(default)] on the string field. From the other hand for f64 empty string is invalid data. Probably this can be solved by having a setting in the rust-csv for selecting a behaviour (treat_empty_fields_as_missing).

@dtolnay
Copy link
Member

dtolnay commented Jul 9, 2023

Alternative to requesting csv crate changes, I think your best bet would be to parse the f64 from string yourself.

use serde::{Deserialize, Deserializer};
use std::fmt::Display;
use std::str::FromStr;

#[derive(Debug, serde::Deserialize)]
struct Test {
    symbol: String,
    #[serde(deserialize_with = "deserialize_empty_as_default")]
    up: f64,
}

fn deserialize_empty_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
    T: Default + FromStr,
    T::Err: Display,
{
    let repr = String::deserialize(deserializer)?;
    if repr.is_empty() {
        Ok(T::default())
    } else {
        repr.parse().map_err(serde::de::Error::custom)
    }
}

@dtolnay dtolnay closed this as completed Jul 9, 2023
@dtolnay dtolnay added the support label Jul 9, 2023
@dtolnay dtolnay changed the title serde(default) appears to fail on a simple struct serde(default) does not apply for empty fields in csv format Jul 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

3 participants