anchor_syn/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_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 codegen::accounts as accounts_codegen;
15use codegen::program as program_codegen;
16use parser::accounts as accounts_parser;
17use parser::program as program_parser;
18use proc_macro2::{Span, TokenStream};
19use quote::quote;
20use quote::ToTokens;
21use std::collections::HashMap;
22use std::ops::Deref;
23use syn::ext::IdentExt;
24use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult};
25use syn::punctuated::Punctuated;
26use syn::spanned::Spanned;
27use syn::token::Comma;
28use syn::Attribute;
29use syn::Lit;
30use syn::{
31    Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, LitInt, PatType, Token, Type,
32    TypePath,
33};
34
35#[derive(Debug)]
36pub struct Program {
37    pub ixs: Vec<Ix>,
38    pub name: Ident,
39    pub docs: Option<Vec<String>>,
40    pub program_mod: ItemMod,
41    pub fallback_fn: Option<FallbackFn>,
42}
43
44impl Parse for Program {
45    fn parse(input: ParseStream) -> ParseResult<Self> {
46        let program_mod = <ItemMod as Parse>::parse(input)?;
47        program_parser::parse(program_mod)
48    }
49}
50
51impl From<&Program> for TokenStream {
52    fn from(program: &Program) -> Self {
53        program_codegen::generate(program)
54    }
55}
56
57impl ToTokens for Program {
58    fn to_tokens(&self, tokens: &mut TokenStream) {
59        tokens.extend::<TokenStream>(self.into());
60    }
61}
62
63#[derive(Debug)]
64pub struct Ix {
65    pub raw_method: ItemFn,
66    pub ident: Ident,
67    pub docs: Option<Vec<String>>,
68    pub cfgs: Vec<Attribute>,
69    pub args: Vec<IxArg>,
70    pub returns: IxReturn,
71    // The ident for the struct deriving Accounts.
72    pub anchor_ident: Ident,
73    // The discriminator based on the `#[interface]` attribute.
74    // TODO: Remove and use `overrides`
75    pub interface_discriminator: Option<[u8; 8]>,
76    /// Overrides coming from the `#[instruction]` attribute
77    pub overrides: Option<Overrides>,
78}
79
80/// Common overrides for the `#[instruction]`, `#[account]` and `#[event]` attributes
81#[derive(Debug, Default)]
82pub struct Overrides {
83    /// Override the default 8-byte discriminator
84    pub discriminator: Option<TokenStream>,
85}
86
87impl Parse for Overrides {
88    fn parse(input: ParseStream) -> ParseResult<Self> {
89        let mut attr = Self::default();
90        let args = input.parse_terminated::<_, Comma>(NamedArg::parse)?;
91        for arg in args {
92            match arg.name.to_string().as_str() {
93                "discriminator" => {
94                    let value = match &arg.value {
95                        // Allow `discriminator = 42`
96                        Expr::Lit(lit) if matches!(lit.lit, Lit::Int(_)) => quote! { &[#lit] },
97                        // Allow `discriminator = [0, 1, 2, 3]`
98                        Expr::Array(arr) => quote! { &#arr },
99                        expr => expr.to_token_stream(),
100                    };
101                    attr.discriminator.replace(value)
102                }
103                _ => return Err(ParseError::new(arg.name.span(), "Invalid argument")),
104            };
105        }
106
107        Ok(attr)
108    }
109}
110
111struct NamedArg {
112    name: Ident,
113    #[allow(dead_code)]
114    eq_token: Token![=],
115    value: Expr,
116}
117
118impl Parse for NamedArg {
119    fn parse(input: ParseStream) -> ParseResult<Self> {
120        Ok(Self {
121            name: input.parse()?,
122            eq_token: input.parse()?,
123            value: input.parse()?,
124        })
125    }
126}
127
128#[derive(Debug)]
129pub struct IxArg {
130    pub name: Ident,
131    pub docs: Option<Vec<String>>,
132    pub raw_arg: PatType,
133}
134
135#[derive(Debug)]
136pub struct IxReturn {
137    pub ty: Type,
138}
139
140#[derive(Debug)]
141pub struct FallbackFn {
142    raw_method: ItemFn,
143}
144
145#[derive(Debug)]
146pub struct AccountsStruct {
147    // Name of the accounts struct.
148    pub ident: Ident,
149    // Generics + lifetimes on the accounts struct.
150    pub generics: Generics,
151    // Fields on the accounts struct.
152    pub fields: Vec<AccountField>,
153    // Instruction data api expression.
154    instruction_api: Option<Punctuated<Expr, Comma>>,
155}
156
157impl Parse for AccountsStruct {
158    fn parse(input: ParseStream) -> ParseResult<Self> {
159        let strct = <ItemStruct as Parse>::parse(input)?;
160        accounts_parser::parse(&strct)
161    }
162}
163
164impl From<&AccountsStruct> for TokenStream {
165    fn from(accounts: &AccountsStruct) -> Self {
166        accounts_codegen::generate(accounts)
167    }
168}
169
170impl ToTokens for AccountsStruct {
171    fn to_tokens(&self, tokens: &mut TokenStream) {
172        tokens.extend::<TokenStream>(self.into());
173    }
174}
175
176impl AccountsStruct {
177    pub fn new(
178        strct: ItemStruct,
179        fields: Vec<AccountField>,
180        instruction_api: Option<Punctuated<Expr, Comma>>,
181    ) -> Self {
182        let ident = strct.ident.clone();
183        let generics = strct.generics;
184        Self {
185            ident,
186            generics,
187            fields,
188            instruction_api,
189        }
190    }
191
192    // Return value maps instruction name to type.
193    // E.g. if we have `#[instruction(data: u64)]` then returns
194    // { "data": "u64"}.
195    pub fn instruction_args(&self) -> Option<HashMap<String, String>> {
196        self.instruction_api.as_ref().map(|instruction_api| {
197            instruction_api
198                .iter()
199                .map(|expr| {
200                    let arg = parser::tts_to_string(expr);
201                    let components: Vec<&str> = arg.split(" : ").collect();
202                    assert!(components.len() == 2);
203                    (components[0].to_string(), components[1].to_string())
204                })
205                .collect()
206        })
207    }
208
209    pub fn field_names(&self) -> Vec<String> {
210        self.fields
211            .iter()
212            .map(|field| field.ident().to_string())
213            .collect()
214    }
215
216    pub fn has_optional(&self) -> bool {
217        for field in &self.fields {
218            if let AccountField::Field(field) = field {
219                if field.is_optional {
220                    return true;
221                }
222            }
223        }
224        false
225    }
226
227    pub fn is_field_optional<T: quote::ToTokens>(&self, field: &T) -> bool {
228        let matching_field = self
229            .fields
230            .iter()
231            .find(|f| *f.ident() == parser::tts_to_string(field));
232        if let Some(matching_field) = matching_field {
233            matching_field.is_optional()
234        } else {
235            false
236        }
237    }
238}
239
240#[allow(clippy::large_enum_variant)]
241#[derive(Debug)]
242pub enum AccountField {
243    Field(Field),
244    CompositeField(CompositeField),
245}
246
247impl AccountField {
248    fn ident(&self) -> &Ident {
249        match self {
250            AccountField::Field(field) => &field.ident,
251            AccountField::CompositeField(c_field) => &c_field.ident,
252        }
253    }
254
255    fn is_optional(&self) -> bool {
256        match self {
257            AccountField::Field(field) => field.is_optional,
258            AccountField::CompositeField(_) => false,
259        }
260    }
261
262    pub fn ty_name(&self) -> Option<String> {
263        let qualified_ty_name = match self {
264            AccountField::Field(field) => match &field.ty {
265                Ty::Account(account) => Some(parser::tts_to_string(&account.account_type_path)),
266                Ty::LazyAccount(account) => Some(parser::tts_to_string(&account.account_type_path)),
267                _ => None,
268            },
269            AccountField::CompositeField(field) => Some(field.symbol.clone()),
270        };
271
272        qualified_ty_name.map(|name| match name.rsplit_once(" :: ") {
273            Some((_prefix, suffix)) => suffix.to_string(),
274            None => name,
275        })
276    }
277}
278
279#[derive(Debug)]
280pub struct Field {
281    pub ident: Ident,
282    pub constraints: ConstraintGroup,
283    pub ty: Ty,
284    pub is_optional: bool,
285    /// IDL Doc comment
286    pub docs: Option<Vec<String>>,
287}
288
289impl Field {
290    pub fn typed_ident(&self) -> proc_macro2::TokenStream {
291        let name = &self.ident;
292        let ty_decl = self.ty_decl(false);
293        quote! {
294            #name: #ty_decl
295        }
296    }
297
298    pub fn ty_decl(&self, ignore_option: bool) -> proc_macro2::TokenStream {
299        let account_ty = self.account_ty();
300        let container_ty = self.container_ty();
301        let inner_ty = match &self.ty {
302            Ty::AccountInfo => quote! {
303                AccountInfo
304            },
305            Ty::UncheckedAccount => quote! {
306                UncheckedAccount
307            },
308            Ty::Signer => quote! {
309                Signer
310            },
311            Ty::ProgramData => quote! {
312                ProgramData
313            },
314            Ty::SystemAccount => quote! {
315                SystemAccount
316            },
317            Ty::Account(AccountTy { boxed, .. })
318            | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
319                if *boxed {
320                    quote! {
321                        Box<#container_ty<#account_ty>>
322                    }
323                } else {
324                    quote! {
325                        #container_ty<#account_ty>
326                    }
327                }
328            }
329            Ty::Sysvar(ty) => {
330                let account = match ty {
331                    SysvarTy::Clock => quote! {Clock},
332                    SysvarTy::Rent => quote! {Rent},
333                    SysvarTy::EpochSchedule => quote! {EpochSchedule},
334                    SysvarTy::Fees => quote! {Fees},
335                    SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
336                    SysvarTy::SlotHashes => quote! {SlotHashes},
337                    SysvarTy::SlotHistory => quote! {SlotHistory},
338                    SysvarTy::StakeHistory => quote! {StakeHistory},
339                    SysvarTy::Instructions => quote! {Instructions},
340                    SysvarTy::Rewards => quote! {Rewards},
341                };
342                quote! {
343                    Sysvar<#account>
344                }
345            }
346            _ => quote! {
347                #container_ty<#account_ty>
348            },
349        };
350        if self.is_optional && !ignore_option {
351            quote! {
352                Option<#inner_ty>
353            }
354        } else {
355            quote! {
356                #inner_ty
357            }
358        }
359    }
360
361    // Ignores optional accounts. Optional account checks and handing should be done prior to this
362    // function being called.
363    pub fn from_account_info(
364        &self,
365        kind: Option<&InitKind>,
366        checked: bool,
367    ) -> proc_macro2::TokenStream {
368        let field = &self.ident;
369        let field_str = field.to_string();
370        let container_ty = self.container_ty();
371        let owner_addr = match &kind {
372            None => quote! { __program_id },
373            Some(InitKind::Program { .. }) => quote! {
374                __program_id
375            },
376            _ => quote! {
377                &anchor_spl::token::ID
378            },
379        };
380        match &self.ty {
381            Ty::AccountInfo => quote! { #field.to_account_info() },
382            Ty::UncheckedAccount => {
383                quote! { UncheckedAccount::try_from(&#field) }
384            }
385            Ty::Account(AccountTy { boxed, .. })
386            | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
387                let stream = if checked {
388                    quote! {
389                        match #container_ty::try_from(&#field) {
390                            Ok(val) => val,
391                            Err(e) => return Err(e.with_account_name(#field_str))
392                        }
393                    }
394                } else {
395                    quote! {
396                        match #container_ty::try_from_unchecked(&#field) {
397                            Ok(val) => val,
398                            Err(e) => return Err(e.with_account_name(#field_str))
399                        }
400                    }
401                };
402                if *boxed {
403                    quote! {
404                        Box::new(#stream)
405                    }
406                } else {
407                    stream
408                }
409            }
410            Ty::LazyAccount(_) => {
411                if checked {
412                    quote! {
413                        match #container_ty::try_from(&#field) {
414                            Ok(val) => val,
415                            Err(e) => return Err(e.with_account_name(#field_str))
416                        }
417                    }
418                } else {
419                    quote! {
420                        match #container_ty::try_from_unchecked(&#field) {
421                            Ok(val) => val,
422                            Err(e) => return Err(e.with_account_name(#field_str))
423                        }
424                    }
425                }
426            }
427            Ty::AccountLoader(_) => {
428                if checked {
429                    quote! {
430                        match #container_ty::try_from(&#field) {
431                            Ok(val) => val,
432                            Err(e) => return Err(e.with_account_name(#field_str))
433                        }
434                    }
435                } else {
436                    quote! {
437                        match #container_ty::try_from_unchecked(#owner_addr, &#field) {
438                            Ok(val) => val,
439                            Err(e) => return Err(e.with_account_name(#field_str))
440                        }
441                    }
442                }
443            }
444            _ => {
445                if checked {
446                    quote! {
447                        match #container_ty::try_from(#owner_addr, &#field) {
448                            Ok(val) => val,
449                            Err(e) => return Err(e.with_account_name(#field_str))
450                        }
451                    }
452                } else {
453                    quote! {
454                        match #container_ty::try_from_unchecked(#owner_addr, &#field) {
455                            Ok(val) => val,
456                            Err(e) => return Err(e.with_account_name(#field_str))
457                        }
458                    }
459                }
460            }
461        }
462    }
463
464    pub fn container_ty(&self) -> proc_macro2::TokenStream {
465        match &self.ty {
466            Ty::Account(_) => quote! {
467                anchor_lang::accounts::account::Account
468            },
469            Ty::LazyAccount(_) => quote! {
470                anchor_lang::accounts::lazy_account::LazyAccount
471            },
472            Ty::AccountLoader(_) => quote! {
473                anchor_lang::accounts::account_loader::AccountLoader
474            },
475            Ty::Sysvar(_) => quote! { anchor_lang::accounts::sysvar::Sysvar },
476            Ty::Program(_) => quote! { anchor_lang::accounts::program::Program },
477            Ty::Interface(_) => quote! { anchor_lang::accounts::interface::Interface },
478            Ty::InterfaceAccount(_) => {
479                quote! { anchor_lang::accounts::interface_account::InterfaceAccount }
480            }
481            Ty::AccountInfo => quote! {},
482            Ty::UncheckedAccount => quote! {},
483            Ty::Signer => quote! {},
484            Ty::SystemAccount => quote! {},
485            Ty::ProgramData => quote! {},
486        }
487    }
488
489    // Returns the inner account struct type.
490    pub fn account_ty(&self) -> proc_macro2::TokenStream {
491        match &self.ty {
492            Ty::AccountInfo => quote! {
493                AccountInfo
494            },
495            Ty::UncheckedAccount => quote! {
496                UncheckedAccount
497            },
498            Ty::Signer => quote! {
499                Signer
500            },
501            Ty::SystemAccount => quote! {
502                SystemAccount
503            },
504            Ty::ProgramData => quote! {
505                ProgramData
506            },
507            Ty::Account(ty) => {
508                let ident = &ty.account_type_path;
509                quote! {
510                    #ident
511                }
512            }
513            Ty::LazyAccount(ty) => {
514                let ident = &ty.account_type_path;
515                quote! {
516                    #ident
517                }
518            }
519            Ty::InterfaceAccount(ty) => {
520                let ident = &ty.account_type_path;
521                quote! {
522                    #ident
523                }
524            }
525            Ty::AccountLoader(ty) => {
526                let ident = &ty.account_type_path;
527                quote! {
528                    #ident
529                }
530            }
531            Ty::Sysvar(ty) => match ty {
532                SysvarTy::Clock => quote! {Clock},
533                SysvarTy::Rent => quote! {Rent},
534                SysvarTy::EpochSchedule => quote! {EpochSchedule},
535                SysvarTy::Fees => quote! {Fees},
536                SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
537                SysvarTy::SlotHashes => quote! {SlotHashes},
538                SysvarTy::SlotHistory => quote! {SlotHistory},
539                SysvarTy::StakeHistory => quote! {StakeHistory},
540                SysvarTy::Instructions => quote! {Instructions},
541                SysvarTy::Rewards => quote! {Rewards},
542            },
543            Ty::Program(ty) => {
544                let program = &ty.account_type_path;
545                quote! {
546                    #program
547                }
548            }
549            Ty::Interface(ty) => {
550                let program = &ty.account_type_path;
551                quote! {
552                    #program
553                }
554            }
555        }
556    }
557}
558
559#[derive(Debug)]
560pub struct CompositeField {
561    pub ident: Ident,
562    pub constraints: ConstraintGroup,
563    pub symbol: String,
564    pub raw_field: syn::Field,
565    /// IDL Doc comment
566    pub docs: Option<Vec<String>>,
567}
568
569// A type of an account field.
570#[derive(Debug, PartialEq, Eq)]
571pub enum Ty {
572    AccountInfo,
573    UncheckedAccount,
574    AccountLoader(AccountLoaderTy),
575    Sysvar(SysvarTy),
576    Account(AccountTy),
577    LazyAccount(LazyAccountTy),
578    Program(ProgramTy),
579    Interface(InterfaceTy),
580    InterfaceAccount(InterfaceAccountTy),
581    Signer,
582    SystemAccount,
583    ProgramData,
584}
585
586#[derive(Debug, PartialEq, Eq)]
587pub enum SysvarTy {
588    Clock,
589    Rent,
590    EpochSchedule,
591    Fees,
592    RecentBlockhashes,
593    SlotHashes,
594    SlotHistory,
595    StakeHistory,
596    Instructions,
597    Rewards,
598}
599
600#[derive(Debug, PartialEq, Eq)]
601pub struct AccountLoaderTy {
602    // The struct type of the account.
603    pub account_type_path: TypePath,
604}
605
606#[derive(Debug, PartialEq, Eq)]
607pub struct AccountTy {
608    // The struct type of the account.
609    pub account_type_path: TypePath,
610    // True if the account has been boxed via `Box<T>`.
611    pub boxed: bool,
612}
613
614#[derive(Debug, PartialEq, Eq)]
615pub struct LazyAccountTy {
616    // The struct type of the account.
617    pub account_type_path: TypePath,
618}
619
620#[derive(Debug, PartialEq, Eq)]
621pub struct InterfaceAccountTy {
622    // The struct type of the account.
623    pub account_type_path: TypePath,
624    // True if the account has been boxed via `Box<T>`.
625    pub boxed: bool,
626}
627
628#[derive(Debug, PartialEq, Eq)]
629pub struct ProgramTy {
630    // The struct type of the account.
631    pub account_type_path: TypePath,
632}
633
634#[derive(Debug, PartialEq, Eq)]
635pub struct InterfaceTy {
636    // The struct type of the account.
637    pub account_type_path: TypePath,
638}
639
640#[derive(Debug)]
641pub struct Error {
642    pub name: String,
643    pub raw_enum: ItemEnum,
644    pub ident: Ident,
645    pub codes: Vec<ErrorCode>,
646    pub args: Option<ErrorArgs>,
647}
648
649#[derive(Debug)]
650pub struct ErrorArgs {
651    pub offset: LitInt,
652}
653
654impl Parse for ErrorArgs {
655    fn parse(stream: ParseStream) -> ParseResult<Self> {
656        let offset_span = stream.span();
657        let offset = stream.call(Ident::parse_any)?;
658        if offset.to_string().as_str() != "offset" {
659            return Err(ParseError::new(offset_span, "expected keyword offset"));
660        }
661        stream.parse::<Token![=]>()?;
662        Ok(ErrorArgs {
663            offset: stream.parse()?,
664        })
665    }
666}
667
668#[derive(Debug)]
669pub struct ErrorCode {
670    pub id: u32,
671    pub ident: Ident,
672    pub msg: Option<String>,
673}
674
675// All well formed constraints on a single `Accounts` field.
676#[derive(Debug, Default, Clone)]
677pub struct ConstraintGroup {
678    pub init: Option<ConstraintInitGroup>,
679    pub zeroed: Option<ConstraintZeroed>,
680    pub mutable: Option<ConstraintMut>,
681    pub signer: Option<ConstraintSigner>,
682    pub owner: Option<ConstraintOwner>,
683    pub rent_exempt: Option<ConstraintRentExempt>,
684    pub seeds: Option<ConstraintSeedsGroup>,
685    pub executable: Option<ConstraintExecutable>,
686    pub has_one: Vec<ConstraintHasOne>,
687    pub raw: Vec<ConstraintRaw>,
688    pub close: Option<ConstraintClose>,
689    pub address: Option<ConstraintAddress>,
690    pub associated_token: Option<ConstraintAssociatedToken>,
691    pub token_account: Option<ConstraintTokenAccountGroup>,
692    pub mint: Option<ConstraintTokenMintGroup>,
693    pub realloc: Option<ConstraintReallocGroup>,
694}
695
696impl ConstraintGroup {
697    pub fn is_zeroed(&self) -> bool {
698        self.zeroed.is_some()
699    }
700
701    pub fn is_mutable(&self) -> bool {
702        self.mutable.is_some()
703    }
704
705    pub fn is_signer(&self) -> bool {
706        self.signer.is_some()
707    }
708
709    pub fn is_close(&self) -> bool {
710        self.close.is_some()
711    }
712}
713
714// A single account constraint *after* merging all tokens into a well formed
715// constraint. Some constraints like "seeds" are defined by multiple
716// tokens, so a merging phase is required.
717#[allow(clippy::large_enum_variant)]
718#[derive(Debug)]
719pub enum Constraint {
720    Init(ConstraintInitGroup),
721    Zeroed(ConstraintZeroed),
722    Mut(ConstraintMut),
723    Signer(ConstraintSigner),
724    HasOne(ConstraintHasOne),
725    Raw(ConstraintRaw),
726    Owner(ConstraintOwner),
727    RentExempt(ConstraintRentExempt),
728    Seeds(ConstraintSeedsGroup),
729    AssociatedToken(ConstraintAssociatedToken),
730    Executable(ConstraintExecutable),
731    Close(ConstraintClose),
732    Address(ConstraintAddress),
733    TokenAccount(ConstraintTokenAccountGroup),
734    Mint(ConstraintTokenMintGroup),
735    Realloc(ConstraintReallocGroup),
736}
737
738// Constraint token is a single keyword in a `#[account(<TOKEN>)]` attribute.
739#[allow(clippy::large_enum_variant)]
740#[derive(Debug)]
741pub enum ConstraintToken {
742    Init(Context<ConstraintInit>),
743    Zeroed(Context<ConstraintZeroed>),
744    Mut(Context<ConstraintMut>),
745    Signer(Context<ConstraintSigner>),
746    HasOne(Context<ConstraintHasOne>),
747    Raw(Context<ConstraintRaw>),
748    Owner(Context<ConstraintOwner>),
749    RentExempt(Context<ConstraintRentExempt>),
750    Seeds(Context<ConstraintSeeds>),
751    Executable(Context<ConstraintExecutable>),
752    Close(Context<ConstraintClose>),
753    Payer(Context<ConstraintPayer>),
754    Space(Context<ConstraintSpace>),
755    Address(Context<ConstraintAddress>),
756    TokenMint(Context<ConstraintTokenMint>),
757    TokenAuthority(Context<ConstraintTokenAuthority>),
758    TokenTokenProgram(Context<ConstraintTokenProgram>),
759    AssociatedTokenMint(Context<ConstraintTokenMint>),
760    AssociatedTokenAuthority(Context<ConstraintTokenAuthority>),
761    AssociatedTokenTokenProgram(Context<ConstraintTokenProgram>),
762    MintAuthority(Context<ConstraintMintAuthority>),
763    MintFreezeAuthority(Context<ConstraintMintFreezeAuthority>),
764    MintDecimals(Context<ConstraintMintDecimals>),
765    MintTokenProgram(Context<ConstraintTokenProgram>),
766    Bump(Context<ConstraintTokenBump>),
767    ProgramSeed(Context<ConstraintProgramSeed>),
768    Realloc(Context<ConstraintRealloc>),
769    ReallocPayer(Context<ConstraintReallocPayer>),
770    ReallocZero(Context<ConstraintReallocZero>),
771    // extensions
772    ExtensionGroupPointerAuthority(Context<ConstraintExtensionAuthority>),
773    ExtensionGroupPointerGroupAddress(Context<ConstraintExtensionGroupPointerGroupAddress>),
774    ExtensionGroupMemberPointerAuthority(Context<ConstraintExtensionAuthority>),
775    ExtensionGroupMemberPointerMemberAddress(
776        Context<ConstraintExtensionGroupMemberPointerMemberAddress>,
777    ),
778    ExtensionMetadataPointerAuthority(Context<ConstraintExtensionAuthority>),
779    ExtensionMetadataPointerMetadataAddress(
780        Context<ConstraintExtensionMetadataPointerMetadataAddress>,
781    ),
782    ExtensionCloseAuthority(Context<ConstraintExtensionAuthority>),
783    ExtensionTokenHookAuthority(Context<ConstraintExtensionAuthority>),
784    ExtensionTokenHookProgramId(Context<ConstraintExtensionTokenHookProgramId>),
785    ExtensionPermanentDelegate(Context<ConstraintExtensionPermanentDelegate>),
786}
787
788impl Parse for ConstraintToken {
789    fn parse(stream: ParseStream) -> ParseResult<Self> {
790        accounts_parser::constraints::parse_token(stream)
791    }
792}
793
794#[derive(Debug, Clone)]
795pub struct ConstraintInit {
796    pub if_needed: bool,
797}
798
799#[derive(Debug, Clone)]
800pub struct ConstraintInitIfNeeded {}
801
802#[derive(Debug, Clone)]
803pub struct ConstraintZeroed {}
804
805#[derive(Debug, Clone)]
806pub struct ConstraintMut {
807    pub error: Option<Expr>,
808}
809
810#[derive(Debug, Clone)]
811pub struct ConstraintReallocGroup {
812    pub payer: Expr,
813    pub space: Expr,
814    pub zero: Expr,
815}
816
817#[derive(Debug, Clone)]
818pub struct ConstraintRealloc {
819    pub space: Expr,
820}
821
822#[derive(Debug, Clone)]
823pub struct ConstraintReallocPayer {
824    pub target: Expr,
825}
826
827#[derive(Debug, Clone)]
828pub struct ConstraintReallocZero {
829    pub zero: Expr,
830}
831
832#[derive(Debug, Clone)]
833pub struct ConstraintSigner {
834    pub error: Option<Expr>,
835}
836
837#[derive(Debug, Clone)]
838pub struct ConstraintHasOne {
839    pub join_target: Expr,
840    pub error: Option<Expr>,
841}
842
843#[derive(Debug, Clone)]
844pub struct ConstraintRaw {
845    pub raw: Expr,
846    pub error: Option<Expr>,
847}
848
849#[derive(Debug, Clone)]
850pub struct ConstraintOwner {
851    pub owner_address: Expr,
852    pub error: Option<Expr>,
853}
854
855#[derive(Debug, Clone)]
856pub struct ConstraintAddress {
857    pub address: Expr,
858    pub error: Option<Expr>,
859}
860
861#[derive(Debug, Clone)]
862pub enum ConstraintRentExempt {
863    Enforce,
864    Skip,
865}
866
867#[derive(Debug, Clone)]
868pub struct ConstraintInitGroup {
869    pub if_needed: bool,
870    pub seeds: Option<ConstraintSeedsGroup>,
871    pub payer: Expr,
872    pub space: Option<Expr>,
873    pub kind: InitKind,
874}
875
876#[derive(Debug, Clone)]
877pub struct ConstraintSeedsGroup {
878    pub is_init: bool,
879    pub seeds: Punctuated<Expr, Token![,]>,
880    pub bump: Option<Expr>,         // None => bump was given without a target.
881    pub program_seed: Option<Expr>, // None => use the current program's program_id.
882}
883
884#[derive(Debug, Clone)]
885pub struct ConstraintSeeds {
886    pub seeds: Punctuated<Expr, Token![,]>,
887}
888
889#[derive(Debug, Clone)]
890pub struct ConstraintExecutable {}
891
892#[derive(Debug, Clone)]
893pub struct ConstraintPayer {
894    pub target: Expr,
895}
896
897#[derive(Debug, Clone)]
898pub struct ConstraintSpace {
899    pub space: Expr,
900}
901
902// extension constraints
903#[derive(Debug, Clone)]
904pub struct ConstraintExtensionAuthority {
905    pub authority: Expr,
906}
907
908#[derive(Debug, Clone)]
909pub struct ConstraintExtensionGroupPointerGroupAddress {
910    pub group_address: Expr,
911}
912
913#[derive(Debug, Clone)]
914pub struct ConstraintExtensionGroupMemberPointerMemberAddress {
915    pub member_address: Expr,
916}
917
918#[derive(Debug, Clone)]
919pub struct ConstraintExtensionMetadataPointerMetadataAddress {
920    pub metadata_address: Expr,
921}
922
923#[derive(Debug, Clone)]
924pub struct ConstraintExtensionTokenHookProgramId {
925    pub program_id: Expr,
926}
927
928#[derive(Debug, Clone)]
929pub struct ConstraintExtensionPermanentDelegate {
930    pub permanent_delegate: Expr,
931}
932
933#[derive(Debug, Clone)]
934#[allow(clippy::large_enum_variant)]
935pub enum InitKind {
936    Program {
937        owner: Option<Expr>,
938    },
939    Interface {
940        owner: Option<Expr>,
941    },
942    // Owner for token and mint represents the authority. Not to be confused
943    // with the owner of the AccountInfo.
944    Token {
945        owner: Expr,
946        mint: Expr,
947        token_program: Option<Expr>,
948    },
949    AssociatedToken {
950        owner: Expr,
951        mint: Expr,
952        token_program: Option<Expr>,
953    },
954    Mint {
955        owner: Expr,
956        freeze_authority: Option<Expr>,
957        decimals: Expr,
958        token_program: Option<Expr>,
959        // extensions
960        group_pointer_authority: Option<Expr>,
961        group_pointer_group_address: Option<Expr>,
962        group_member_pointer_authority: Option<Expr>,
963        group_member_pointer_member_address: Option<Expr>,
964        metadata_pointer_authority: Option<Expr>,
965        metadata_pointer_metadata_address: Option<Expr>,
966        close_authority: Option<Expr>,
967        permanent_delegate: Option<Expr>,
968        transfer_hook_authority: Option<Expr>,
969        transfer_hook_program_id: Option<Expr>,
970    },
971}
972
973#[derive(Debug, Clone)]
974pub struct ConstraintClose {
975    pub sol_dest: Ident,
976}
977
978#[derive(Debug, Clone)]
979pub struct ConstraintTokenMint {
980    pub mint: Expr,
981}
982
983#[derive(Debug, Clone)]
984pub struct ConstraintMintConfidentialTransferData {
985    pub confidential_transfer_data: Expr,
986}
987
988#[derive(Debug, Clone)]
989pub struct ConstraintMintMetadata {
990    pub token_metadata: Expr,
991}
992
993#[derive(Debug, Clone)]
994pub struct ConstraintMintTokenGroupData {
995    pub token_group_data: Expr,
996}
997
998#[derive(Debug, Clone)]
999pub struct ConstraintMintTokenGroupMemberData {
1000    pub token_group_member_data: Expr,
1001}
1002
1003#[derive(Debug, Clone)]
1004pub struct ConstraintMintMetadataPointerData {
1005    pub metadata_pointer_data: Expr,
1006}
1007
1008#[derive(Debug, Clone)]
1009pub struct ConstraintMintGroupPointerData {
1010    pub group_pointer_data: Expr,
1011}
1012
1013#[derive(Debug, Clone)]
1014pub struct ConstraintMintGroupMemberPointerData {
1015    pub group_member_pointer_data: Expr,
1016}
1017
1018#[derive(Debug, Clone)]
1019pub struct ConstraintMintCloseAuthority {
1020    pub close_authority: Expr,
1021}
1022
1023#[derive(Debug, Clone)]
1024pub struct ConstraintTokenAuthority {
1025    pub auth: Expr,
1026}
1027
1028#[derive(Debug, Clone)]
1029pub struct ConstraintTokenProgram {
1030    token_program: Expr,
1031}
1032
1033#[derive(Debug, Clone)]
1034pub struct ConstraintMintAuthority {
1035    pub mint_auth: Expr,
1036}
1037
1038#[derive(Debug, Clone)]
1039pub struct ConstraintMintFreezeAuthority {
1040    pub mint_freeze_auth: Expr,
1041}
1042
1043#[derive(Debug, Clone)]
1044pub struct ConstraintMintDecimals {
1045    pub decimals: Expr,
1046}
1047
1048#[derive(Debug, Clone)]
1049pub struct ConstraintTokenBump {
1050    pub bump: Option<Expr>,
1051}
1052
1053#[derive(Debug, Clone)]
1054pub struct ConstraintProgramSeed {
1055    pub program_seed: Expr,
1056}
1057
1058#[derive(Debug, Clone)]
1059pub struct ConstraintAssociatedToken {
1060    pub wallet: Expr,
1061    pub mint: Expr,
1062    pub token_program: Option<Expr>,
1063}
1064
1065#[derive(Debug, Clone)]
1066pub struct ConstraintTokenAccountGroup {
1067    pub mint: Option<Expr>,
1068    pub authority: Option<Expr>,
1069    pub token_program: Option<Expr>,
1070}
1071
1072#[derive(Debug, Clone)]
1073pub struct ConstraintTokenMintGroup {
1074    pub decimals: Option<Expr>,
1075    pub mint_authority: Option<Expr>,
1076    pub freeze_authority: Option<Expr>,
1077    pub token_program: Option<Expr>,
1078    pub group_pointer_authority: Option<Expr>,
1079    pub group_pointer_group_address: Option<Expr>,
1080    pub group_member_pointer_authority: Option<Expr>,
1081    pub group_member_pointer_member_address: Option<Expr>,
1082    pub metadata_pointer_authority: Option<Expr>,
1083    pub metadata_pointer_metadata_address: Option<Expr>,
1084    pub close_authority: Option<Expr>,
1085    pub permanent_delegate: Option<Expr>,
1086    pub transfer_hook_authority: Option<Expr>,
1087    pub transfer_hook_program_id: Option<Expr>,
1088}
1089
1090// Syntaxt context object for preserving metadata about the inner item.
1091#[derive(Debug, Clone)]
1092pub struct Context<T> {
1093    span: Span,
1094    inner: T,
1095}
1096
1097impl<T> Context<T> {
1098    pub fn new(span: Span, inner: T) -> Self {
1099        Self { span, inner }
1100    }
1101
1102    pub fn into_inner(self) -> T {
1103        self.inner
1104    }
1105}
1106
1107impl<T> Deref for Context<T> {
1108    type Target = T;
1109
1110    fn deref(&self) -> &Self::Target {
1111        &self.inner
1112    }
1113}
1114
1115impl<T> Spanned for Context<T> {
1116    fn span(&self) -> Span {
1117        self.span
1118    }
1119}