bitbuffer_derive 0.11.3

Reading bit sequences from a byte slice
Documentation
use crate::params::FieldParam;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote_spanned;
use syn::Path;

pub fn write_struct(fields: &[FieldParam], span: Span) -> TokenStream {
    let expand = fields
        .iter()
        .enumerate()
        .zip(names(fields))
        .map(|((index, field), name)| {
            let member = field.member(index as u32);
            let size_field = match (field.is_int(), field.field_name.as_ref()) {
                (true, Some(name)) => Some(quote_spanned! { field.span() =>
                    #[allow(unused_variables)]
                    let #name = self.#member;
                }),
                _ => None,
            };
            quote_spanned! { field.span() =>
                #size_field
                #[allow(unused_variables)]
                let #name = &self.#member;
            }
        });
    let writes = writes(fields);

    quote_spanned! {span=>
        #(#expand)*
        #(#writes)*
    }
}

fn names(fields: &[FieldParam]) -> impl Iterator<Item = Ident> + '_ {
    fields
        .iter()
        .enumerate()
        .map(|(index, field)| Ident::new(&format!("__field_{}", index), field.span()))
}

fn writes(fields: &[FieldParam]) -> impl Iterator<Item = TokenStream> + '_ {
    let names = names(fields);
    fields.iter().zip(names).map(|(field, name)| {
        let align = &field.align.write();
        let span = field.span();
        match &field.size {
            Some(size) => {
                quote_spanned! { span =>
                    {
                        #align
                        let _size: usize = #size;
                        __stream.write_sized(#name, _size)?;
                    }
                }
            }
            None => {
                quote_spanned! { span =>
                    {
                        #align
                        __stream.write(#name)?;
                    }
                }
            }
        }
    })
}

pub fn write_enum_variant(variant: Path, fields: &[FieldParam], span: Span) -> TokenStream {
    let names = names(fields);
    let named = fields.iter().any(|f| f.field_name.is_some());
    let writes = writes(fields);
    if named {
        quote_spanned!(span => #variant{#(#names,)*} => {
            #(#writes;)*
        })
    } else {
        quote_spanned!(span => #variant(#(#names,)*) => {
            #(#writes;)*
        })
    }
}