muta-codec-derive 0.2.2

Muta fixed codec derive procedural macros.
Documentation
use proc_macro2::TokenStream;
use quote::quote;

use crate::decode::{decode_field, decode_parse_quotes, decode_unnamed_field};
use crate::encode::encode_field;

pub fn impl_fixed_codec(ast: syn::DeriveInput) -> TokenStream {
    let name = ast.ident;
    let body = if let syn::Data::Struct(s) = &ast.data {
        s
    } else {
        panic!("#[derive(FixedCodec)] is only defined for structs.");
    };

    let impl_encode = impl_encode(&name, body);
    let impl_decode = impl_decode(&name, body);
    let impl_muta = quote! {
        impl FixedCodec for #name {
            fn encode_fixed(&self) -> ProtocolResult<Bytes> {
                Ok(Bytes::from(rlp::encode(self)))
            }

            fn decode_fixed(bytes: Bytes) -> ProtocolResult<Self> {
                Ok(rlp::decode(bytes.as_ref()).map_err(FixedCodecError::from)?)
            }
        }
    };

    quote! {
        const _: () = {
            extern crate rlp;

            #impl_encode
            #impl_decode
            #impl_muta
        };
    }
}

fn impl_encode(name: &syn::Ident, body: &syn::DataStruct) -> TokenStream {
    let stmts = body
        .fields
        .iter()
        .enumerate()
        .map(|(i, field)| encode_field(i, field))
        .collect::<Vec<_>>();
    let stmts_len = stmts.len();
    let stmts_len = quote! { #stmts_len };

    quote! {
        impl rlp::Encodable for #name {
            fn rlp_append(&self, stream: &mut rlp::RlpStream) {
                stream.begin_list(#stmts_len);
                #(#stmts)*
            }
        }
    }
}

pub fn impl_decode(name: &syn::Ident, body: &syn::DataStruct) -> TokenStream {
    let decoded = match &body.fields {
        syn::Fields::Named(_) => {
            let stmts = body
                .fields
                .iter()
                .enumerate()
                .map(|(i, field)| decode_field(i, field, decode_parse_quotes()))
                .collect::<Vec<_>>();

            quote! {
                #name {
                   #(#stmts)*
                }
            }
        }
        syn::Fields::Unnamed(_) => {
            let stmts = body
                .fields
                .iter()
                .enumerate()
                .map(|(i, field)| decode_unnamed_field(i, field, decode_parse_quotes()))
                .collect::<Vec<_>>();

            quote! {
                #name(#(#stmts)*)
            }
        }
        _ => panic!("unit struct or unit variant such as None isn't supported"),
    };

    quote! {
        impl rlp::Decodable for #name {
            fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
                let result = #decoded;
                Ok(result)
            }
        }
    }
}