xmlity-derive 0.0.9

Derive proc-macros for xmlity.
Documentation
use std::borrow::Cow;

use proc_macro2::Span;
use syn::{parse_quote, Generics, Ident, ImplItemFn, ItemImpl, Stmt, Type};

use crate::{common::non_bound_generics, DeriveError};

pub trait SerializeBuilder {
    fn serialize_fn_body(
        &self,
        serializer_access: &Ident,
        serializer_type: &syn::Type,
    ) -> Result<Vec<Stmt>, DeriveError>;

    fn ident(&self) -> Cow<'_, Ident>;
    fn generics(&self) -> Cow<'_, Generics>;
}

pub trait SerializeBuilderExt: SerializeBuilder {
    fn serialize_fn(&self) -> Result<ImplItemFn, DeriveError>;
    fn serialize_trait_impl(&self) -> Result<ItemImpl, DeriveError>;
}

impl<T: SerializeBuilder> SerializeBuilderExt for T {
    fn serialize_fn(&self) -> Result<ImplItemFn, DeriveError> {
        let serializer_access_ident = Ident::new("__serializer", Span::call_site());
        let serializer_type: syn::Type = parse_quote!(__XmlitySerializer);
        let body = self.serialize_fn_body(&serializer_access_ident, &serializer_type)?;
        Ok(parse_quote!(
            fn serialize<#serializer_type>(&self, mut #serializer_access_ident: #serializer_type) -> Result<<#serializer_type as ::xmlity::Serializer>::Ok, <#serializer_type as ::xmlity::Serializer>::Error>
            where
                #serializer_type: ::xmlity::Serializer,
            {
                #(#body)*
            }
        ))
    }

    fn serialize_trait_impl(&self) -> Result<ItemImpl, DeriveError> {
        let ident = self.ident();
        let generics = self.generics();
        let serialize_fn = self.serialize_fn()?;

        let non_bound_generics = crate::common::non_bound_generics(&generics);

        Ok(parse_quote! {
            impl #generics ::xmlity::Serialize for #ident #non_bound_generics {
                #serialize_fn
            }
        })
    }
}

pub trait SerializeAttributeBuilder {
    fn serialize_attribute_fn_body(
        &self,
        serializer_access: &Ident,
        serializer_type: &syn::Type,
    ) -> Result<Vec<Stmt>, DeriveError>;

    fn ident(&self) -> Cow<'_, Ident>;
    fn generics(&self) -> Cow<'_, syn::Generics>;
}

pub trait SerializeAttributeBuilderExt: SerializeAttributeBuilder {
    fn serialize_attribute_fn(&self) -> Result<ImplItemFn, DeriveError>;
    fn serialize_attribute_trait_impl(&self) -> Result<ItemImpl, DeriveError>;
}

impl<T: SerializeAttributeBuilder> SerializeAttributeBuilderExt for T {
    fn serialize_attribute_fn(&self) -> Result<ImplItemFn, DeriveError> {
        let serializer_access_ident = Ident::new("__serializer", Span::call_site());
        let serializer_type: syn::Type = parse_quote!(__XmlityAttributeSerializer);
        let body = self.serialize_attribute_fn_body(&serializer_access_ident, &serializer_type)?;
        Ok(parse_quote!(
            fn serialize_attribute<#serializer_type>(&self, mut #serializer_access_ident: #serializer_type) -> Result<<#serializer_type as ::xmlity::AttributeSerializer>::Ok, <#serializer_type as ::xmlity::AttributeSerializer>::Error>
            where
                #serializer_type: ::xmlity::AttributeSerializer,
            {
                #(#body)*
            }
        ))
    }

    fn serialize_attribute_trait_impl(&self) -> Result<ItemImpl, DeriveError> {
        let serialize_attribute_fn = self.serialize_attribute_fn()?;
        let ident = self.ident();
        let generics = self.generics();

        let non_bound_generics = non_bound_generics(&generics);

        Ok(parse_quote! {
            impl #generics ::xmlity::SerializeAttribute for #ident #non_bound_generics {
                #serialize_attribute_fn
            }
        })
    }
}

pub trait SerializationGroupBuilder {
    fn serialize_attributes_fn_body(
        &self,
        element_access_ident: &Ident,
    ) -> Result<Vec<Stmt>, DeriveError>;

    fn serialize_children_fn_body(
        &self,
        children_access_ident: &Ident,
    ) -> Result<Vec<Stmt>, DeriveError>;

    fn ident(&self) -> Cow<'_, Ident>;
    fn generics(&self) -> Cow<'_, Generics>;
}

pub trait SerializationGroupBuilderExt: SerializationGroupBuilder {
    fn serialize_attributes_fn(&self) -> Result<ImplItemFn, DeriveError>;
    fn serialize_children_fn(&self) -> Result<ImplItemFn, DeriveError>;
    fn serialization_group_trait_impl(&self) -> Result<ItemImpl, DeriveError>;
}

impl<T: SerializationGroupBuilder> SerializationGroupBuilderExt for T {
    fn serialize_attributes_fn(&self) -> Result<ImplItemFn, DeriveError> {
        let serialize_attributes_ident = Ident::new("__element", proc_macro2::Span::call_site());
        let serialize_attributes_type: Type = parse_quote!(__XmlitySerializeAttributes);
        let body = self.serialize_attributes_fn_body(&serialize_attributes_ident)?;

        Ok(parse_quote!(
            fn serialize_attributes<#serialize_attributes_type: xmlity::ser::SerializeAttributes>(
                &self,
                #serialize_attributes_ident: &mut #serialize_attributes_type,
            ) -> Result<(), <#serialize_attributes_type as xmlity::ser::SerializeAttributes>::Error> {
               #(#body)*
            }
        ))
    }

    fn serialize_children_fn(&self) -> Result<ImplItemFn, DeriveError> {
        let children_access_ident = Ident::new("__children", proc_macro2::Span::call_site());
        let children_access_type: Type = parse_quote!(__XmlitySerializeSeq);
        let body = self.serialize_children_fn_body(&children_access_ident)?;

        Ok(parse_quote!(
            fn serialize_children<#children_access_type: xmlity::ser::SerializeSeq>(
                &self,
                #children_access_ident: &mut #children_access_type,
            ) -> Result<(), <#children_access_type as xmlity::ser::SerializeSeq>::Error> {
                #(#body)*
            }
        ))
    }

    fn serialization_group_trait_impl(&self) -> Result<ItemImpl, DeriveError> {
        let ident = self.ident();
        let generics = self.generics();
        let non_bound_generics = non_bound_generics(&generics);

        let serialize_attributes_fn = self.serialize_attributes_fn()?;
        let serialize_children_fn = self.serialize_children_fn()?;

        Ok(parse_quote! {
        impl #generics ::xmlity::ser::SerializationGroup for #ident #non_bound_generics {
            #serialize_attributes_fn

            #serialize_children_fn
        }
        })
    }
}