Crate derive_serialize_into [−] [src]
Derive Serialize
and Deserialize
for wrapper types
This crate provides several custom derives that provide implementations of
serde's Serialize
and Deserialize
traits for wrapper types, as well as
Deserialize
implementations that perform some validation.
Sometimes you have a single-field type
struct Contact { email: String, }
which you want to serialize and deserialize as a string instead of a struct, e.g. you want its
JSON representation to just be ""user@domain.com"
" instead of
"{ "email": "user@domain.com" }
". You can derive Serialize
and Deserialize
implementations
for that purpose, as well as Into
and From
implementations to convert between String
and
Contact
.
Another example is a validated wrapper type like
struct Email(String);
that should never be instantianted with a string that doesn't represent a valid email address.
If you implement Email: TryFrom<String>
using the
try_from crate, such that conversion fails for invalid
addresses, the derived Deserialize
will also fail if the string is in the wrong format.
Supported derive attributes
#[derive(IntoInner)]
On structures T
with a single field of type S
, this creates an impl From<&T> for &S
that
returns a reference to the field.
#[derive(FromInner)]
On structures T
with a single field of type S
, this creates an impl From<S> for T
.
#[derive(SerializeInto)]
On structures T
, given an impl Into<S> for &T
, this creates an impl Serialize for T
which
first converts to S
and then serializes it. If #[serialize_into(S)]
is not specified and
T
is a structure with a single field, it uses a reference to that field's type as S
.
#[derive(DeserializeFrom)]
On structures T
, given an impl Into<T> for S
, this creates an impl Deserialize for T
which first deserializes to S
and then converts to T
. If #[deserialize_from(S)]
is not
specified and T
is a structure with a single field, it uses that field's type as S
.
#[derive(DeserializeTryFrom)]
On structures T
, given an impl TryInto<T> for S
, this creates an impl Deserialize for T
which first deserializes to S
and then converts to T
. If #[deserialize_from(S)]
is not
specified and T
is a structure with a single field, it uses that field's type as S
.
Deserialization fails if conversion from S
to T
fails. The TryInto
implementation's error
type must implement Display
and will be converted to a custom deserialization error.
Example: simple wrapper types
#[macro_use] extern crate derive_serialize_into; extern crate serde; extern crate serde_json; #[derive(DeserializeFrom, FromInner, IntoInner, SerializeInto, Debug, Eq, PartialEq)] struct Seconds(i64); #[derive(DeserializeFrom, FromInner, IntoInner, SerializeInto, Debug, Eq, PartialEq)] struct Days { number: i64, } fn main() { assert_eq!(Seconds(5), serde_json::from_str("5").unwrap()); assert_eq!("5", &serde_json::to_string(&Seconds(5)).unwrap()); assert!(serde_json::from_str::<Seconds>("nan").is_err()); assert_eq!(Days { number: 5 }, serde_json::from_str("5").unwrap()); assert_eq!("5", &serde_json::to_string(&Days { number: 5 }).unwrap()); assert!(serde_json::from_str::<Days>("nan").is_err()); }
Example: validated email addresses
#[macro_use] extern crate derive_serialize_into; extern crate serde; extern crate serde_json; extern crate try_from; extern crate validator; #[derive(DeserializeTryFrom, IntoInner, SerializeInto, Debug, Eq, PartialEq)] struct Email(String); impl try_from::TryFrom<String> for Email { type Err = &'static str; fn try_from(raw: String) -> Result<Email, &'static str> { if validator::validate_email(&raw) { Ok(Email(raw)) } else { Err("invalid email address") } } } fn main() { let email_json = r#""user@domain.com""#; let email = Email("user@domain.com".to_string()); assert_eq!(email, serde_json::from_str(email_json).unwrap()); assert_eq!(email_json, &serde_json::to_string(&email).unwrap()); assert!(serde_json::from_str::<Email>(r#""missing_at_sign""#).is_err()); }
Example: custom TryFrom
and Into
#[macro_use] extern crate derive_serialize_into; extern crate serde; extern crate serde_json; extern crate try_from; #[derive(DeserializeTryFrom, SerializeInto, Debug, Eq, PartialEq)] #[serialize_into(String)] #[deserialize_from(String)] enum Money { Eur(u64), Usd(u64), } impl try_from::TryFrom<String> for Money { type Err = &'static str; fn try_from(s: String) -> Result<Money, &'static str> { let amt_str: String = s.chars().skip(1).collect::<String>(); let amt = amt_str.parse().map_err(|_| "invalid amount")?; match s.chars().next() { Some('€') => Ok(Money::Eur(amt)), Some('$') => Ok(Money::Usd(amt)), _ => Err("invalid currency"), } } } impl<'a> From<&'a Money> for String { fn from(money: &Money) -> String { match *money { Money::Eur(amt) => format!("€{}", amt), Money::Usd(amt) => format!("${}", amt), } } } fn main() { assert_eq!(Money::Eur(5), serde_json::from_str(r#""€5""#).unwrap()); assert_eq!(r#""$5""#, &serde_json::to_string(&Money::Usd(5)).unwrap()); assert!(serde_json::from_str::<Money>(r#""8""#).is_err()); }