solalumin-attribute-event 0.1.0-alpha.1

Solalumin attribute macro for defining an event
Documentation
extern crate proc_macro;

use quote::quote;
use syn::parse_macro_input;
use syn::{parse::Parse, Expr, Token};

struct MacroInput2 {
    arg_1: Expr,
    comma: Token![,],
    arg_2: Expr,
}

impl Parse for MacroInput2 {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Self {
            arg_1: input.parse()?,
            comma: input.parse()?,
            arg_2: input.parse()?,
        })
    }
}

#[proc_macro_derive(SchemaGeneratorAnchor)]
pub fn schema_generator_anchor(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let account_strct = parse_macro_input!(input as syn::ItemStruct);

    let account_name = &account_strct.ident;

    proc_macro::TokenStream::from(quote! {
        impl solalumin_state::states::SchemaEventAnchor for #account_name {
             fn generate_schema(self) -> Vec<u8> {
                let mut d = Self::DISCRIMINATOR.to_vec();
                let mut defs = Default::default();
                Self::add_definitions_recursively(&mut defs);
                let container: borsh::schema::BorshSchemaContainer = Self::schema_container();
                let mut data = container
                    .try_to_vec()
                    .expect("Failed to serialize BorshSchemaContainer for account");
                d.append(&mut data);
                d
            }
        }
    })
}

#[proc_macro_attribute]
pub fn schema_generator(
    _args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let event_strct = parse_macro_input!(input as syn::ItemStruct);

    let event_name = &event_strct.ident;

    let discriminator: proc_macro2::TokenStream = {
        let discriminator_preimage = format!("event:{event_name}");
        let mut discriminator = [0u8; 8];
        discriminator.copy_from_slice(
            &solalumin_state::solalumin_hash::hash(discriminator_preimage.as_bytes()).to_bytes()[..8],
        );
        format!("{discriminator:?}").parse().unwrap()
    };

    proc_macro::TokenStream::from(quote! {
        #[derive(borsh::BorshSerialize, borsh::BorshDeserialize, borsh::BorshSchema)]
        #event_strct

        impl solalumin_state::states::SchemaEvent for #event_name {
            fn data(&self) -> Vec<u8> {
                let mut d = #discriminator.to_vec();
                d.append(&mut self.try_to_vec().unwrap());
                d
            }

            fn generate_schema(self) -> Vec<u8> {
                let mut d = #discriminator.to_vec();
                let mut defs = Default::default();
                Self::add_definitions_recursively(&mut defs);
                let container: borsh::schema::BorshSchemaContainer = Self::schema_container();
                let mut data = container
                    .try_to_vec()
                    .expect("Failed to serialize BorshSchemaContainer for event");
                d.append(&mut data);
                d
            }
        }

        impl solalumin_state::states::Discriminator for #event_name {
            const DISCRIMINATOR: [u8; 8] = #discriminator;
        }
    })
}

#[proc_macro]
pub fn register_program_log_data_schema(
    token_stream: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(token_stream as MacroInput2);

    let data = &input.arg_1;
    let is_anchor = &input.arg_2;
    proc_macro::TokenStream::from(quote! {
        {
            let schema_string = base64::encode(#data.generate_schema().as_slice());
            msg!("LD:{}:{}", #is_anchor, schema_string);
        }
    })
}

#[proc_macro]
pub fn register_program_account_schema(
    token_stream: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(token_stream as MacroInput2);

    let data = &input.arg_1;
    let is_anchor = &input.arg_2;
    proc_macro::TokenStream::from(quote! {
        {
            let schema_string = base64::encode(#data.generate_schema().as_slice());
            msg!("AR:{}:{}", #is_anchor, schema_string);
        }
    })
}

#[proc_macro]
pub fn register_program_instruction_log_schema(
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let data: proc_macro2::TokenStream = input.into();
    proc_macro::TokenStream::from(quote! {
        {
            solana_program::log::sol_log_data(&[&#data.generate_schema()]);
        }
    })
}

#[proc_macro]
pub fn publish(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let data: proc_macro2::TokenStream = input.into();
    proc_macro::TokenStream::from(quote! {
        {
            solana_program::log::sol_log_data(&[&solalumin_state::states::SchemaEvent::data(&#data)]);
        }
    })
}