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

Add serde attribute try_from #1526

Merged
merged 1 commit into from Jul 17, 2019
Merged

Add serde attribute try_from #1526

merged 1 commit into from Jul 17, 2019

Conversation

fanzeyi
Copy link
Contributor

@fanzeyi fanzeyi commented May 12, 2019

This pull request adds a new serde attribute try_from which will make serde try to convert the type specified in the attribute to the type serde is trying to deserialize into. (#1524)

For example,

use serde::Deserialize;
use serde_json;
use std::convert::TryFrom;

#[derive(Deserialize, Debug)]
#[serde(try_from = "u32")]
enum Color {
    Red,
}

impl TryFrom<u32> for Color {
    type Error = String;

    fn try_from(value: u32) -> Result<Self, Self::Error> {
        if value > 10 {
            Err("out of range".into())
        } else {
            Ok(Color::Red)
        }
    }
}

fn main() {
    let result: Color = serde_json::from_str("2").unwrap();
    println!("result = {:?}", result);
    let _: Color = serde_json::from_str("100").unwrap();
}

will produce the following output:

result = Red
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("out of range", line: 0, column: 0)', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

Details

  • serde_derive will generate the try_from call when generating deserializing code
  • The generated code will map the result type to a call to serde::Error::custom
  • Similar to from attribute, try_from is incompatible with transparent
  • from and try_from attributes cannot be specified at the same time

@fanzeyi
Copy link
Contributor Author

fanzeyi commented May 12, 2019

Hmm... This will break serde's backward compatibility (1.13+) as try_from / try_into just stabilized 😢

Would it be acceptable to make it a feature?

@bluebear94
Copy link

Would it be possible to make this feature conditionally available to versions that support TryFrom?

@davidbarsky
Copy link

@fanzeyi Hi! I'm not a maintainer, but looking at how the alloc feature is supported in Serde on Rust versions later than 1.36, I can somewhat confidently infer that placing the try_from behind a feature flag is the correct approach. Depending on how much time you have, I'd be happy to do this myself in a separate PR that builds atop of yours.

@fanzeyi
Copy link
Contributor Author

fanzeyi commented Jul 17, 2019

@davidbarsky Let me ask @dtolnay today.

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this implementation looks good to me. We use a build script to provide things like this only on compilers that support them, without needing a feature -- see f249e72.

@dtolnay dtolnay merged commit 4c29eea into serde-rs:master Jul 17, 2019
@davidbarsky
Copy link

Ah, my bad for misunderstanding. Thanks for the clarification!

@jhpratt
Copy link

jhpratt commented Apr 20, 2020

@dtolnay Slightly odd request, but would it be possible to allow a custom TryFrom implementation for back-compatibility? I was looking into dropping the MSRV for the time crate from 1.34 to 1.32, and am using TryFrom via standback. Standback just copies code from std/core as appropriate, so it's generally compatible.

If it's not possible, I suppose I could write out what is currently derived. I presume it isn't too common to do this, though.

Edit: Actually, it looks simple enough to forward this manually that it probably isn't necessary to do this.

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

Successfully merging this pull request may close these issues.

None yet

5 participants