bin_codec_derive 0.1.0

binary encoder decoder with bit field
Documentation
use crate::Endin;
use crate::attribute::FieldAttr;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::*;
use syn::*;

mod field;
mod named;
mod unnamed;
mod variant;

pub(crate) fn encode(input: TokenStream, ed: Endin) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let generics = input.generics;
    let where_clause = &generics.where_clause;
    let name = input.ident;
    let codec: TokenStream2 = match &input.data {
        Data::Struct(data_struct) => encode_struct(&data_struct, &ed),
        _ => unimplemented!()
    };
    let size: TokenStream2 = match &input.data {
        Data::Struct(data_struct) => size_struct(&data_struct, &ed),
        _ => unimplemented!()
    };
    let trait_name = match ed {
        Endin::Big => quote!(bin_codec::EncodeBe),
        Endin::Little => quote!(bin_codec::EncodeLe),
    };
    let expanded = quote! {
        impl #generics #trait_name for #name #generics #where_clause {
            fn encode_offset<__CTX>(&self, target: &mut [u8], ctx: &mut __CTX, offset: &mut usize, bits: usize) {
                use bin_codec::*;
                let target_ptr = target.as_mut_ptr();
                #codec
            }

            fn bits_with_user_define(&self, bits: Option<usize>) -> usize {
                #size
            }
        }
    };
    TokenStream::from(expanded)
}

pub(crate) fn decode(input: TokenStream, ed: Endin) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let attr = FieldAttr::from_attrs(&input.attrs);
    let generics = input.generics;
    let where_clause = &generics.where_clause;
    let name = &input.ident;
    let codec: TokenStream2 = match &input.data {
        Data::Struct(data_struct) => decode_struct(&data_struct, name, &ed),
        _ => unimplemented!(),
    };
    let trait_name = match ed {
        Endin::Big => quote!(bin_codec::DecodeBe),
        Endin::Little => quote!(bin_codec::DecodeLe),
    };
    let context_type = attr.context.map(|l| quote!(#l)).unwrap_or(quote!(()));
    let has_next = attr.has_next.map(|l| quote!(*sd = ShouldDecode::HasNext(#l);));
    let expanded = quote! {
        impl #generics #trait_name for #name #generics #where_clause {
            type Context = #context_type;
            fn decode_offset(data: &[u8], data_start: &mut usize, sd: &mut ShouldDecode, ctx: &mut Self::Context, bits: usize) -> bin_codec::Result<Self> {
                #codec
                #has_next
                Ok(rt)
            }

            fn default_bits() -> usize {
                0
            }
        }
    };
    TokenStream::from(expanded)
}

fn encode_struct(data: &DataStruct, ed: &Endin) -> TokenStream2 {
    match &data.fields {
        Fields::Named(named) => self::named::encode(named, ed),
        Fields::Unnamed(unnamed) => self::unnamed::encode(unnamed, ed),
        Fields::Unit => unimplemented!(),
    }
}

fn size_struct(data: &DataStruct, ed: &Endin) -> TokenStream2 {
    match &data.fields {
        Fields::Named(named) => self::named::size(named, ed),
        Fields::Unnamed(unnamed) => self::unnamed::size(unnamed, ed),
        Fields::Unit => unimplemented!(),
    }
}

fn decode_struct(data: &DataStruct, name: &Ident, ed: &Endin) -> TokenStream2 {
    match &data.fields {
        Fields::Named(named) => {
            let (ref values, ref fields) = self::named::decode(named, ed);
            quote! {
                #(let #fields = #values;)*
                let rt = #name {
                    #(#fields,)*
                };
            }
        }
        Fields::Unnamed(unnamed) => {
            let (ref values, ref fields) = self::unnamed::decode(unnamed, ed);
            quote! {
                #(let #fields = #values;)*
                let rt = #name (
                    #(#fields,)*
                );
            }
        }
        Fields::Unit => unimplemented!("`unit struct` not implemented"),
    }
}