narrative-macros 0.8.0

Procedural macros for the narrative crate
Documentation
use proc_macro2::TokenStream;
use quote::quote;

pub fn generate(input: &syn::ItemStruct) -> TokenStream {
    let derive = super::derive_attr::generate();
    let _ = &input.attrs;
    let ident = &input.ident;
    let generics = &input.generics;
    let fields = match &input.fields {
        syn::Fields::Named(named) => {
            let iter = named.named.iter().map(|field| {
                let attrs = &field.attrs;
                let ident = &field.ident;
                let ty = &field.ty;
                quote! {
                    #(#attrs)*
                    pub #ident: #ty,
                }
            });
            quote!({ #(#iter)* })
        }
        syn::Fields::Unnamed(unnamed) => {
            let iter = unnamed.unnamed.iter().map(|field| {
                let attrs = &field.attrs;
                let ty = &field.ty;
                quote! {
                    #(#attrs)*
                    pub #ty
                }
            });
            quote!(( #(#iter),* );)
        }
        syn::Fields::Unit => quote!(;),
    };
    quote! {
        #derive
        pub struct #ident #generics #fields
    }
}

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

    #[test]
    fn test_struct_visibility_unit() {
        let input = syn::parse_quote! {
            struct User;
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User;
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }

    #[test]
    fn test_struct_visibility_named_fields() {
        let input = syn::parse_quote! {
            pub struct User {
                id: i32,
                name: String,
            }
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User {
                pub id: i32,
                pub name: String,
            }
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }

    #[test]
    fn test_struct_visibility_unnamed_fields() {
        let input = syn::parse_quote! {
            pub struct User(i32, String);
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User(pub i32, pub String);
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }

    #[test]
    fn test_struct_keep_member_named_attributes() {
        let input = syn::parse_quote! {
            pub struct User {
                #[keep_this]
                #[keep_this2]
                id: i32,
                name: String,
            }
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User {
                #[keep_this]
                #[keep_this2]
                pub id: i32,
                pub name: String,
            }
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }

    #[test]
    fn test_struct_keep_member_unnamed_attributes() {
        let input = syn::parse_quote! {
            pub struct User(#[keep_this] #[keep_this2] i32, String);
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User(#[keep_this] #[keep_this2] pub i32, pub String);
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }

    #[test]
    fn test_struct_keep_generics() {
        let input = syn::parse_quote! {
            pub struct User<T, U> {
                id: i32,
                name: String,
            }
        };
        let actual = generate(&input);
        let expected = quote! {
            #[derive(Clone, Debug, PartialEq, narrative::serde::Serialize)]
            #[serde(crate = "narrative::serde")]
            pub struct User<T, U> {
                pub id: i32,
                pub name: String,
            }
        };
        assert_eq!(actual.to_string(), expected.to_string());
    }
}