binrw_derive 0.15.1

Derive macro for binrw
Documentation
use super::{prelude::PreludeGenerator, struct_field::write_field};
use crate::binrw::{
    codegen::sanitization::{THIS, WRITER},
    parser::{Input, Struct},
};
use proc_macro2::TokenStream;
use quote::quote;
use syn::Ident;

pub(super) fn generate_struct(input: &Input, name: Option<&Ident>, st: &Struct) -> TokenStream {
    StructGenerator::new(input, st, name, &input.stream_ident_or(WRITER))
        .write_fields()
        .prefix_prelude()
        .prefix_borrow_fields()
        .prefix_imports()
        .finish()
}

pub(super) struct StructGenerator<'input> {
    input: &'input Input,
    st: &'input Struct,
    name: Option<&'input Ident>,
    writer_var: &'input TokenStream,
    out: TokenStream,
}

impl<'input> StructGenerator<'input> {
    pub(super) fn new(
        input: &'input Input,
        st: &'input Struct,
        name: Option<&'input Ident>,
        writer_var: &'input TokenStream,
    ) -> Self {
        Self {
            input,
            st,
            name,
            writer_var,
            out: TokenStream::new(),
        }
    }

    pub(super) fn prefix_imports(mut self) -> Self {
        self.out = PreludeGenerator::new(self.out, self.input, self.name, self.writer_var)
            .prefix_imports()
            .finish();

        self
    }

    pub(super) fn prefix_prelude(mut self) -> Self {
        self.out = PreludeGenerator::new(self.out, self.input, self.name, self.writer_var)
            .prefix_map_stream()
            .prefix_magic(&self.st.magic)
            .prefix_endian(&self.st.endian)
            .prefix_assertions()
            .finish();

        self
    }

    pub(super) fn write_fields(mut self) -> Self {
        let write_fields = self
            .st
            .fields
            .iter()
            .map(|field| write_field(self.writer_var, field));

        self.out = quote! {
            #(#write_fields)*
        };

        self
    }

    pub(super) fn prefix_borrow_fields(mut self) -> Self {
        let borrow_fields = self.name.map(|name| {
            let pattern = self.st.fields_pattern();

            Some(quote! {
                let #name #pattern = self;
            })
        });

        let out = self.out;
        self.out = quote! {
            let #THIS = self;
            #borrow_fields
            #out
        };

        self
    }

    pub(super) fn finish(self) -> TokenStream {
        self.out
    }
}