light_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, parse_quote, ItemFn};
6
7mod cpi_signer;
8mod pubkey;
9
10/// Converts a base58 encoded public key into a byte array.
11#[proc_macro]
12pub fn pubkey(input: TokenStream) -> TokenStream {
13    let args = parse_macro_input!(input as pubkey::PubkeyArgs);
14    pubkey::pubkey(args)
15        .unwrap_or_else(|err| err.to_compile_error())
16        .into()
17}
18
19/// Converts a base58 encoded public key into a raw byte array [u8; 32].
20#[proc_macro]
21pub fn pubkey_array(input: TokenStream) -> TokenStream {
22    let args = parse_macro_input!(input as pubkey::PubkeyArgs);
23    pubkey::pubkey_array(args)
24        .unwrap_or_else(|err| err.to_compile_error())
25        .into()
26}
27
28#[proc_macro_attribute]
29pub fn heap_neutral(_: TokenStream, input: TokenStream) -> TokenStream {
30    let mut function = parse_macro_input!(input as ItemFn);
31
32    // Insert memory management code at the beginning of the function
33    let init_code: syn::Stmt = parse_quote! {
34        #[cfg(target_os = "solana")]
35        let pos = light_heap::GLOBAL_ALLOCATOR.get_heap_pos();
36    };
37    let msg = format!("pre: {}", function.sig.ident);
38    let log_pre: syn::Stmt = parse_quote! {
39        #[cfg(all(target_os = "solana", feature = "mem-profiling"))]
40        light_heap::GLOBAL_ALLOCATOR.log_total_heap(#msg);
41    };
42    function.block.stmts.insert(0, init_code);
43    function.block.stmts.insert(1, log_pre);
44
45    // Insert memory management code at the end of the function
46    let msg = format!("post: {}", function.sig.ident);
47    let log_post: syn::Stmt = parse_quote! {
48        #[cfg(all(target_os = "solana", feature = "mem-profiling"))]
49        light_heap::GLOBAL_ALLOCATOR.log_total_heap(#msg);
50    };
51    let cleanup_code: syn::Stmt = parse_quote! {
52        #[cfg(target_os = "solana")]
53        light_heap::GLOBAL_ALLOCATOR.free_heap(pos)?;
54    };
55    let len = function.block.stmts.len();
56    function.block.stmts.insert(len - 1, log_post);
57    function.block.stmts.insert(len - 1, cleanup_code);
58    TokenStream::from(quote! { #function })
59}
60
61/// No-op derive macro that does nothing.
62/// Used as a placeholder for serialization derives when not needed.
63#[proc_macro_derive(Noop)]
64pub fn derive_noop(_input: TokenStream) -> TokenStream {
65    TokenStream::new()
66}
67
68/// Derives a Light Protocol CPI signer PDA at compile time
69///
70/// This macro computes the CPI signer PDA using the "cpi_authority" seed
71/// for the given program ID. Uses `solana_pubkey` with `solana` feature,
72/// otherwise uses `pinocchio` (default).
73///
74/// ## Usage
75///
76/// ```rust
77/// # use light_macros::derive_light_cpi_signer_pda;
78/// // In a Solana program
79/// let (cpi_signer, bump) = derive_light_cpi_signer_pda!("SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7");
80/// ```
81///
82/// Returns a tuple `([u8; 32], u8)` containing the PDA address and bump seed.
83#[proc_macro]
84pub fn derive_light_cpi_signer_pda(input: TokenStream) -> TokenStream {
85    cpi_signer::derive_light_cpi_signer_pda(input)
86}
87
88/// Derives a complete Light Protocol CPI configuration at runtime
89///
90/// This macro computes the program ID, CPI signer PDA, and bump seed
91/// for the given program ID. Uses `solana_pubkey` with `solana` feature,
92/// otherwise uses `pinocchio` (default).
93///
94/// ## Usage
95///
96/// ```rust
97/// # use light_macros::derive_light_cpi_signer;
98/// # struct CpiSigner { program_id: [u8; 32], cpi_signer: [u8; 32], bump: u8 }
99/// // In a Solana program
100/// const LIGHT_CPI_SIGNER: CpiSigner = derive_light_cpi_signer!("SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7");
101/// ```
102///
103/// Returns a `CpiSigner` struct (must be in scope) containing:
104/// - `program_id`: Program ID bytes
105/// - `cpi_signer`: CPI signer PDA address
106/// - `bump`: Bump seed
107#[proc_macro]
108pub fn derive_light_cpi_signer(input: TokenStream) -> TokenStream {
109    cpi_signer::derive_light_cpi_signer(input)
110}