bolt_anchor_syn/
lib.rs

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