bolt_attribute_bolt_component_deserialize/
lib.rs

1use bolt_utils::add_bolt_metadata;
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, Attribute, DeriveInput};
5
6/// This macro is used to defined a struct as a BOLT component and automatically implements the
7/// `ComponentDeserialize` and `AccountDeserialize` traits for the struct.
8///
9/// #[component]
10/// pub struct Position {
11///     pub x: i64,
12///     pub y: i64,
13///     pub z: i64,
14/// }
15/// ```
16#[proc_macro_attribute]
17pub fn component_deserialize(_attr: TokenStream, item: TokenStream) -> TokenStream {
18    let mut input = parse_macro_input!(item as DeriveInput);
19
20    // Add the AnchorDeserialize and AnchorSerialize derives to the struct
21    let additional_derives: Attribute = syn::parse_quote! { #[derive(bolt_lang::InitSpace, bolt_lang::AnchorDeserialize, bolt_lang::AnchorSerialize, Clone, Copy)] };
22    input.attrs.push(additional_derives);
23
24    let name = &input.ident.clone();
25    // Assume that the component_id is the same as the struct name, minus the "Component" prefix
26    let name_str = name.to_string();
27    let component_id = name_str.strip_prefix("Component").unwrap_or("");
28    let mut owner_definition = quote! {};
29    if !component_id.is_empty() {
30        add_bolt_metadata(&mut input);
31        owner_definition = quote! {
32            use std::str::FromStr;
33            #[automatically_derived]
34            impl Owner for #name {
35                fn owner() -> Pubkey {
36                    Pubkey::from_str(#component_id).unwrap()
37                }
38            }
39        };
40    }
41    let expanded = quote! {
42        #input
43
44        #[automatically_derived]
45        impl bolt_lang::ComponentDeserialize for #name{
46            fn from_account_info(account: &bolt_lang::AccountInfo) -> bolt_lang::Result<#name> {
47                #name::try_deserialize_unchecked(&mut &*(*account.data.borrow()).as_ref()).map_err(Into::into)
48            }
49        }
50
51        #[automatically_derived]
52        impl bolt_lang::AccountDeserialize for #name {
53            fn try_deserialize(buf: &mut &[u8]) -> bolt_lang::Result<Self> {
54                Self::try_deserialize_unchecked(buf)
55            }
56
57            fn try_deserialize_unchecked(buf: &mut &[u8]) -> bolt_lang::Result<Self> {
58                let mut data: &[u8] = &buf[8..];
59                bolt_lang::AnchorDeserialize::deserialize(&mut data)
60                    .map_err(|_| bolt_lang::AccountDidNotDeserializeErrorCode.into())
61            }
62        }
63
64        #[automatically_derived]
65        impl bolt_lang::AccountSerialize for #name {
66            fn try_serialize<W>(&self, _writer: &mut W) -> Result<()> {
67                Ok(())
68            }
69        }
70
71        #[automatically_derived]
72        impl anchor_lang::Discriminator for #name {
73            const DISCRIMINATOR: &'static [u8] = &[1, 1, 1, 1, 1, 1, 1, 1];
74        }
75
76        #owner_definition
77    };
78
79    expanded.into()
80}