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 read_struct_or_enum(
    struct_name: &Path,
    fields: &[FieldParam],
    span: Span,
    unchecked: bool,
) -> TokenStream {
    let named = fields.iter().any(|f| f.field_name.is_some());
    let values = fields.iter().map(|f| {
        let align = &f.align;
        let field_type = &f.ty;
        let span = f.span();
        let r#unsafe = if unchecked {
            quote_spanned!(span => unsafe)
        } else {
            quote_spanned!(span =>)
        };

        let read_fn = Ident::new(if unchecked { "read_unchecked" } else { "read" }, span);
        let read_sized_fn = Ident::new(
            if unchecked {
                "read_sized_unchecked"
            } else {
                "read_sized"
            },
            span,
        );
        let end_param = if unchecked {
            Some(quote_spanned!(span => end))
        } else {
            None
        };
        match &f.size {
            Some(size) => {
                quote_spanned! { span =>
                    #r#unsafe {
                        #align
                        let _size: usize = #size;
                        __stream.#read_sized_fn::<#field_type>(_size, #end_param)?
                    }
                }
            }
            None => {
                quote_spanned! { span =>
                    #r#unsafe {
                        #align
                        __stream.#read_fn::<#field_type>(#end_param)?
                    }
                }
            }
        }
    });

    if named {
        let definitions = fields.iter().zip(values).map(|(f, value)| {
            let name = &f.field_name;
            quote_spanned! { span =>
                let #name = #value;
            }
        });
        let struct_definition = fields.iter().map(|f| {
            let name = f
                .field_name
                .as_ref()
                .expect("unnamed field in named struct?");
            quote_spanned! { span =>
                #name,
            }
        });
        quote_spanned! { span =>
            #(#definitions)*

            Ok(#struct_name {
                #(#struct_definition)*
            })
        }
    } else {
        quote_spanned! { span =>
            Ok(#struct_name(
                #(#values ,)*
            ))
        }
    }
}