lib.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 = "hash")]
  11. pub mod hash;
  12. #[cfg(not(feature = "hash"))]
  13. pub(crate) mod hash;
  14. #[cfg(feature = "idl")]
  15. pub mod idl;
  16. pub mod parser;
  17. #[derive(Debug)]
  18. pub struct Program {
  19. pub state: Option<State>,
  20. pub ixs: Vec<Ix>,
  21. pub name: syn::Ident,
  22. pub program_mod: syn::ItemMod,
  23. }
  24. // State struct singleton.
  25. #[derive(Debug)]
  26. pub struct State {
  27. pub name: String,
  28. pub strct: syn::ItemStruct,
  29. pub ctor_and_anchor: Option<(syn::ImplItemMethod, syn::Ident)>,
  30. pub impl_block_and_methods: Option<(syn::ItemImpl, Vec<StateIx>)>,
  31. pub interfaces: Option<Vec<StateInterface>>,
  32. pub is_zero_copy: bool,
  33. }
  34. #[derive(Debug)]
  35. pub struct StateIx {
  36. pub raw_method: syn::ImplItemMethod,
  37. pub ident: syn::Ident,
  38. pub args: Vec<IxArg>,
  39. pub anchor_ident: syn::Ident,
  40. // True if there exists a &self on the method.
  41. pub has_receiver: bool,
  42. }
  43. #[derive(Debug)]
  44. pub struct StateInterface {
  45. pub trait_name: String,
  46. pub methods: Vec<StateIx>,
  47. }
  48. #[derive(Debug)]
  49. pub struct Ix {
  50. pub raw_method: syn::ItemFn,
  51. pub ident: syn::Ident,
  52. pub args: Vec<IxArg>,
  53. // The ident for the struct deriving Accounts.
  54. pub anchor_ident: syn::Ident,
  55. }
  56. #[derive(Debug)]
  57. pub struct IxArg {
  58. pub name: proc_macro2::Ident,
  59. pub raw_arg: syn::PatType,
  60. }
  61. #[derive(Debug)]
  62. pub struct AccountsStruct {
  63. // Name of the accounts struct.
  64. pub ident: syn::Ident,
  65. // Generics + lifetimes on the accounts struct.
  66. pub generics: syn::Generics,
  67. // Fields on the accounts struct.
  68. pub fields: Vec<AccountField>,
  69. }
  70. impl AccountsStruct {
  71. pub fn new(strct: syn::ItemStruct, fields: Vec<AccountField>) -> Self {
  72. let ident = strct.ident.clone();
  73. let generics = strct.generics;
  74. Self {
  75. ident,
  76. generics,
  77. fields,
  78. }
  79. }
  80. // Returns all program owned accounts in the Accounts struct.
  81. //
  82. // `global_accs` is given to "link" account types that are embedded
  83. // in each other.
  84. pub fn account_tys(
  85. &self,
  86. global_accs: &HashMap<String, AccountsStruct>,
  87. ) -> Result<Vec<String>> {
  88. let mut tys = vec![];
  89. for f in &self.fields {
  90. match f {
  91. AccountField::Field(f) => {
  92. if let Ty::ProgramAccount(pty) = &f.ty {
  93. tys.push(pty.account_ident.to_string());
  94. }
  95. }
  96. AccountField::AccountsStruct(comp_f) => {
  97. let accs = global_accs.get(&comp_f.symbol).ok_or_else(|| {
  98. anyhow::format_err!("Invalid account type: {}", comp_f.symbol)
  99. })?;
  100. tys.extend(accs.account_tys(global_accs)?);
  101. }
  102. }
  103. }
  104. Ok(tys)
  105. }
  106. #[cfg(feature = "idl")]
  107. pub fn idl_accounts(
  108. &self,
  109. global_accs: &HashMap<String, AccountsStruct>,
  110. ) -> Vec<IdlAccountItem> {
  111. self.fields
  112. .iter()
  113. .map(|acc: &AccountField| match acc {
  114. AccountField::AccountsStruct(comp_f) => {
  115. let accs_strct = global_accs
  116. .get(&comp_f.symbol)
  117. .expect("Could not reslve Accounts symbol");
  118. let accounts = accs_strct.idl_accounts(global_accs);
  119. IdlAccountItem::IdlAccounts(IdlAccounts {
  120. name: comp_f.ident.to_string().to_mixed_case(),
  121. accounts,
  122. })
  123. }
  124. AccountField::Field(acc) => IdlAccountItem::IdlAccount(IdlAccount {
  125. name: acc.ident.to_string().to_mixed_case(),
  126. is_mut: acc.is_mut,
  127. is_signer: acc.is_signer,
  128. }),
  129. })
  130. .collect::<Vec<_>>()
  131. }
  132. }
  133. #[derive(Debug)]
  134. pub enum AccountField {
  135. // Use a `String` instead of the `AccountsStruct` because all
  136. // accounts structs aren't visible to a single derive macro.
  137. //
  138. // When we need the global context, we fill in the String with the
  139. // appropriate values. See, `account_tys` as an example.
  140. AccountsStruct(CompositeField), // Composite
  141. Field(Field), // Primitive
  142. }
  143. #[derive(Debug)]
  144. pub struct CompositeField {
  145. pub ident: syn::Ident,
  146. pub symbol: String,
  147. pub constraints: Vec<Constraint>,
  148. pub raw_field: syn::Field,
  149. }
  150. // An account in the accounts struct.
  151. #[derive(Debug)]
  152. pub struct Field {
  153. pub ident: syn::Ident,
  154. pub ty: Ty,
  155. pub constraints: Vec<Constraint>,
  156. pub is_mut: bool,
  157. pub is_signer: bool,
  158. pub is_init: bool,
  159. // TODO: move associated out of the constraints and put into tis own
  160. // field + struct.
  161. // Used by the associated attribute only.
  162. pub payer: Option<syn::Ident>,
  163. // Used by the associated attribute only.
  164. pub space: Option<proc_macro2::TokenStream>,
  165. // Used by the associated attribute only.
  166. pub associated_seeds: Vec<syn::Ident>,
  167. }
  168. impl Field {
  169. pub fn typed_ident(&self) -> proc_macro2::TokenStream {
  170. let name = &self.ident;
  171. let ty = match &self.ty {
  172. Ty::AccountInfo => quote! { AccountInfo },
  173. Ty::ProgramState(ty) => {
  174. let account = &ty.account_ident;
  175. quote! {
  176. ProgramState<#account>
  177. }
  178. }
  179. Ty::CpiState(ty) => {
  180. let account = &ty.account_ident;
  181. quote! {
  182. CpiState<#account>
  183. }
  184. }
  185. Ty::ProgramAccount(ty) => {
  186. let account = &ty.account_ident;
  187. quote! {
  188. ProgramAccount<#account>
  189. }
  190. }
  191. Ty::Loader(ty) => {
  192. let account = &ty.account_ident;
  193. quote! {
  194. Loader<#account>
  195. }
  196. }
  197. Ty::CpiAccount(ty) => {
  198. let account = &ty.account_ident;
  199. quote! {
  200. CpiAccount<#account>
  201. }
  202. }
  203. Ty::Sysvar(ty) => {
  204. let account = match ty {
  205. SysvarTy::Clock => quote! {Clock},
  206. SysvarTy::Rent => quote! {Rent},
  207. SysvarTy::EpochSchedule => quote! {EpochSchedule},
  208. SysvarTy::Fees => quote! {Fees},
  209. SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
  210. SysvarTy::SlotHashes => quote! {SlotHashes},
  211. SysvarTy::SlotHistory => quote! {SlotHistory},
  212. SysvarTy::StakeHistory => quote! {StakeHistory},
  213. SysvarTy::Instructions => quote! {Instructions},
  214. SysvarTy::Rewards => quote! {Rewards},
  215. };
  216. quote! {
  217. Sysvar<#account>
  218. }
  219. }
  220. };
  221. quote! {
  222. #name: #ty
  223. }
  224. }
  225. }
  226. // A type of an account field.
  227. #[derive(Debug, PartialEq)]
  228. pub enum Ty {
  229. AccountInfo,
  230. ProgramState(ProgramStateTy),
  231. CpiState(CpiStateTy),
  232. ProgramAccount(ProgramAccountTy),
  233. Loader(LoaderTy),
  234. CpiAccount(CpiAccountTy),
  235. Sysvar(SysvarTy),
  236. }
  237. #[derive(Debug, PartialEq)]
  238. pub enum SysvarTy {
  239. Clock,
  240. Rent,
  241. EpochSchedule,
  242. Fees,
  243. RecentBlockhashes,
  244. SlotHashes,
  245. SlotHistory,
  246. StakeHistory,
  247. Instructions,
  248. Rewards,
  249. }
  250. #[derive(Debug, PartialEq)]
  251. pub struct ProgramStateTy {
  252. pub account_ident: syn::Ident,
  253. }
  254. #[derive(Debug, PartialEq)]
  255. pub struct CpiStateTy {
  256. pub account_ident: syn::Ident,
  257. }
  258. #[derive(Debug, PartialEq)]
  259. pub struct ProgramAccountTy {
  260. // The struct type of the account.
  261. pub account_ident: syn::Ident,
  262. }
  263. #[derive(Debug, PartialEq)]
  264. pub struct CpiAccountTy {
  265. // The struct type of the account.
  266. pub account_ident: syn::Ident,
  267. }
  268. #[derive(Debug, PartialEq)]
  269. pub struct LoaderTy {
  270. // The struct type of the account.
  271. pub account_ident: syn::Ident,
  272. }
  273. // An access control constraint for an account.
  274. #[derive(Debug)]
  275. pub enum Constraint {
  276. Signer(ConstraintSigner),
  277. BelongsTo(ConstraintBelongsTo),
  278. Literal(ConstraintLiteral),
  279. Owner(ConstraintOwner),
  280. RentExempt(ConstraintRentExempt),
  281. Seeds(ConstraintSeeds),
  282. Executable(ConstraintExecutable),
  283. State(ConstraintState),
  284. Associated(ConstraintAssociated),
  285. }
  286. #[derive(Debug)]
  287. pub struct ConstraintBelongsTo {
  288. pub join_target: proc_macro2::Ident,
  289. }
  290. #[derive(Debug)]
  291. pub struct ConstraintSigner {}
  292. #[derive(Debug)]
  293. pub struct ConstraintLiteral {
  294. pub tokens: proc_macro2::TokenStream,
  295. }
  296. #[derive(Debug)]
  297. pub struct ConstraintOwner {
  298. pub owner_target: proc_macro2::Ident,
  299. }
  300. #[derive(Debug)]
  301. pub enum ConstraintRentExempt {
  302. Enforce,
  303. Skip,
  304. }
  305. #[derive(Debug)]
  306. pub struct ConstraintSeeds {
  307. pub seeds: proc_macro2::Group,
  308. }
  309. #[derive(Debug)]
  310. pub struct ConstraintExecutable {}
  311. #[derive(Debug)]
  312. pub struct ConstraintState {
  313. pub program_target: proc_macro2::Ident,
  314. }
  315. #[derive(Debug)]
  316. pub struct ConstraintAssociated {
  317. pub associated_target: proc_macro2::Ident,
  318. pub is_init: bool,
  319. }
  320. #[derive(Debug)]
  321. pub struct Error {
  322. pub name: String,
  323. pub raw_enum: syn::ItemEnum,
  324. pub ident: syn::Ident,
  325. pub codes: Vec<ErrorCode>,
  326. }
  327. #[derive(Debug)]
  328. pub struct ErrorCode {
  329. pub id: u32,
  330. pub ident: syn::Ident,
  331. pub msg: Option<String>,
  332. }