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

Cannot deserialize None value into a unit struct #12

Open
tenuous-guidance opened this issue Mar 17, 2023 · 2 comments
Open

Cannot deserialize None value into a unit struct #12

tenuous-guidance opened this issue Mar 17, 2023 · 2 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@tenuous-guidance
Copy link
Contributor

Consider the following types:

#[derive(Debug, Deserialize)]
struct Config {
    var: Var,
}

#[derive(Debug, Deserialize)]
struct Var(Option<usize>);

I want to set the Config to { var: Var(None) }, how do I do so?

Options I have tried:

  • Unsetting var (this works with var: Option<usize> and so is what I'd expect to work here),
  • Setting var to None,
  • Setting var to "" (the empty string),
  • Unsetting var_0,
  • Setting var_0 to None,
  • Setting var_0 to "" (the empty string).

Example test case:
Dependencies:

[dependencies]
envious = { version = "0.1.1" }
serde = { version = "1", features = ["derive"], default-features = false }

[dev-dependencies]
temp-env = "0.3"

Code:

use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct Config {
    var: Var,
}

#[derive(Debug, Deserialize)]
struct Var(Option<usize>);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn unset() {
        temp_env::with_var("var", Option::<String>::None, || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn empty() {
        temp_env::with_var("var", Some(""), || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn none() {
        temp_env::with_var("var", Some("None"), || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn set_0() {
        temp_env::with_var("var_0", Some("1"), || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn unset_0() {
        temp_env::with_var("var_0", Option::<String>::None, || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn empty_0() {
        temp_env::with_var("var_0", Some(""), || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }

    #[test]
    fn none_0() {
        temp_env::with_var("var_0", Some("None"), || {
            envious::from_env::<Config>(envious::Prefix::None).unwrap();
        })
    }
}
@TheNeikos
Copy link
Owner

This is an interesting case.

So the problem stems broadly from the fact that environment variables can either not exist or be a &str.

JSON for example has the null value, which would help deal with it here.

I am not sure how to solve it from envious's side. One thing that should work for you, is if you give it a default that returns a None?

@TheNeikos TheNeikos added bug Something isn't working help wanted Extra attention is needed labels Mar 17, 2023
@tenuous-guidance
Copy link
Contributor Author

It looks like it can work with:

#[derive(Debug, Deserialize)]
struct Config {
    #[serde(default)] 
    var: Var,
}

#[derive(Default, Debug, Deserialize)]
struct Var(Option<usize>);

Might be that's the best that can be done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants