lib.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //! DSL syntax tokens.
  2. #[cfg(feature = "idl")]
  3. use crate::idl::{IdlAccount, IdlAccountItem, IdlAccounts};
  4. use anyhow::Result;
  5. #[cfg(feature = "idl")]
  6. use heck::MixedCase;
  7. use quote::quote;
  8. use std::collections::HashMap;
  9. pub mod codegen;
  10. #[cfg(feature = "idl")]
  11. pub mod idl;
  12. pub mod parser;
  13. #[derive(Debug)]
  14. pub struct Program {
  15. pub rpcs: Vec<Rpc>,
  16. pub name: syn::Ident,
  17. pub program_mod: syn::ItemMod,
  18. }
  19. #[derive(Debug)]
  20. pub struct Rpc {
  21. pub raw_method: syn::ItemFn,
  22. pub ident: syn::Ident,
  23. pub args: Vec<RpcArg>,
  24. // The ident for the struct deriving Accounts.
  25. pub anchor_ident: syn::Ident,
  26. }
  27. #[derive(Debug)]
  28. pub struct RpcArg {
  29. pub name: proc_macro2::Ident,
  30. pub raw_arg: syn::PatType,
  31. }
  32. #[derive(Debug)]
  33. pub struct AccountsStruct {
  34. // Name of the accounts struct.
  35. pub ident: syn::Ident,
  36. // Generics + lifetimes on the accounts struct.
  37. pub generics: syn::Generics,
  38. // Fields on the accounts struct.
  39. pub fields: Vec<AccountField>,
  40. }
  41. impl AccountsStruct {
  42. pub fn new(strct: syn::ItemStruct, fields: Vec<AccountField>) -> Self {
  43. let ident = strct.ident.clone();
  44. let generics = strct.generics.clone();
  45. Self {
  46. ident,
  47. generics,
  48. fields,
  49. }
  50. }
  51. // Returns all program owned accounts in the Accounts struct.
  52. //
  53. // `global_accs` is given to "link" account types that are embedded
  54. // in each other.
  55. pub fn account_tys(
  56. &self,
  57. global_accs: &HashMap<String, AccountsStruct>,
  58. ) -> Result<Vec<String>> {
  59. let mut tys = vec![];
  60. for f in &self.fields {
  61. match f {
  62. AccountField::Field(f) => {
  63. if let Ty::ProgramAccount(pty) = &f.ty {
  64. tys.push(pty.account_ident.to_string());
  65. }
  66. }
  67. AccountField::AccountsStruct(comp_f) => {
  68. let accs = global_accs.get(&comp_f.symbol).ok_or(anyhow::format_err!(
  69. "Invalid account type: {}",
  70. comp_f.symbol
  71. ))?;
  72. tys.extend(accs.account_tys(global_accs)?);
  73. }
  74. }
  75. }
  76. Ok(tys)
  77. }
  78. #[cfg(feature = "idl")]
  79. pub fn idl_accounts(
  80. &self,
  81. global_accs: &HashMap<String, AccountsStruct>,
  82. ) -> Vec<IdlAccountItem> {
  83. self.fields
  84. .iter()
  85. .map(|acc: &AccountField| match acc {
  86. AccountField::AccountsStruct(comp_f) => {
  87. let accs_strct = global_accs
  88. .get(&comp_f.symbol)
  89. .expect("Could not reslve Accounts symbol");
  90. let accounts = accs_strct.idl_accounts(global_accs);
  91. IdlAccountItem::IdlAccounts(IdlAccounts {
  92. name: comp_f.ident.to_string().to_mixed_case(),
  93. accounts,
  94. })
  95. }
  96. AccountField::Field(acc) => IdlAccountItem::IdlAccount(IdlAccount {
  97. name: acc.ident.to_string().to_mixed_case(),
  98. is_mut: acc.is_mut,
  99. is_signer: acc.is_signer,
  100. }),
  101. })
  102. .collect::<Vec<_>>()
  103. }
  104. }
  105. #[derive(Debug)]
  106. pub enum AccountField {
  107. // Use a `String` instead of the `AccountsStruct` because all
  108. // accounts structs aren't visible to a single derive macro.
  109. //
  110. // When we need the global context, we fill in the String with the
  111. // appropriate values. See, `account_tys` as an example.
  112. AccountsStruct(CompositeField), // Composite
  113. Field(Field), // Primitive
  114. }
  115. #[derive(Debug)]
  116. pub struct CompositeField {
  117. pub ident: syn::Ident,
  118. pub symbol: String,
  119. pub constraints: Vec<Constraint>,
  120. pub raw_field: syn::Field,
  121. }
  122. // An account in the accounts struct.
  123. #[derive(Debug)]
  124. pub struct Field {
  125. pub ident: syn::Ident,
  126. pub ty: Ty,
  127. pub constraints: Vec<Constraint>,
  128. pub is_mut: bool,
  129. pub is_signer: bool,
  130. pub is_init: bool,
  131. }
  132. impl Field {
  133. pub fn typed_ident(&self) -> proc_macro2::TokenStream {
  134. let name = &self.ident;
  135. let ty = match &self.ty {
  136. Ty::AccountInfo => quote! { AccountInfo },
  137. Ty::ProgramAccount(ty) => {
  138. let account = &ty.account_ident;
  139. quote! {
  140. ProgramAccount<#account>
  141. }
  142. }
  143. Ty::CpiAccount(ty) => {
  144. let account = &ty.account_ident;
  145. quote! {
  146. CpiAccount<#account>
  147. }
  148. }
  149. Ty::Sysvar(ty) => {
  150. let account = match ty {
  151. SysvarTy::Clock => quote! {Clock},
  152. SysvarTy::Rent => quote! {Rent},
  153. SysvarTy::EpochSchedule => quote! {EpochSchedule},
  154. SysvarTy::Fees => quote! {Fees},
  155. SysvarTy::RecentBlockHashes => quote! {RecentBlockHashes},
  156. SysvarTy::SlotHashes => quote! {SlotHashes},
  157. SysvarTy::SlotHistory => quote! {SlotHistory},
  158. SysvarTy::StakeHistory => quote! {StakeHistory},
  159. SysvarTy::Instructions => quote! {Instructions},
  160. SysvarTy::Rewards => quote! {Rewards},
  161. };
  162. quote! {
  163. Sysvar<#account>
  164. }
  165. }
  166. };
  167. quote! {
  168. #name: #ty
  169. }
  170. }
  171. }
  172. // A type of an account field.
  173. #[derive(Debug, PartialEq)]
  174. pub enum Ty {
  175. AccountInfo,
  176. ProgramAccount(ProgramAccountTy),
  177. CpiAccount(CpiAccountTy),
  178. Sysvar(SysvarTy),
  179. }
  180. #[derive(Debug, PartialEq)]
  181. pub enum SysvarTy {
  182. Clock,
  183. Rent,
  184. EpochSchedule,
  185. Fees,
  186. RecentBlockHashes,
  187. SlotHashes,
  188. SlotHistory,
  189. StakeHistory,
  190. Instructions,
  191. Rewards,
  192. }
  193. #[derive(Debug, PartialEq)]
  194. pub struct ProgramAccountTy {
  195. // The struct type of the account.
  196. pub account_ident: syn::Ident,
  197. }
  198. #[derive(Debug, PartialEq)]
  199. pub struct CpiAccountTy {
  200. // The struct type of the account.
  201. pub account_ident: syn::Ident,
  202. }
  203. // An access control constraint for an account.
  204. #[derive(Debug)]
  205. pub enum Constraint {
  206. Signer(ConstraintSigner),
  207. BelongsTo(ConstraintBelongsTo),
  208. Literal(ConstraintLiteral),
  209. Owner(ConstraintOwner),
  210. RentExempt(ConstraintRentExempt),
  211. Seeds(ConstraintSeeds),
  212. }
  213. #[derive(Debug)]
  214. pub struct ConstraintBelongsTo {
  215. pub join_target: proc_macro2::Ident,
  216. }
  217. #[derive(Debug)]
  218. pub struct ConstraintSigner {}
  219. #[derive(Debug)]
  220. pub struct ConstraintLiteral {
  221. pub tokens: proc_macro2::TokenStream,
  222. }
  223. #[derive(Debug)]
  224. pub enum ConstraintOwner {
  225. Program,
  226. Skip,
  227. }
  228. #[derive(Debug)]
  229. pub enum ConstraintRentExempt {
  230. Enforce,
  231. Skip,
  232. }
  233. #[derive(Debug)]
  234. pub struct ConstraintSeeds {
  235. pub seeds: proc_macro2::Group,
  236. }
  237. #[derive(Debug)]
  238. pub struct Error {
  239. pub name: String,
  240. pub raw_enum: syn::ItemEnum,
  241. pub ident: syn::Ident,
  242. pub codes: Vec<ErrorCode>,
  243. }
  244. #[derive(Debug)]
  245. pub struct ErrorCode {
  246. pub id: u32,
  247. pub ident: syn::Ident,
  248. pub msg: Option<String>,
  249. }