1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3pub mod codegen;
4pub mod parser;
5
6#[cfg(feature = "idl-build")]
7pub mod idl;
8
9#[cfg(feature = "hash")]
10pub mod hash;
11#[cfg(not(feature = "hash"))]
12pub(crate) mod hash;
13
14use {
15 codegen::{accounts as accounts_codegen, program as program_codegen},
16 parser::{accounts as accounts_parser, program as program_parser},
17 proc_macro2::{Span, TokenStream},
18 quote::{quote, ToTokens},
19 std::{collections::HashMap, ops::Deref},
20 syn::{
21 ext::IdentExt,
22 parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult},
23 punctuated::Punctuated,
24 spanned::Spanned,
25 token::Comma,
26 Attribute, Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, Lit, LitInt,
27 PatType, Token, Type, TypePath,
28 },
29};
30
31#[derive(Debug)]
32pub struct Program {
33 pub ixs: Vec<Ix>,
34 pub name: Ident,
35 pub docs: Option<Vec<String>>,
36 pub program_mod: ItemMod,
37 pub fallback_fn: Option<FallbackFn>,
38 pub program_args: Option<ProgramArgs>,
39}
40
41impl Parse for Program {
42 fn parse(input: ParseStream) -> ParseResult<Self> {
43 let program_mod = <ItemMod as Parse>::parse(input)?;
44 program_parser::parse(program_mod)
45 }
46}
47
48impl From<&Program> for TokenStream {
49 fn from(program: &Program) -> Self {
50 program_codegen::generate(program)
51 }
52}
53
54impl ToTokens for Program {
55 fn to_tokens(&self, tokens: &mut TokenStream) {
56 tokens.extend::<TokenStream>(self.into());
57 }
58}
59
60#[derive(Debug, Default)]
61pub struct ProgramArgs {
62 legacy_idl: bool,
63}
64
65impl Parse for ProgramArgs {
66 fn parse(input: ParseStream) -> syn::Result<Self> {
67 let mut parsed = Self::default();
68 let args = input.parse_terminated(Ident::parse, Token![,])?;
69
70 for arg in args {
71 match arg.to_string().as_str() {
72 "legacy_idl" => {
73 if parsed.legacy_idl {
74 return Err(syn::Error::new(
75 arg.span(),
76 "Duplicate `legacy_idl` argument",
77 ));
78 }
79 parsed.legacy_idl = true;
80 }
81 name => {
82 return Err(syn::Error::new(
83 arg.span(),
84 format!("Invalid argument `{name}`. Expected one of: `legacy_idl`"),
85 ));
86 }
87 }
88 }
89
90 Ok(parsed)
91 }
92}
93
94#[derive(Debug)]
95pub struct Ix {
96 pub raw_method: ItemFn,
97 pub ident: Ident,
98 pub docs: Option<Vec<String>>,
99 pub cfgs: Vec<Attribute>,
100 pub args: Vec<IxArg>,
101 pub returns: IxReturn,
102 pub anchor_ident: Ident,
104 pub overrides: Option<Overrides>,
106}
107
108#[derive(Debug, Default)]
110pub struct Overrides {
111 pub discriminator: Option<TokenStream>,
113}
114
115impl Parse for Overrides {
116 fn parse(input: ParseStream) -> ParseResult<Self> {
117 let mut attr = Self::default();
118 let args = input.parse_terminated(NamedArg::parse, Token![,])?;
119 for arg in args {
120 match arg.name.to_string().as_str() {
121 "discriminator" => {
122 let value = match &arg.value {
123 Expr::Lit(lit) if matches!(lit.lit, Lit::Int(_)) => quote! { &[#lit] },
125 Expr::Array(arr) => quote! { &#arr },
127 expr => expr.to_token_stream(),
128 };
129 attr.discriminator.replace(value)
130 }
131 name => {
132 return Err(ParseError::new(
133 arg.name.span(),
134 format!(
135 "Invalid argument `{}`. Expected one of: `discriminator`",
136 name
137 ),
138 ));
139 }
140 };
141 }
142
143 Ok(attr)
144 }
145}
146
147struct NamedArg {
148 name: Ident,
149 #[allow(dead_code)]
150 eq_token: Token![=],
151 value: Expr,
152}
153
154impl Parse for NamedArg {
155 fn parse(input: ParseStream) -> ParseResult<Self> {
156 Ok(Self {
157 name: input.parse()?,
158 eq_token: input.parse()?,
159 value: input.parse()?,
160 })
161 }
162}
163
164#[derive(Debug)]
165pub struct IxArg {
166 pub name: Ident,
167 pub docs: Option<Vec<String>>,
168 pub raw_arg: PatType,
169}
170
171#[derive(Debug)]
172pub struct IxReturn {
173 pub ty: Type,
174}
175
176#[derive(Debug)]
177pub struct FallbackFn {
178 raw_method: ItemFn,
179}
180
181#[derive(Debug)]
182pub struct AccountsStruct {
183 pub ident: Ident,
185 pub generics: Generics,
187 pub fields: Vec<AccountField>,
189 instruction_api: Option<Punctuated<syn::FnArg, Comma>>,
191}
192
193impl Parse for AccountsStruct {
194 fn parse(input: ParseStream) -> ParseResult<Self> {
195 let strct = <ItemStruct as Parse>::parse(input)?;
196 accounts_parser::parse(&strct)
197 }
198}
199
200impl From<&AccountsStruct> for TokenStream {
201 fn from(accounts: &AccountsStruct) -> Self {
202 accounts_codegen::generate(accounts)
203 }
204}
205
206impl ToTokens for AccountsStruct {
207 fn to_tokens(&self, tokens: &mut TokenStream) {
208 tokens.extend::<TokenStream>(self.into());
209 }
210}
211
212impl AccountsStruct {
213 pub fn new(
214 strct: ItemStruct,
215 fields: Vec<AccountField>,
216 instruction_api: Option<Punctuated<syn::FnArg, Comma>>,
217 ) -> Self {
218 let ident = strct.ident.clone();
219 let generics = strct.generics;
220 Self {
221 ident,
222 generics,
223 fields,
224 instruction_api,
225 }
226 }
227
228 pub fn instruction_args(&self) -> Option<HashMap<String, String>> {
232 self.instruction_api.as_ref().map(|instruction_api| {
233 instruction_api
234 .iter()
235 .map(|expr| {
236 let arg = parser::tts_to_string(expr);
237 let components: Vec<&str> = arg.split(" : ").collect();
238 assert!(components.len() == 2);
239 #[allow(
240 clippy::indexing_slicing,
241 reason = "len == 2 asserted immediately above"
242 )]
243 let result = (components[0].to_string(), components[1].to_string());
244 result
245 })
246 .collect()
247 })
248 }
249
250 pub fn field_names(&self) -> Vec<String> {
251 self.fields
252 .iter()
253 .map(|field| field.ident().to_string())
254 .collect()
255 }
256
257 pub fn has_optional(&self) -> bool {
258 for field in &self.fields {
259 if let AccountField::Field(field) = field {
260 if field.is_optional {
261 return true;
262 }
263 }
264 }
265 false
266 }
267
268 pub fn is_field_optional<T: quote::ToTokens>(&self, field: &T) -> bool {
269 let matching_field = self
270 .fields
271 .iter()
272 .find(|f| *f.ident() == parser::tts_to_string(field));
273 if let Some(matching_field) = matching_field {
274 matching_field.is_optional()
275 } else {
276 false
277 }
278 }
279}
280
281#[allow(clippy::large_enum_variant)]
282#[derive(Debug)]
283pub enum AccountField {
284 Field(Field),
285 CompositeField(CompositeField),
286}
287
288impl AccountField {
289 fn ident(&self) -> &Ident {
290 match self {
291 AccountField::Field(field) => &field.ident,
292 AccountField::CompositeField(c_field) => &c_field.ident,
293 }
294 }
295
296 fn is_optional(&self) -> bool {
297 match self {
298 AccountField::Field(field) => field.is_optional,
299 AccountField::CompositeField(_) => false,
300 }
301 }
302
303 pub fn ty_name(&self) -> Option<String> {
304 let qualified_ty_name = match self {
305 AccountField::Field(field) => match &field.ty {
306 Ty::Account(account) => Some(parser::tts_to_string(&account.account_type_path)),
307 Ty::LazyAccount(account) => Some(parser::tts_to_string(&account.account_type_path)),
308 _ => None,
309 },
310 AccountField::CompositeField(field) => Some(field.symbol.clone()),
311 };
312
313 qualified_ty_name.map(|name| match name.rsplit_once(" :: ") {
314 Some((_prefix, suffix)) => suffix.to_string(),
315 None => name,
316 })
317 }
318}
319
320#[derive(Debug)]
321pub struct Field {
322 pub ident: Ident,
323 pub constraints: ConstraintGroup,
324 pub ty: Ty,
325 pub is_optional: bool,
326 pub ty_span: Span,
327 pub docs: Option<Vec<String>>,
329}
330
331impl Field {
332 pub fn typed_ident(&self) -> proc_macro2::TokenStream {
333 let name = &self.ident;
334 let ty_decl = self.ty_decl(false);
335 quote! {
336 #name: #ty_decl
337 }
338 }
339
340 pub fn ty_decl(&self, ignore_option: bool) -> proc_macro2::TokenStream {
341 let account_ty = self.account_ty();
342 let container_ty = self.container_ty();
343 let inner_ty = match &self.ty {
344 Ty::AccountInfo => quote! {
345 AccountInfo
346 },
347 Ty::UncheckedAccount => quote! {
348 UncheckedAccount
349 },
350 Ty::Signer => quote! {
351 Signer
352 },
353 Ty::ProgramData => quote! {
354 ProgramData
355 },
356 Ty::SystemAccount => quote! {
357 SystemAccount
358 },
359 Ty::Account(AccountTy { boxed, .. })
360 | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
361 if *boxed {
362 quote! {
363 Box<#container_ty<#account_ty>>
364 }
365 } else {
366 quote! {
367 #container_ty<#account_ty>
368 }
369 }
370 }
371 Ty::Sysvar(ty) => {
372 let account = match ty {
373 SysvarTy::Clock => quote! {Clock},
374 SysvarTy::Rent => quote! {Rent},
375 SysvarTy::EpochSchedule => quote! {EpochSchedule},
376 SysvarTy::Fees => quote! {Fees},
377 SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
378 SysvarTy::SlotHashes => quote! {SlotHashes},
379 SysvarTy::SlotHistory => quote! {SlotHistory},
380 SysvarTy::StakeHistory => quote! {StakeHistory},
381 SysvarTy::Instructions => quote! {Instructions},
382 SysvarTy::Rewards => quote! {Rewards},
383 };
384 quote! {
385 Sysvar<#account>
386 }
387 }
388 Ty::Program(ty) => {
389 let program = &ty.account_type_path;
390 let program_str = quote!(#program).to_string();
392 if program_str == "__SolanaProgramUnitType" {
393 quote! {
394 #container_ty<'info>
395 }
396 } else {
397 quote! {
398 #container_ty<'info, #program>
399 }
400 }
401 }
402 Ty::Migration(ty) => {
403 let from = &ty.from_type_path;
404 let to = &ty.to_type_path;
405 quote! {
406 #container_ty<'info, #from, #to>
407 }
408 }
409 _ => quote! {
410 #container_ty<#account_ty>
411 },
412 };
413 if self.is_optional && !ignore_option {
414 quote! {
415 Option<#inner_ty>
416 }
417 } else {
418 quote! {
419 #inner_ty
420 }
421 }
422 }
423
424 pub fn from_account_info(
427 &self,
428 kind: Option<&InitKind>,
429 checked: bool,
430 ) -> proc_macro2::TokenStream {
431 let field = &self.ident;
432 let field_str = field.to_string();
433 let container_ty = self.container_ty();
434 let owner_addr = match &kind {
435 None => quote! { __program_id },
436 Some(InitKind::Program { .. }) => quote! {
437 __program_id
438 },
439 _ => quote! {
440 &anchor_spl::token::ID
441 },
442 };
443 match &self.ty {
444 Ty::AccountInfo => quote! { #field.to_account_info() },
445 Ty::UncheckedAccount => {
446 quote! { UncheckedAccount::try_from(&#field) }
447 }
448 Ty::Account(AccountTy { boxed, .. })
449 | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
450 let stream = if checked {
451 quote! {
452 match #container_ty::try_from(&#field) {
453 Ok(val) => val,
454 Err(e) => return Err(e.with_account_name(#field_str))
455 }
456 }
457 } else {
458 quote! {
459 match #container_ty::try_from_unchecked(&#field) {
460 Ok(val) => val,
461 Err(e) => return Err(e.with_account_name(#field_str))
462 }
463 }
464 };
465 if *boxed {
466 quote! {
467 Box::new(#stream)
468 }
469 } else {
470 stream
471 }
472 }
473 Ty::LazyAccount(_) => {
474 if checked {
475 quote! {
476 match #container_ty::try_from(&#field) {
477 Ok(val) => val,
478 Err(e) => return Err(e.with_account_name(#field_str))
479 }
480 }
481 } else {
482 quote! {
483 match #container_ty::try_from_unchecked(&#field) {
484 Ok(val) => val,
485 Err(e) => return Err(e.with_account_name(#field_str))
486 }
487 }
488 }
489 }
490 Ty::AccountLoader(_) => {
491 if checked {
492 quote! {
493 match #container_ty::try_from(&#field) {
494 Ok(val) => val,
495 Err(e) => return Err(e.with_account_name(#field_str))
496 }
497 }
498 } else {
499 quote! {
500 match #container_ty::try_from_unchecked(#owner_addr, &#field) {
501 Ok(val) => val,
502 Err(e) => return Err(e.with_account_name(#field_str))
503 }
504 }
505 }
506 }
507 _ => {
508 if checked {
509 quote! {
510 match #container_ty::try_from(#owner_addr, &#field) {
511 Ok(val) => val,
512 Err(e) => return Err(e.with_account_name(#field_str))
513 }
514 }
515 } else {
516 quote! {
517 match #container_ty::try_from_unchecked(#owner_addr, &#field) {
518 Ok(val) => val,
519 Err(e) => return Err(e.with_account_name(#field_str))
520 }
521 }
522 }
523 }
524 }
525 }
526
527 pub fn container_ty(&self) -> proc_macro2::TokenStream {
528 match &self.ty {
529 Ty::Account(_) => quote! {
530 anchor_lang::accounts::account::Account
531 },
532 Ty::LazyAccount(_) => quote! {
533 anchor_lang::accounts::lazy_account::LazyAccount
534 },
535 Ty::AccountLoader(_) => quote! {
536 anchor_lang::accounts::account_loader::AccountLoader
537 },
538 Ty::Migration(_) => quote! {
539 anchor_lang::accounts::migration::Migration
540 },
541 Ty::Sysvar(_) => quote! { anchor_lang::accounts::sysvar::Sysvar },
542 Ty::Program(_) => quote! { anchor_lang::accounts::program::Program },
543 Ty::Interface(_) => quote! { anchor_lang::accounts::interface::Interface },
544 Ty::InterfaceAccount(_) => {
545 quote! { anchor_lang::accounts::interface_account::InterfaceAccount }
546 }
547 Ty::AccountInfo => quote! {},
548 Ty::UncheckedAccount => quote! {},
549 Ty::Signer => quote! {},
550 Ty::SystemAccount => quote! {},
551 Ty::ProgramData => quote! {},
552 }
553 }
554
555 pub fn account_ty(&self) -> proc_macro2::TokenStream {
557 match &self.ty {
558 Ty::AccountInfo => quote! {
559 AccountInfo
560 },
561 Ty::UncheckedAccount => quote! {
562 UncheckedAccount
563 },
564 Ty::Signer => quote! {
565 Signer
566 },
567 Ty::SystemAccount => quote! {
568 SystemAccount
569 },
570 Ty::ProgramData => quote! {
571 ProgramData
572 },
573 Ty::Account(ty) => {
574 let ident = &ty.account_type_path;
575 quote! {
576 #ident
577 }
578 }
579 Ty::LazyAccount(ty) => {
580 let ident = &ty.account_type_path;
581 quote! {
582 #ident
583 }
584 }
585 Ty::InterfaceAccount(ty) => {
586 let ident = &ty.account_type_path;
587 quote! {
588 #ident
589 }
590 }
591 Ty::AccountLoader(ty) => {
592 let ident = &ty.account_type_path;
593 quote! {
594 #ident
595 }
596 }
597 Ty::Migration(ty) => {
598 let from = &ty.from_type_path;
600 quote! {
601 #from
602 }
603 }
604 Ty::Sysvar(ty) => match ty {
605 SysvarTy::Clock => quote! {Clock},
606 SysvarTy::Rent => quote! {Rent},
607 SysvarTy::EpochSchedule => quote! {EpochSchedule},
608 SysvarTy::Fees => quote! {Fees},
609 SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
610 SysvarTy::SlotHashes => quote! {SlotHashes},
611 SysvarTy::SlotHistory => quote! {SlotHistory},
612 SysvarTy::StakeHistory => quote! {StakeHistory},
613 SysvarTy::Instructions => quote! {Instructions},
614 SysvarTy::Rewards => quote! {Rewards},
615 },
616 Ty::Program(ty) => {
617 let program = &ty.account_type_path;
618 let program_str = quote!(#program).to_string();
620 if program_str == "__SolanaProgramUnitType" {
621 quote! {}
622 } else {
623 quote! {
624 #program
625 }
626 }
627 }
628 Ty::Interface(ty) => {
629 let program = &ty.account_type_path;
630 quote! {
631 #program
632 }
633 }
634 }
635 }
636}
637
638#[derive(Debug)]
639pub struct CompositeField {
640 pub ident: Ident,
641 pub constraints: ConstraintGroup,
642 pub symbol: String,
643 pub raw_field: syn::Field,
644 pub docs: Option<Vec<String>>,
646}
647
648#[derive(Debug, PartialEq, Eq)]
650pub enum Ty {
651 AccountInfo,
652 UncheckedAccount,
653 AccountLoader(AccountLoaderTy),
654 Sysvar(SysvarTy),
655 Account(AccountTy),
656 LazyAccount(LazyAccountTy),
657 Migration(MigrationTy),
658 Program(ProgramTy),
659 Interface(InterfaceTy),
660 InterfaceAccount(InterfaceAccountTy),
661 Signer,
662 SystemAccount,
663 ProgramData,
664}
665
666#[derive(Debug, PartialEq, Eq)]
667pub enum SysvarTy {
668 Clock,
669 Rent,
670 EpochSchedule,
671 Fees,
672 RecentBlockhashes,
673 SlotHashes,
674 SlotHistory,
675 StakeHistory,
676 Instructions,
677 Rewards,
678}
679
680#[derive(Debug, PartialEq, Eq)]
681pub struct AccountLoaderTy {
682 pub account_type_path: TypePath,
684}
685
686#[derive(Debug, PartialEq, Eq)]
687pub struct AccountTy {
688 pub account_type_path: TypePath,
690 pub boxed: bool,
692}
693
694#[derive(Debug, PartialEq, Eq)]
695pub struct LazyAccountTy {
696 pub account_type_path: TypePath,
698}
699
700#[derive(Debug, PartialEq, Eq)]
701pub struct MigrationTy {
702 pub from_type_path: TypePath,
704 pub to_type_path: TypePath,
705}
706
707#[derive(Debug, PartialEq, Eq)]
708pub struct InterfaceAccountTy {
709 pub account_type_path: TypePath,
711 pub boxed: bool,
713}
714
715#[derive(Debug, PartialEq, Eq)]
716pub struct ProgramTy {
717 pub account_type_path: TypePath,
719}
720
721#[derive(Debug, PartialEq, Eq)]
722pub struct InterfaceTy {
723 pub account_type_path: TypePath,
725}
726
727#[derive(Debug)]
728pub struct Error {
729 pub name: String,
730 pub raw_enum: ItemEnum,
731 pub ident: Ident,
732 pub codes: Vec<ErrorCode>,
733 pub args: Option<ErrorArgs>,
734}
735
736#[derive(Debug)]
737pub struct ErrorArgs {
738 pub offset: LitInt,
739}
740
741impl Parse for ErrorArgs {
742 fn parse(stream: ParseStream) -> ParseResult<Self> {
743 let offset_span = stream.span();
744 let offset = stream.call(Ident::parse_any)?;
745 if offset.to_string().as_str() != "offset" {
746 return Err(ParseError::new(offset_span, "expected keyword offset"));
747 }
748 stream.parse::<Token![=]>()?;
749 let offset: LitInt = stream.parse()?;
750 Ok(ErrorArgs { offset })
751 }
752}
753
754#[derive(Debug)]
755pub struct ErrorCode {
756 pub id: u32,
757 pub ident: Ident,
758 pub msg: Option<String>,
759}
760
761#[derive(Debug, Default, Clone)]
763pub struct ConstraintGroup {
764 pub init: Option<ConstraintInitGroup>,
765 pub zeroed: Option<ConstraintZeroed>,
766 pub mutable: Option<ConstraintMut>,
767 pub dup: Option<ConstraintDup>,
768 pub signer: Option<ConstraintSigner>,
769 pub owner: Option<ConstraintOwner>,
770 pub rent_exempt: Option<ConstraintRentExempt>,
771 pub seeds: Option<ConstraintSeedsGroup>,
772 pub executable: Option<ConstraintExecutable>,
773 pub has_one: Vec<ConstraintHasOne>,
774 pub raw: Vec<ConstraintRaw>,
775 pub close: Option<ConstraintClose>,
776 pub address: Option<ConstraintAddress>,
777 pub associated_token: Option<ConstraintAssociatedToken>,
778 pub token_account: Option<ConstraintTokenAccountGroup>,
779 pub mint: Option<ConstraintTokenMintGroup>,
780 pub realloc: Option<ConstraintReallocGroup>,
781}
782
783impl ConstraintGroup {
784 pub fn is_zeroed(&self) -> bool {
785 self.zeroed.is_some()
786 }
787
788 pub fn is_mutable(&self) -> bool {
789 self.mutable.is_some()
790 }
791
792 pub fn is_dup(&self) -> bool {
793 self.dup.is_some()
794 }
795
796 pub fn is_pure_init(&self) -> bool {
799 matches!(&self.init, Some(c) if !c.if_needed)
800 }
801
802 pub fn is_signer(&self) -> bool {
803 self.signer.is_some()
804 }
805
806 pub fn is_close(&self) -> bool {
807 self.close.is_some()
808 }
809}
810
811#[allow(clippy::large_enum_variant)]
815#[derive(Debug)]
816pub enum Constraint {
817 Init(ConstraintInitGroup),
818 Zeroed(ConstraintZeroed),
819 Mut(ConstraintMut),
820 Dup(ConstraintDup),
821 Signer(ConstraintSigner),
822 HasOne(ConstraintHasOne),
823 Raw(ConstraintRaw),
824 Owner(ConstraintOwner),
825 RentExempt(ConstraintRentExempt),
826 Seeds(ConstraintSeedsGroup),
827 AssociatedToken(ConstraintAssociatedToken),
828 Executable(ConstraintExecutable),
829 Close(ConstraintClose),
830 Address(ConstraintAddress),
831 TokenAccount(ConstraintTokenAccountGroup),
832 Mint(ConstraintTokenMintGroup),
833 Realloc(ConstraintReallocGroup),
834}
835
836#[allow(clippy::large_enum_variant)]
838#[derive(Debug)]
839pub enum ConstraintToken {
840 Init(Context<ConstraintInit>),
841 Zeroed(Context<ConstraintZeroed>),
842 Mut(Context<ConstraintMut>),
843 Dup(Context<ConstraintDup>),
844 Signer(Context<ConstraintSigner>),
845 HasOne(Context<ConstraintHasOne>),
846 Raw(Context<ConstraintRaw>),
847 Owner(Context<ConstraintOwner>),
848 RentExempt(Context<ConstraintRentExempt>),
849 Seeds(Context<ConstraintSeeds>),
850 Executable(Context<ConstraintExecutable>),
851 Close(Context<ConstraintClose>),
852 Payer(Context<ConstraintPayer>),
853 Space(Context<ConstraintSpace>),
854 Address(Context<ConstraintAddress>),
855 TokenMint(Context<ConstraintTokenMint>),
856 TokenAuthority(Context<ConstraintTokenAuthority>),
857 TokenTokenProgram(Context<ConstraintTokenProgram>),
858 AssociatedTokenMint(Context<ConstraintTokenMint>),
859 AssociatedTokenAuthority(Context<ConstraintTokenAuthority>),
860 AssociatedTokenTokenProgram(Context<ConstraintTokenProgram>),
861 MintAuthority(Context<ConstraintMintAuthority>),
862 MintFreezeAuthority(Context<ConstraintMintFreezeAuthority>),
863 MintDecimals(Context<ConstraintMintDecimals>),
864 MintTokenProgram(Context<ConstraintTokenProgram>),
865 Bump(Context<ConstraintTokenBump>),
866 ProgramSeed(Context<ConstraintProgramSeed>),
867 Realloc(Context<ConstraintRealloc>),
868 ReallocPayer(Context<ConstraintReallocPayer>),
869 ReallocZero(Context<ConstraintReallocZero>),
870 ExtensionGroupPointerAuthority(Context<ConstraintExtensionAuthority>),
872 ExtensionGroupPointerGroupAddress(Context<ConstraintExtensionGroupPointerGroupAddress>),
873 ExtensionGroupMemberPointerAuthority(Context<ConstraintExtensionAuthority>),
874 ExtensionGroupMemberPointerMemberAddress(
875 Context<ConstraintExtensionGroupMemberPointerMemberAddress>,
876 ),
877 ExtensionMetadataPointerAuthority(Context<ConstraintExtensionAuthority>),
878 ExtensionMetadataPointerMetadataAddress(
879 Context<ConstraintExtensionMetadataPointerMetadataAddress>,
880 ),
881 ExtensionCloseAuthority(Context<ConstraintExtensionAuthority>),
882 ExtensionTokenHookAuthority(Context<ConstraintExtensionAuthority>),
883 ExtensionTokenHookProgramId(Context<ConstraintExtensionTokenHookProgramId>),
884 ExtensionPermanentDelegate(Context<ConstraintExtensionPermanentDelegate>),
885}
886
887impl Parse for ConstraintToken {
888 fn parse(stream: ParseStream) -> ParseResult<Self> {
889 accounts_parser::constraints::parse_token(stream)
890 }
891}
892
893#[derive(Debug, Clone)]
894pub struct ConstraintInit {
895 pub if_needed: bool,
896}
897
898#[derive(Debug, Clone)]
899pub struct ConstraintInitIfNeeded {}
900
901#[derive(Debug, Clone)]
902pub struct ConstraintZeroed {}
903
904#[derive(Debug, Clone)]
905pub struct ConstraintMut {
906 pub error: Option<Expr>,
907}
908
909#[derive(Debug, Clone)]
910pub struct ConstraintDup {}
911
912#[derive(Debug, Clone)]
913pub struct ConstraintReallocGroup {
914 pub payer: Expr,
915 pub space: Expr,
916 pub zero: Expr,
917}
918
919#[derive(Debug, Clone)]
920pub struct ConstraintRealloc {
921 pub space: Expr,
922}
923
924#[derive(Debug, Clone)]
925pub struct ConstraintReallocPayer {
926 pub target: Expr,
927}
928
929#[derive(Debug, Clone)]
930pub struct ConstraintReallocZero {
931 pub zero: Expr,
932}
933
934#[derive(Debug, Clone)]
935pub struct ConstraintSigner {
936 pub error: Option<Expr>,
937}
938
939#[derive(Debug, Clone)]
940pub struct ConstraintHasOne {
941 pub join_target: Expr,
942 pub error: Option<Expr>,
943}
944
945#[derive(Debug, Clone)]
946pub struct ConstraintRaw {
947 pub raw: Expr,
948 pub error: Option<Expr>,
949}
950
951#[derive(Debug, Clone)]
952pub struct ConstraintOwner {
953 pub owner_address: Expr,
954 pub error: Option<Expr>,
955}
956
957#[derive(Debug, Clone)]
958pub struct ConstraintAddress {
959 pub address: Expr,
960 pub error: Option<Expr>,
961}
962
963#[derive(Debug, Clone)]
964pub enum ConstraintRentExempt {
965 Enforce,
966 Skip,
967}
968
969#[derive(Debug, Clone)]
970pub struct ConstraintInitGroup {
971 pub if_needed: bool,
972 pub seeds: Option<ConstraintSeedsGroup>,
973 pub payer: Expr,
974 pub space: Option<Expr>,
975 pub kind: InitKind,
976}
977
978#[derive(Debug, Clone)]
981pub enum SeedsExpr {
982 List(Punctuated<Expr, Token![,]>),
984 Expr(Box<Expr>),
986}
987
988impl SeedsExpr {
989 fn list_mut(&mut self) -> Option<&mut Punctuated<Expr, Token![,]>> {
991 match self {
992 SeedsExpr::List(list) => Some(list),
993 SeedsExpr::Expr(_) => None,
994 }
995 }
996
997 pub fn pop(&mut self) -> Option<syn::punctuated::Pair<Expr, Token![,]>> {
1002 self.list_mut()?.pop()
1003 }
1004
1005 pub fn push_value(&mut self, value: Expr) {
1006 if let Some(list) = self.list_mut() {
1007 list.push_value(value);
1008 }
1009 }
1010
1011 pub fn is_empty(&self) -> bool {
1015 match self {
1016 SeedsExpr::List(list) => list.is_empty(),
1017 SeedsExpr::Expr(_) => false, }
1019 }
1020
1021 pub fn iter(&self) -> Box<dyn Iterator<Item = &Expr> + '_> {
1023 match self {
1024 SeedsExpr::List(list) => Box::new(list.iter()),
1025 SeedsExpr::Expr(expr) => Box::new(std::iter::once(expr.as_ref())),
1026 }
1027 }
1028
1029 pub fn len(&self) -> usize {
1031 match self {
1032 SeedsExpr::List(list) => list.len(),
1033 SeedsExpr::Expr(_) => 1,
1034 }
1035 }
1036}
1037
1038impl quote::ToTokens for SeedsExpr {
1040 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1041 match self {
1042 SeedsExpr::List(list) => list.to_tokens(tokens),
1043 SeedsExpr::Expr(expr) => expr.to_tokens(tokens),
1044 }
1045 }
1046}
1047
1048impl syn::parse::Parse for SeedsExpr {
1049 fn parse(stream: syn::parse::ParseStream) -> syn::parse::Result<Self> {
1050 if stream.peek(syn::token::Bracket) {
1051 let content;
1052 syn::bracketed!(content in stream);
1053 let mut list: Punctuated<Expr, Token![,]> =
1054 content.parse_terminated(Expr::parse, Token![,])?;
1055 list.pop_punct();
1056
1057 Ok(SeedsExpr::List(list))
1058 } else {
1059 Ok(SeedsExpr::Expr(Box::new(stream.parse()?)))
1060 }
1061 }
1062}
1063
1064#[derive(Debug, Clone)]
1065pub struct ConstraintSeedsGroup {
1066 pub is_init: bool,
1067 pub seeds: SeedsExpr,
1068 pub bump: Option<Expr>, pub program_seed: Option<Expr>, }
1071
1072#[derive(Debug, Clone)]
1073pub struct ConstraintSeeds {
1074 pub seeds: SeedsExpr,
1075}
1076
1077#[derive(Debug, Clone)]
1078pub struct ConstraintExecutable {}
1079
1080#[derive(Debug, Clone)]
1081pub struct ConstraintPayer {
1082 pub target: Expr,
1083}
1084
1085#[derive(Debug, Clone)]
1086pub struct ConstraintSpace {
1087 pub space: Expr,
1088}
1089
1090#[derive(Debug, Clone)]
1092pub struct ConstraintExtensionAuthority {
1093 pub authority: Expr,
1094}
1095
1096#[derive(Debug, Clone)]
1097pub struct ConstraintExtensionGroupPointerGroupAddress {
1098 pub group_address: Expr,
1099}
1100
1101#[derive(Debug, Clone)]
1102pub struct ConstraintExtensionGroupMemberPointerMemberAddress {
1103 pub member_address: Expr,
1104}
1105
1106#[derive(Debug, Clone)]
1107pub struct ConstraintExtensionMetadataPointerMetadataAddress {
1108 pub metadata_address: Expr,
1109}
1110
1111#[derive(Debug, Clone)]
1112pub struct ConstraintExtensionTokenHookProgramId {
1113 pub program_id: Expr,
1114}
1115
1116#[derive(Debug, Clone)]
1117pub struct ConstraintExtensionPermanentDelegate {
1118 pub permanent_delegate: Expr,
1119}
1120
1121#[derive(Debug, Clone)]
1122#[allow(clippy::large_enum_variant)]
1123pub enum InitKind {
1124 Program {
1125 owner: Option<Expr>,
1126 },
1127 Interface {
1128 owner: Option<Expr>,
1129 },
1130 Token {
1133 owner: Expr,
1134 mint: Expr,
1135 token_program: Option<Expr>,
1136 },
1137 AssociatedToken {
1138 owner: Expr,
1139 mint: Expr,
1140 token_program: Option<Expr>,
1141 },
1142 Mint {
1143 owner: Expr,
1144 freeze_authority: Option<Expr>,
1145 decimals: Expr,
1146 token_program: Option<Expr>,
1147 group_pointer_authority: Option<Expr>,
1149 group_pointer_group_address: Option<Expr>,
1150 group_member_pointer_authority: Option<Expr>,
1151 group_member_pointer_member_address: Option<Expr>,
1152 metadata_pointer_authority: Option<Expr>,
1153 metadata_pointer_metadata_address: Option<Expr>,
1154 close_authority: Option<Expr>,
1155 permanent_delegate: Option<Expr>,
1156 transfer_hook_authority: Option<Expr>,
1157 transfer_hook_program_id: Option<Expr>,
1158 },
1159}
1160
1161#[derive(Debug, Clone)]
1162pub struct ConstraintClose {
1163 pub sol_dest: Ident,
1164}
1165
1166#[derive(Debug, Clone)]
1167pub struct ConstraintTokenMint {
1168 pub mint: Expr,
1169}
1170
1171#[derive(Debug, Clone)]
1172pub struct ConstraintMintConfidentialTransferData {
1173 pub confidential_transfer_data: Expr,
1174}
1175
1176#[derive(Debug, Clone)]
1177pub struct ConstraintMintMetadata {
1178 pub token_metadata: Expr,
1179}
1180
1181#[derive(Debug, Clone)]
1182pub struct ConstraintMintTokenGroupData {
1183 pub token_group_data: Expr,
1184}
1185
1186#[derive(Debug, Clone)]
1187pub struct ConstraintMintTokenGroupMemberData {
1188 pub token_group_member_data: Expr,
1189}
1190
1191#[derive(Debug, Clone)]
1192pub struct ConstraintMintMetadataPointerData {
1193 pub metadata_pointer_data: Expr,
1194}
1195
1196#[derive(Debug, Clone)]
1197pub struct ConstraintMintGroupPointerData {
1198 pub group_pointer_data: Expr,
1199}
1200
1201#[derive(Debug, Clone)]
1202pub struct ConstraintMintGroupMemberPointerData {
1203 pub group_member_pointer_data: Expr,
1204}
1205
1206#[derive(Debug, Clone)]
1207pub struct ConstraintMintCloseAuthority {
1208 pub close_authority: Expr,
1209}
1210
1211#[derive(Debug, Clone)]
1212pub struct ConstraintTokenAuthority {
1213 pub auth: Expr,
1214}
1215
1216#[derive(Debug, Clone)]
1217pub struct ConstraintTokenProgram {
1218 token_program: Expr,
1219}
1220
1221#[derive(Debug, Clone)]
1222pub struct ConstraintMintAuthority {
1223 pub mint_auth: Expr,
1224}
1225
1226#[derive(Debug, Clone)]
1227pub struct ConstraintMintFreezeAuthority {
1228 pub mint_freeze_auth: Expr,
1229}
1230
1231#[derive(Debug, Clone)]
1232pub struct ConstraintMintDecimals {
1233 pub decimals: Expr,
1234}
1235
1236#[derive(Debug, Clone)]
1237pub struct ConstraintTokenBump {
1238 pub bump: Option<Expr>,
1239}
1240
1241#[derive(Debug, Clone)]
1242pub struct ConstraintProgramSeed {
1243 pub program_seed: Expr,
1244}
1245
1246#[derive(Debug, Clone)]
1247pub struct ConstraintAssociatedToken {
1248 pub wallet: Expr,
1249 pub mint: Expr,
1250 pub token_program: Option<Expr>,
1251}
1252
1253#[derive(Debug, Clone)]
1254pub struct ConstraintTokenAccountGroup {
1255 pub mint: Option<Expr>,
1256 pub authority: Option<Expr>,
1257 pub token_program: Option<Expr>,
1258}
1259
1260#[derive(Debug, Clone)]
1261pub struct ConstraintTokenMintGroup {
1262 pub decimals: Option<Expr>,
1263 pub mint_authority: Option<Expr>,
1264 pub freeze_authority: Option<Expr>,
1265 pub token_program: Option<Expr>,
1266 pub group_pointer_authority: Option<Expr>,
1267 pub group_pointer_group_address: Option<Expr>,
1268 pub group_member_pointer_authority: Option<Expr>,
1269 pub group_member_pointer_member_address: Option<Expr>,
1270 pub metadata_pointer_authority: Option<Expr>,
1271 pub metadata_pointer_metadata_address: Option<Expr>,
1272 pub close_authority: Option<Expr>,
1273 pub permanent_delegate: Option<Expr>,
1274 pub transfer_hook_authority: Option<Expr>,
1275 pub transfer_hook_program_id: Option<Expr>,
1276}
1277
1278#[derive(Debug, Clone)]
1280pub struct Context<T> {
1281 span: Span,
1282 inner: T,
1283}
1284
1285impl<T> Context<T> {
1286 pub fn new(span: Span, inner: T) -> Self {
1287 Self { span, inner }
1288 }
1289
1290 pub fn into_inner(self) -> T {
1291 self.inner
1292 }
1293}
1294
1295impl<T> Deref for Context<T> {
1296 type Target = T;
1297
1298 fn deref(&self) -> &Self::Target {
1299 &self.inner
1300 }
1301}
1302
1303impl<T> Context<T> {
1304 pub fn span(&self) -> Span {
1305 self.span
1306 }
1307}
1308
1309impl<T: ToTokens> ToTokens for Context<T> {
1310 fn to_tokens(&self, tokens: &mut TokenStream) {
1311 self.inner.to_tokens(tokens)
1312 }
1313}