lib.rs 8.2 KB

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