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