123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- use crate::codegen::program::common::*;
- use crate::{Program, State};
- use heck::CamelCase;
- use quote::quote;
- // Generate non-inlined wrappers for each instruction handler, since Solana's
- // BPF max stack size can't handle reasonable sized dispatch trees without doing
- // so.
- pub fn generate(program: &Program) -> proc_macro2::TokenStream {
- let program_name = &program.name;
- let non_inlined_idl: proc_macro2::TokenStream = {
- quote! {
- // Entry for all IDL related instructions. Use the "no-idl" feature
- // to eliminate this code, for example, if one wants to make the
- // IDL no longer mutable or if one doesn't want to store the IDL
- // on chain.
- #[inline(never)]
- #[cfg(not(feature = "no-idl"))]
- pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
- let mut accounts = accounts;
- let mut data: &[u8] = idl_ix_data;
- let ix = anchor_lang::idl::IdlInstruction::deserialize(&mut data)
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- match ix {
- anchor_lang::idl::IdlInstruction::Create { data_len } => {
- let mut accounts =
- anchor_lang::idl::IdlCreateAccounts::try_accounts(program_id, &mut accounts, &[])?;
- __idl_create_account(program_id, &mut accounts, data_len)?;
- accounts.exit(program_id)?;
- },
- anchor_lang::idl::IdlInstruction::CreateBuffer => {
- let mut accounts =
- anchor_lang::idl::IdlCreateBuffer::try_accounts(program_id, &mut accounts, &[])?;
- __idl_create_buffer(program_id, &mut accounts)?;
- accounts.exit(program_id)?;
- },
- anchor_lang::idl::IdlInstruction::Write { data } => {
- let mut accounts =
- anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[])?;
- __idl_write(program_id, &mut accounts, data)?;
- accounts.exit(program_id)?;
- },
- anchor_lang::idl::IdlInstruction::SetAuthority { new_authority } => {
- let mut accounts =
- anchor_lang::idl::IdlAccounts::try_accounts(program_id, &mut accounts, &[])?;
- __idl_set_authority(program_id, &mut accounts, new_authority)?;
- accounts.exit(program_id)?;
- },
- anchor_lang::idl::IdlInstruction::SetBuffer => {
- let mut accounts =
- anchor_lang::idl::IdlSetBuffer::try_accounts(program_id, &mut accounts, &[])?;
- __idl_set_buffer(program_id, &mut accounts)?;
- accounts.exit(program_id)?;
- },
- }
- Ok(())
- }
- #[inline(never)]
- #[cfg(feature = "no-idl")]
- pub fn __idl_dispatch(program_id: &Pubkey, accounts: &[AccountInfo], idl_ix_data: &[u8]) -> ProgramResult {
- Err(anchor_lang::__private::ErrorCode::IdlInstructionStub.into())
- }
- // One time IDL account initializer. Will faill on subsequent
- // invocations.
- #[inline(never)]
- pub fn __idl_create_account(
- program_id: &Pubkey,
- accounts: &mut anchor_lang::idl::IdlCreateAccounts,
- data_len: u64,
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!("Instruction: IdlCreateAccount");
- if program_id != accounts.program.key {
- return Err(anchor_lang::__private::ErrorCode::IdlInstructionInvalidProgram.into());
- }
- // Create the IDL's account.
- let from = accounts.from.key;
- let (base, nonce) = Pubkey::find_program_address(&[], program_id);
- let seed = anchor_lang::idl::IdlAccount::seed();
- let owner = accounts.program.key;
- let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
- // Space: account discriminator || authority pubkey || vec len || vec data
- let space = 8 + 32 + 4 + data_len as usize;
- let rent = Rent::get()?;
- let lamports = rent.minimum_balance(space);
- let seeds = &[&[nonce][..]];
- let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
- from,
- &to,
- &base,
- seed,
- lamports,
- space as u64,
- owner,
- );
- anchor_lang::solana_program::program::invoke_signed(
- &ix,
- &[
- accounts.from.clone(),
- accounts.to.clone(),
- accounts.base.clone(),
- accounts.system_program.clone(),
- ],
- &[seeds],
- )?;
- // Deserialize the newly created account.
- let mut idl_account = {
- let mut account_data = accounts.to.try_borrow_data()?;
- let mut account_data_slice: &[u8] = &account_data;
- anchor_lang::idl::IdlAccount::try_deserialize_unchecked(
- &mut account_data_slice,
- )?
- };
- // Set the authority.
- idl_account.authority = *accounts.from.key;
- // Store the new account data.
- let mut data = accounts.to.try_borrow_mut_data()?;
- let dst: &mut [u8] = &mut data;
- let mut cursor = std::io::Cursor::new(dst);
- idl_account.try_serialize(&mut cursor)?;
- Ok(())
- }
- #[inline(never)]
- pub fn __idl_create_buffer(
- program_id: &Pubkey,
- accounts: &mut anchor_lang::idl::IdlCreateBuffer,
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!("Instruction: IdlCreateBuffer");
- let mut buffer = &mut accounts.buffer;
- buffer.authority = *accounts.authority.key;
- Ok(())
- }
- #[inline(never)]
- pub fn __idl_write(
- program_id: &Pubkey,
- accounts: &mut anchor_lang::idl::IdlAccounts,
- idl_data: Vec<u8>,
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!("Instruction: IdlWrite");
- let mut idl = &mut accounts.idl;
- idl.data.extend(idl_data);
- Ok(())
- }
- #[inline(never)]
- pub fn __idl_set_authority(
- program_id: &Pubkey,
- accounts: &mut anchor_lang::idl::IdlAccounts,
- new_authority: Pubkey,
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!("Instruction: IdlSetAuthority");
- accounts.idl.authority = new_authority;
- Ok(())
- }
- #[inline(never)]
- pub fn __idl_set_buffer(
- program_id: &Pubkey,
- accounts: &mut anchor_lang::idl::IdlSetBuffer,
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!("Instruction: IdlSetBuffer");
- accounts.idl.data = accounts.buffer.data.clone();
- Ok(())
- }
- }
- };
- // Constructor handler.
- let non_inlined_ctor: proc_macro2::TokenStream = match &program.state {
- None => quote! {},
- Some(state) => match state.ctor_and_anchor.as_ref() {
- None => quote! {},
- Some((_ctor, anchor_ident)) => {
- let ctor_untyped_args = generate_ctor_args(state);
- let name = &state.strct.ident;
- let mod_name = &program.name;
- let variant_arm = generate_ctor_variant(state);
- let ix_name: proc_macro2::TokenStream =
- generate_ctor_variant_name().parse().unwrap();
- let ix_name_log = format!("Instruction: {}", ix_name);
- if state.is_zero_copy {
- quote! {
- // One time state account initializer. Will faill on subsequent
- // invocations.
- #[inline(never)]
- pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction data.
- let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let instruction::state::#variant_arm = ix;
- // Deserialize accounts.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- let ctor_accounts = anchor_lang::__private::Ctor::try_accounts(program_id, &mut remaining_accounts, &[])?;
- let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts, ix_data)?;
- // Create the solana account for the ctor data.
- let from = ctor_accounts.from.key;
- let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
- let seed = anchor_lang::__private::PROGRAM_STATE_SEED;
- let owner = ctor_accounts.program.key;
- let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
- let space = 8 + std::mem::size_of::<#name>();
- let rent = Rent::get()?;
- let lamports = rent.minimum_balance(std::convert::TryInto::try_into(space).unwrap());
- let seeds = &[&[nonce][..]];
- let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
- from,
- &to,
- &base,
- seed,
- lamports,
- space as u64,
- owner,
- );
- anchor_lang::solana_program::program::invoke_signed(
- &ix,
- &[
- ctor_accounts.from.clone(),
- ctor_accounts.to.clone(),
- ctor_accounts.base.clone(),
- ctor_accounts.system_program.clone(),
- ],
- &[seeds],
- )?;
- // Zero copy deserialize.
- let loader: anchor_lang::Loader<#mod_name::#name> = anchor_lang::Loader::try_from_unchecked(program_id, &ctor_accounts.to)?;
- // Invoke the ctor in a new lexical scope so that
- // the zero-copy RefMut gets dropped. Required
- // so that we can subsequently run the exit routine.
- {
- let mut instance = loader.load_init()?;
- instance.new(
- anchor_lang::Context::new(
- program_id,
- &mut ctor_user_def_accounts,
- remaining_accounts,
- ),
- #(#ctor_untyped_args),*
- )?;
- }
- // Exit routines.
- ctor_user_def_accounts.exit(program_id)?;
- loader.exit(program_id)?;
- Ok(())
- }
- }
- } else {
- quote! {
- // One time state account initializer. Will faill on subsequent
- // invocations.
- #[inline(never)]
- pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], ix_data: &[u8]) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction data.
- let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let instruction::state::#variant_arm = ix;
- // Deserialize accounts.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- let ctor_accounts = anchor_lang::__private::Ctor::try_accounts(program_id, &mut remaining_accounts, &[])?;
- let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts, ix_data)?;
- // Invoke the ctor.
- let instance = #mod_name::#name::new(
- anchor_lang::Context::new(
- program_id,
- &mut ctor_user_def_accounts,
- remaining_accounts,
- ),
- #(#ctor_untyped_args),*
- )?;
- // Create the solana account for the ctor data.
- let from = ctor_accounts.from.key;
- let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
- let seed = anchor_lang::ProgramState::<#name>::seed();
- let owner = ctor_accounts.program.key;
- let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
- let space = anchor_lang::__private::AccountSize::size(&instance)?;
- let rent = Rent::get()?;
- let lamports = rent.minimum_balance(std::convert::TryInto::try_into(space).unwrap());
- let seeds = &[&[nonce][..]];
- let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
- from,
- &to,
- &base,
- seed,
- lamports,
- space,
- owner,
- );
- anchor_lang::solana_program::program::invoke_signed(
- &ix,
- &[
- ctor_accounts.from.clone(),
- ctor_accounts.to.clone(),
- ctor_accounts.base.clone(),
- ctor_accounts.system_program.clone(),
- ],
- &[seeds],
- )?;
- // Serialize the state and save it to storage.
- ctor_user_def_accounts.exit(program_id)?;
- let mut data = ctor_accounts.to.try_borrow_mut_data()?;
- let dst: &mut [u8] = &mut data;
- let mut cursor = std::io::Cursor::new(dst);
- instance.try_serialize(&mut cursor)?;
- Ok(())
- }
- }
- }
- }
- },
- };
- // State method handlers.
- let non_inlined_state_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
- None => vec![],
- Some(state) => state
- .impl_block_and_methods
- .as_ref()
- .map(|(_impl_block, methods)| {
- methods
- .iter()
- .map(|ix| {
- let ix_arg_names: Vec<&syn::Ident> =
- ix.args.iter().map(|arg| &arg.name).collect();
- let private_ix_method_name: proc_macro2::TokenStream = {
- let n = format!("__{}", &ix.raw_method.sig.ident.to_string());
- n.parse().unwrap()
- };
- let ix_method_name = &ix.raw_method.sig.ident;
- let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
- let anchor_ident = &ix.anchor_ident;
- let name = &state.strct.ident;
- let mod_name = &program.name;
- let variant_arm =
- generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
- let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
- let ix_name_log = format!("Instruction: {}", ix_name);
- if state.is_zero_copy {
- quote! {
- #[inline(never)]
- pub fn #private_ix_method_name(
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- ix_data: &[u8],
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction.
- let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let instruction::state::#variant_arm = ix;
- // Load state.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- if remaining_accounts.is_empty() {
- return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
- }
- let loader: anchor_lang::Loader<#mod_name::#name> = anchor_lang::Loader::try_accounts(program_id, &mut remaining_accounts, &[])?;
- // Deserialize accounts.
- let mut accounts = #anchor_ident::try_accounts(
- program_id,
- &mut remaining_accounts,
- ix_data,
- )?;
- let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
- // Execute user defined function.
- {
- let mut state = loader.load_mut()?;
- state.#ix_method_name(
- ctx,
- #(#ix_arg_names),*
- )?;
- }
- // Serialize the state and save it to storage.
- accounts.exit(program_id)?;
- loader.exit(program_id)?;
- Ok(())
- }
- }
- } else {
- quote! {
- #[inline(never)]
- pub fn #private_ix_method_name(
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- ix_data: &[u8],
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction.
- let ix = instruction::state::#ix_name::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let instruction::state::#variant_arm = ix;
- // Load state.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- if remaining_accounts.is_empty() {
- return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
- }
- let mut state: anchor_lang::ProgramState<#state_ty> = anchor_lang::ProgramState::try_accounts(program_id, &mut remaining_accounts, &[])?;
- // Deserialize accounts.
- let mut accounts = #anchor_ident::try_accounts(
- program_id,
- &mut remaining_accounts,
- ix_data,
- )?;
- let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
- // Execute user defined function.
- state.#ix_method_name(
- ctx,
- #(#ix_arg_names),*
- )?;
- // Serialize the state and save it to storage.
- accounts.exit(program_id)?;
- let acc_info = state.to_account_info();
- let mut data = acc_info.try_borrow_mut_data()?;
- let dst: &mut [u8] = &mut data;
- let mut cursor = std::io::Cursor::new(dst);
- state.try_serialize(&mut cursor)?;
- Ok(())
- }
- }
- }
- })
- .collect()
- })
- .unwrap_or_default(),
- };
- // State trait handlers.
- let non_inlined_state_trait_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
- None => Vec::new(),
- Some(state) => state
- .interfaces
- .as_ref()
- .map(|interfaces| {
- interfaces
- .iter()
- .flat_map(|iface: &crate::StateInterface| {
- iface
- .methods
- .iter()
- .map(|ix| {
- if state.is_zero_copy {
- // Easy to implement. Just need to write a test.
- // Feel free to open a PR.
- panic!("Trait implementations not yet implemented for zero copy state structs. Please file an issue.");
- }
- let ix_arg_names: Vec<&syn::Ident> =
- ix.args.iter().map(|arg| &arg.name).collect();
- let private_ix_method_name: proc_macro2::TokenStream = {
- let n = format!("__{}_{}", iface.trait_name, &ix.raw_method.sig.ident.to_string());
- n.parse().unwrap()
- };
- let ix_method_name = &ix.raw_method.sig.ident;
- let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
- let anchor_ident = &ix.anchor_ident;
- let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
- let ix_name_log = format!("Instruction: {}", ix_name);
- let raw_args: Vec<&syn::PatType> = ix
- .args
- .iter()
- .map(|arg: &crate::IxArg| &arg.raw_arg)
- .collect();
- let args_struct = {
- if ix.args.is_empty() {
- quote! {
- #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
- struct Args;
- }
- } else {
- quote! {
- #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
- struct Args {
- #(#raw_args),*
- }
- }
- }
- };
- let deserialize_instruction = quote! {
- #args_struct
- let ix = Args::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let Args {
- #(#ix_arg_names),*
- } = ix;
- };
- if ix.has_receiver {
- quote! {
- #[inline(never)]
- pub fn #private_ix_method_name(
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- ix_data: &[u8],
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction.
- #deserialize_instruction
- // Deserialize the program state account.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- if remaining_accounts.is_empty() {
- return Err(anchor_lang::__private::ErrorCode::AccountNotEnoughKeys.into());
- }
- let mut state: anchor_lang::ProgramState<#state_ty> = anchor_lang::ProgramState::try_accounts(program_id, &mut remaining_accounts, &[])?;
- // Deserialize accounts.
- let mut accounts = #anchor_ident::try_accounts(
- program_id,
- &mut remaining_accounts,
- ix_data,
- )?;
- let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
- // Execute user defined function.
- state.#ix_method_name(
- ctx,
- #(#ix_arg_names),*
- )?;
- // Exit procedures.
- accounts.exit(program_id)?;
- let acc_info = state.to_account_info();
- let mut data = acc_info.try_borrow_mut_data()?;
- let dst: &mut [u8] = &mut data;
- let mut cursor = std::io::Cursor::new(dst);
- state.try_serialize(&mut cursor)?;
- Ok(())
- }
- }
- } else {
- let state_name: proc_macro2::TokenStream = state.name.parse().unwrap();
- quote! {
- #[inline(never)]
- pub fn #private_ix_method_name(
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- ix_data: &[u8],
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize instruction.
- #deserialize_instruction
- // Deserialize accounts.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- let mut accounts = #anchor_ident::try_accounts(
- program_id,
- &mut remaining_accounts,
- ix_data,
- )?;
- // Execute user defined function.
- #state_name::#ix_method_name(
- Context::new(program_id, &mut accounts, remaining_accounts),
- #(#ix_arg_names),*
- )?;
- // Exit procedure.
- accounts.exit(program_id)
- }
- }
- }
- })
- .collect::<Vec<proc_macro2::TokenStream>>()
- })
- .collect()
- })
- .unwrap_or_default(),
- };
- let non_inlined_handlers: Vec<proc_macro2::TokenStream> = program
- .ixs
- .iter()
- .map(|ix| {
- let ix_arg_names: Vec<&syn::Ident> = ix.args.iter().map(|arg| &arg.name).collect();
- let ix_name = generate_ix_variant_name(ix.raw_method.sig.ident.to_string());
- let ix_method_name = &ix.raw_method.sig.ident;
- let anchor = &ix.anchor_ident;
- let variant_arm = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
- let ix_name_log = format!("Instruction: {}", ix_name);
- quote! {
- #[inline(never)]
- pub fn #ix_method_name(
- program_id: &Pubkey,
- accounts: &[AccountInfo],
- ix_data: &[u8],
- ) -> ProgramResult {
- #[cfg(not(feature = "no-log-ix-name"))]
- anchor_lang::prelude::msg!(#ix_name_log);
- // Deserialize data.
- let ix = instruction::#ix_name::deserialize(&mut &ix_data[..])
- .map_err(|_| anchor_lang::__private::ErrorCode::InstructionDidNotDeserialize)?;
- let instruction::#variant_arm = ix;
- // Deserialize accounts.
- let mut remaining_accounts: &[AccountInfo] = accounts;
- let mut accounts = #anchor::try_accounts(
- program_id,
- &mut remaining_accounts,
- ix_data,
- )?;
- // Invoke user defined handler.
- #program_name::#ix_method_name(
- Context::new(program_id, &mut accounts, remaining_accounts),
- #(#ix_arg_names),*
- )?;
- // Exit routine.
- accounts.exit(program_id)
- }
- }
- })
- .collect();
- quote! {
- /// Create a private module to not clutter the program's namespace.
- /// Defines an entrypoint for each individual instruction handler
- /// wrapper.
- mod __private {
- use super::*;
- /// __idl mod defines handlers for injected Anchor IDL instructions.
- pub mod __idl {
- use super::*;
- #non_inlined_idl
- }
- /// __state mod defines wrapped handlers for state instructions.
- pub mod __state {
- use super::*;
- #non_inlined_ctor
- #(#non_inlined_state_handlers)*
- }
- /// __interface mod defines wrapped handlers for `#[interface]` trait
- /// implementations.
- pub mod __interface {
- use super::*;
- #(#non_inlined_state_trait_handlers)*
- }
- /// __global mod defines wrapped handlers for global instructions.
- pub mod __global {
- use super::*;
- #(#non_inlined_handlers)*
- }
- }
- }
- }
- fn generate_ix_variant_name(name: String) -> proc_macro2::TokenStream {
- let n = name.to_camel_case();
- n.parse().unwrap()
- }
- fn generate_ctor_variant_name() -> String {
- "New".to_string()
- }
- fn generate_ctor_variant(state: &State) -> proc_macro2::TokenStream {
- let ctor_args = generate_ctor_args(state);
- let ctor_variant_name: proc_macro2::TokenStream = generate_ctor_variant_name().parse().unwrap();
- if ctor_args.is_empty() {
- quote! {
- #ctor_variant_name
- }
- } else {
- quote! {
- #ctor_variant_name {
- #(#ctor_args),*
- }
- }
- }
- }
|