edn-derive 0.7.0

Edn (De)Serialization derive macros
Documentation
use crate::enums::{generate_variant_deserialization, get_enum_variants};
use crate::structs;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{
    punctuated::Punctuated, token::Comma, Data, DataEnum, DataStruct, Error, Field, Fields, Ident,
};

pub fn expand(type_name: &Ident, data: &Data) -> Result<TokenStream2, Error> {
    match data {
        Data::Struct(ref data_struct) => Ok(expand_struct(type_name, data_struct)),
        Data::Enum(ref data_enum) => Ok(expand_enum(type_name, data_enum)),
        Data::Union(ref data_union) => Err(Error::new(
            data_union.union_token.span,
            "edn-derive does not support derive for unions",
        )),
    }
}

fn expand_struct(struct_name: &Ident, data_struct: &DataStruct) -> TokenStream2 {
    match data_struct.fields {
        Fields::Named(ref fields) => expand_named_struct(struct_name, &fields.named),
        Fields::Unnamed(ref fields) => expand_unnamed_struct(struct_name, &fields.unnamed),
        Fields::Unit => expand_unit_struct(struct_name),
    }
}

fn expand_named_struct(struct_name: &Ident, fields: &Punctuated<Field, Comma>) -> TokenStream2 {
    let deserialized_fields = structs::named_field_deserialization(fields);
    quote! {
        impl edn_rs::Deserialize for #struct_name {
            fn deserialize(edn: &edn_rs::Edn) -> std::result::Result<Self, edn_rs::EdnError> {
                std::result::Result::Ok(Self {
                    #deserialized_fields
                })
            }
        }
    }
}

fn expand_unnamed_struct(struct_name: &Ident, fields: &Punctuated<Field, Comma>) -> TokenStream2 {
    let deserialized_fields = structs::unnamed_field_deserialization(fields);
    quote! {
        impl edn_rs::Deserialize for #struct_name {
            fn deserialize(edn: &edn_rs::Edn) -> std::result::Result<Self, edn_rs::EdnError> {
                std::result::Result::Ok(Self {
                    #deserialized_fields
                })
            }
        }
    }
}

fn expand_unit_struct(struct_name: &Ident) -> TokenStream2 {
    quote! {
        impl edn_rs::Deserialize for #struct_name {
            fn deserialize(edn: &edn_rs::Edn) -> std::result::Result<Self, edn_rs::EdnError> {
                match edn {
                    edn_rs::Edn::Nil => std::result::Result::Ok(Self),
                    _ => std::result::Result::Err(edn_rs::EdnError::Deserialize(format!(
                                "couldn't convert {} into an unit struct",
                                edn
                    )))
                }
            }
        }
    }
}

fn expand_enum(enum_name: &Ident, data_enum: &DataEnum) -> TokenStream2 {
    let enum_variants = get_enum_variants(data_enum);

    let deserialized_variants = generate_variant_deserialization(enum_name, enum_variants);

    quote! {
        impl edn_rs::Deserialize for #enum_name {
            fn deserialize(edn: &edn_rs::Edn) -> std::result::Result<Self, edn_rs::EdnError> {
                match edn {
                    edn_rs::Edn::Key(k) => match &k[..] {
                        #deserialized_variants
                        _ => std::result::Result::Err(edn_rs::EdnError::Deserialize(format!(
                                "couldn't convert {} keyword into enum",
                                k
                        )))
                    },
                    edn_rs::Edn::Str(s) => match &s[..] {
                        #deserialized_variants
                        _ => std::result::Result::Err(edn_rs::EdnError::Deserialize(format!(
                                "couldn't convert {} string into enum",
                                s
                        ))),
                    },
                    _ => std::result::Result::Err(edn_rs::EdnError::Deserialize(format!(
                                "couldn't convert {} into enum",
                                edn
                    ))),
                }
            }
        }
    }
}