typhoon-context-macro 0.1.0-alpha.12

TODO
Documentation
use {
    super::GeneratorResult,
    crate::{context::Context, StagedGenerator},
    quote::{format_ident, quote},
    syn::parse_quote,
    typhoon_syn::arguments::{Argument, Arguments},
};

pub struct ArgumentsGenerator<'a>(&'a Context);

impl<'a> ArgumentsGenerator<'a> {
    pub fn new(context: &'a Context) -> Self {
        ArgumentsGenerator(context)
    }
}

impl StagedGenerator for ArgumentsGenerator<'_> {
    fn append(&mut self, context: &mut GeneratorResult) -> Result<(), syn::Error> {
        let Some(ref args) = self.0.args else {
            return Ok(());
        };

        let context_name = &self.0.item_struct.ident;
        let (name, args_struct) = match args {
            Arguments::Struct(name) => (name.clone(), None),
            Arguments::Values(args) => {
                let struct_name = format_ident!("{context_name}Args");
                let fields = args
                    .iter()
                    .map(|Argument { name, ty }: &Argument| quote!(pub #name: #ty));

                let generated_struct = quote! {
                    #[derive(Debug, PartialEq, bytemuck::AnyBitPattern, bytemuck::NoUninit, Copy, Clone)]
                    #[repr(C)]
                    pub struct #struct_name {
                        #(#fields),*
                    }
                };

                (struct_name, Some(generated_struct))
            }
        };

        context
            .new_fields
            .push(parse_quote!(pub args: Arg<'info, #name>));
        context
            .inside
            .extend(quote!(let args = Arg::<#name>::from_entrypoint(program_id, accounts, instruction_data)?;));

        if let Some(args_struct) = args_struct {
            context.outside.extend(args_struct);
        }

        Ok(())
    }
}