muta-codec-derive 0.2.2

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

pub struct ParseQuotes {
    single: TokenStream,
    list:   TokenStream,
}

pub fn decode_parse_quotes() -> ParseQuotes {
    ParseQuotes {
        single: quote! { rlp.val_at },
        list:   quote! { rlp.list_at },
    }
}

pub fn decode_unnamed_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> TokenStream {
    let index = quote! { #index };
    let single = quotes.single;
    let list = quotes.list;

    match &field.ty {
        syn::Type::Array(array) => {
            let len = &array.len;
            let bytes = quote! { rlp.val_at::<Vec<u8>>(#index)? };

            quote! { {
                let bytes: Vec<u8> = #bytes;
                if bytes.len() != #len {
                    return rlp::DecoderError::Custom("Length mismatch");
                }

                let mut out = [0u8; #len];
                out.copy_from_slice(&bytes);
                out
            }, }
        }
        syn::Type::Path(path) => {
            let ident = &path
                .path
                .segments
                .first()
                .expect("there must be at least 1 segment")
                .ident;
            let ident_type = ident.to_string();
            if ident_type == "Vec" {
                let field_ident = match &path
                    .path
                    .segments
                    .first()
                    .expect("there must be at least 1 segment")
                    .arguments
                {
                    syn::PathArguments::AngleBracketed(argc) => argc
                        .args
                        .first()
                        .expect("there must be at least 1 argument"),
                    _ => panic!("there must be at least 1 type"),
                };

                quote! { {
                    let temp: Vec<Vec<u8>> = #list(#index)?;
                    let mut ret = Vec::new();
                    for item in temp.into_iter() {
                        if let Ok(res) = #field_ident::decode_fixed(Bytes::from(item.clone())) {
                            ret.push(res);
                        } else {
                            return Err(rlp::DecoderError::Custom("decode fixed error"));
                        }
                    }
                    ret
                }, }
            } else {
                quote! { {
                    let bytes: Vec<u8> = #single(#index)?;
                    #ident::decode_fixed(Bytes::from(bytes)).map_err(|_| rlp::DecoderError::Custom("decode fixed error"))?
                }, }
            }
        }
        _ => panic!("fixed_codec_derive not supported"),
    }
}

pub fn decode_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> TokenStream {
    let id = if let Some(ident) = &field.ident {
        quote! { #ident }
    } else {
        let index = syn::Index::from(index);
        quote! { #index }
    };

    let index = quote! { #index };
    let single = quotes.single;
    let list = quotes.list;

    match &field.ty {
        syn::Type::Array(array) => {
            let len = &array.len;
            let bytes = quote! { rlp.val_at::<Vec<u8>>(#index)? };

            quote! { #id: {
                let bytes: Vec<u8> = #bytes;
                if bytes.len() != #len {
                    return rlp::DecoderError::Custom("Length mismatch");
                }

                let mut out = [0u8; #len];
                out.copy_from_slice(&bytes);
                out
            }, }
        }
        syn::Type::Path(path) => {
            let ident = &path
                .path
                .segments
                .first()
                .expect("there must be at least 1 segment")
                .ident;
            let ident_type = ident.to_string();
            if ident_type == "Vec" {
                let field_ident = match &path
                    .path
                    .segments
                    .first()
                    .expect("there must be at least 1 segment")
                    .arguments
                {
                    syn::PathArguments::AngleBracketed(argc) => argc
                        .args
                        .first()
                        .expect("there must be at least 1 argument"),
                    _ => panic!("there must be at least 1 type"),
                };

                quote! { #id: {
                    let temp: Vec<Vec<u8>> = #list(#index)?;
                    let mut ret = Vec::new();
                    for item in temp.into_iter() {
                        if let Ok(res) = #field_ident::decode_fixed(Bytes::from(item.clone())) {
                            ret.push(res);
                        } else {
                            return Err(rlp::DecoderError::Custom("decode fixed error"));
                        }
                    }
                    ret
                }, }
            } else {
                quote! { #id: {
                    let bytes: Vec<u8> = #single(#index)?;
                    #ident::decode_fixed(Bytes::from(bytes)).map_err(|_| rlp::DecoderError::Custom("decode fixed error"))?
                }, }
            }
        }
        _ => panic!("fixed_codec_derive not supported"),
    }
}