Support for serde::Serialize

rename
Pantonshire 5 years ago
parent 867b09a1fe
commit 46dac98882

@ -9,3 +9,7 @@ description = "Procedural macros for converting between enums and strings"
[dependencies]
enumscribe_derive = { version = "0.1.0", path = "../enumscribe_derive" }
[features]
default = ["serde"]
serde = ["enumscribe_derive/serde"]

@ -6,8 +6,8 @@
//! | `ignore` used? | `other` used? | Conversion to string | Conversion from string |
//! |----------------|---------------|----------------------|------------------------|
//! | No | No | [ScribeStaticStr] | [TryUnscribe] |
//! | Yes | No | [TryScribeStaticStr] | [TryUnscribe] |
//! | No | Yes | [ScribeCowStr] | [Unscribe] |
//! | Yes | No | [TryScribeStaticStr] | [TryUnscribe] |
//! | Yes | Yes | [TryScribeCowStr] | [Unscribe] |
//!
//! There are also [ScribeString] and [TryScribeString] traits which can be used in the same

@ -15,6 +15,5 @@ proc-macro2 = "1.0"
syn = "1.0"
quote = "1.0"
[dev-dependencies]
serde = "1.0"
serde_json = "1.0"
[features]
serde = []

@ -2,7 +2,6 @@
//! to strings and vice-versa.
use proc_macro::TokenStream;
use std::iter;
use proc_macro2::Ident;
use quote::quote;
@ -10,7 +9,7 @@ use syn::{Data, DataEnum, DeriveInput};
use error::{MacroError, MacroResult};
use crate::enums::{Variant, VariantType, VariantConstructor};
use crate::enums::{Variant, VariantType};
mod enums;
mod attribute;
@ -422,6 +421,89 @@ pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
)
}
#[cfg(feature = "serde")]
#[proc_macro_derive(EnumSerialize, attributes(enumscribe))]
pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
let input: DeriveInput = syn::parse(input)
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
let enum_ident = &input.ident;
let serializer_ident = quote! { __enumscribe_serializer };
let mut match_arms = Vec::new();
let mut ignore_variant = false;
for variant in parsed_enum.variants.iter() {
let variant_ident = &variant.data.ident;
match &variant.v_type {
VariantType::Ignore => ignore_variant = true,
VariantType::Named { name, constructor, .. } => {
let constructor_tokens = constructor.empty();
match_arms.push(quote! {
#enum_ident::#variant_ident #constructor_tokens =>
#serializer_ident.serialize_str(#name)
})
},
VariantType::Other { field_name } => {
match field_name {
Some(field_name) => {
match_arms.push(quote! {
#enum_ident::#variant_ident { #field_name } =>
#serializer_ident.serialize_str(&#field_name)
})
},
None => {
let field_name = quote! { __enumscribe_other_inner };
match_arms.push(quote! {
#enum_ident::#variant_ident(#field_name) =>
#serializer_ident.serialize_str(&#field_name)
})
}
}
}
}
}
let ignore_arm = if ignore_variant {
let err_string = format!(
"attempted to serialize an unserializable variant of {}",
enum_ident
);
quote! {
_ => ::std::result::Result::Err(
::serde::ser::Error::custom(#err_string)
)
}
} else {
quote! {}
};
(quote! {
impl ::serde::Serialize for #enum_ident {
fn serialize<S>(&self, #serializer_ident: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::Serializer
{
match self {
#(#match_arms,)*
#ignore_arm
}
}
}
}).into()
}
#[cfg(feature = "serde")]
#[proc_macro_derive(EnumDeserialize, attributes(enumscribe))]
pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
todo!()
}
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
let enum_data = match &input.data {
Data::Enum(enum_data) => enum_data,

@ -8,3 +8,5 @@ license = "MIT"
[dev-dependencies]
enumscribe = { path = "../enumscribe" }
enumscribe_derive = { path = "../enumscribe_derive" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize};
use enumscribe::*;
#[derive(TryScribeCowStr, TryUnscribe, Eq, PartialEq, Debug)]
#[derive(TryScribeCowStr, Unscribe, EnumSerialize, Eq, PartialEq, Debug)]
enum Airport {
#[enumscribe(str = "LHR")]
Heathrow,
@ -10,18 +12,35 @@ enum Airport {
Luton {},
#[enumscribe(str = "BHX", case_insensitive, ignore)]
BirminghamInternational,
// #[enumscribe(other)]
// Other(String),
#[enumscribe(other)]
Other(String),
}
#[derive(Serialize, Eq, PartialEq, Debug)]
struct AirportInfo {
airport: Airport,
info: String,
}
fn main() {
let luton = Airport::Luton {};
println!("Hello, {:?}!", luton.try_scribe());
// let other = Airport::Other("Dedicated EasyJet-only airport".to_owned());
// println!("Hello, {:?}!", other.try_scribe());
let other = Airport::Other("Dedicated EasyJet-only airport".to_owned());
println!("Hello, {:?}!", other.try_scribe());
println!();
println!("{:?}", Airport::unscribe("LHR"));
println!("{:?}", Airport::unscribe("lhr"));
println!("{:?}", Airport::unscribe("lgw"));
println!();
let info = AirportInfo {
airport: Airport::Gatwick(),
info: "It's somewhere in London, innit".to_owned()
};
println!("{:?}", Airport::try_unscribe("LHR"));
println!("{:?}", Airport::try_unscribe("lhr"));
println!("{:?}", Airport::try_unscribe("lgw"));
println!("{}", serde_json::to_string(&info).unwrap());
}

Loading…
Cancel
Save