anchor_syn/codegen/accounts/
__client_accounts.rs1use crate::{AccountField, AccountsStruct, Ty};
2use heck::SnakeCase;
3use quote::quote;
4use std::str::FromStr;
5
6pub fn generate(
10 accs: &AccountsStruct,
11 program_id: proc_macro2::TokenStream,
12) -> proc_macro2::TokenStream {
13 let name = &accs.ident;
14 let account_mod_name: proc_macro2::TokenStream = format!(
15 "__client_accounts_{}",
16 accs.ident.to_string().to_snake_case()
17 )
18 .parse()
19 .unwrap();
20
21 let account_struct_fields: Vec<proc_macro2::TokenStream> = accs
22 .fields
23 .iter()
24 .map(|f: &AccountField| match f {
25 AccountField::CompositeField(s) => {
26 let name = &s.ident;
27 let docs = if let Some(ref docs) = s.docs {
28 docs.iter()
29 .map(|docs_line| {
30 proc_macro2::TokenStream::from_str(&format!(
31 "#[doc = r#\"{docs_line}\"#]"
32 ))
33 .unwrap()
34 })
35 .collect()
36 } else {
37 quote!()
38 };
39 let symbol: proc_macro2::TokenStream = format!(
40 "__client_accounts_{0}::{1}",
41 s.symbol.to_snake_case(),
42 s.symbol,
43 )
44 .parse()
45 .unwrap();
46 quote! {
47 #docs
48 pub #name: #symbol
49 }
50 }
51 AccountField::Field(f) => {
52 let name = &f.ident;
53 let docs = if let Some(ref docs) = f.docs {
54 docs.iter()
55 .map(|docs_line| {
56 proc_macro2::TokenStream::from_str(&format!(
57 "#[doc = r#\"{docs_line}\"#]"
58 ))
59 .unwrap()
60 })
61 .collect()
62 } else {
63 quote!()
64 };
65 if f.is_optional {
66 quote! {
67 #docs
68 pub #name: Option<Pubkey>
69 }
70 } else {
71 quote! {
72 #docs
73 pub #name: Pubkey
74 }
75 }
76 }
77 })
78 .collect();
79
80 let account_struct_metas: Vec<proc_macro2::TokenStream> = accs
81 .fields
82 .iter()
83 .map(|f: &AccountField| match f {
84 AccountField::CompositeField(s) => {
85 let name = &s.ident;
86 quote! {
87 account_metas.extend(self.#name.to_account_metas(None));
88 }
89 }
90 AccountField::Field(f) => {
91 let is_signer = match f.ty {
92 Ty::Signer => true,
93 _ => f.constraints.is_signer(),
94 };
95 let is_signer = match is_signer {
96 false => quote! {false},
97 true => quote! {true},
98 };
99 let meta = match f.constraints.is_mutable() {
100 false => quote! { anchor_lang::solana_program::instruction::AccountMeta::new_readonly },
101 true => quote! { anchor_lang::solana_program::instruction::AccountMeta::new },
102 };
103 let name = &f.ident;
104 if f.is_optional {
105 quote! {
106 if let Some(#name) = &self.#name {
107 account_metas.push(#meta(*#name, #is_signer));
108 } else {
109 account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new_readonly(#program_id, false));
110 }
111 }
112 } else {
113 quote! {
114 account_metas.push(#meta(self.#name, #is_signer));
115 }
116 }
117 }
118 })
119 .collect();
120 let re_exports: Vec<proc_macro2::TokenStream> = {
126 let mut re_exports = std::collections::HashSet::new();
128 for f in accs.fields.iter().filter_map(|f: &AccountField| match f {
129 AccountField::CompositeField(s) => Some(s),
130 AccountField::Field(_) => None,
131 }) {
132 re_exports.insert(format!(
133 "__client_accounts_{0}::{1}",
134 f.symbol.to_snake_case(),
135 f.symbol,
136 ));
137 }
138
139 re_exports
140 .iter()
141 .map(|symbol: &String| {
142 let symbol: proc_macro2::TokenStream = symbol.parse().unwrap();
143 quote! {
144 pub use #symbol;
145 }
146 })
147 .collect()
148 };
149
150 let struct_doc = proc_macro2::TokenStream::from_str(&format!(
151 "#[doc = \" Generated client accounts for [`{name}`].\"]"
152 ))
153 .unwrap();
154
155 quote! {
156 pub(crate) mod #account_mod_name {
166 use super::*;
167 use anchor_lang::prelude::borsh;
168 #(#re_exports)*
169
170 #struct_doc
171 #[derive(anchor_lang::AnchorSerialize)]
172 pub struct #name {
173 #(#account_struct_fields),*
174 }
175
176 #[automatically_derived]
177 impl anchor_lang::ToAccountMetas for #name {
178 fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<anchor_lang::solana_program::instruction::AccountMeta> {
179 let mut account_metas = vec![];
180
181 #(#account_struct_metas)*
182
183 account_metas
184 }
185 }
186 }
187 }
188}