Add `IdlBuild` trait (#2629)

This commit is contained in:
acheron 2023-09-15 23:59:18 +02:00 committed by GitHub
parent fdda604d41
commit b5f4796156
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 188 additions and 35 deletions

View File

@ -43,8 +43,10 @@ anchor-attribute-program = { path = "./attribute/program", version = "0.28.0" }
anchor-derive-accounts = { path = "./derive/accounts", version = "0.28.0" }
anchor-derive-serde = { path = "./derive/serde", version = "0.28.0" }
anchor-derive-space = { path = "./derive/space", version = "0.28.0" }
# `anchor-syn` should only be included with `idl-build` feature
anchor-syn = { path = "./syn", version = "0.28.0", optional = true }
arrayref = "0.3"
base64 = "0.13"
bincode = "1"

View File

@ -405,10 +405,10 @@ pub fn zero_copy(
#[cfg(feature = "idl-build")]
{
let no_docs = get_no_docs();
let idl_gen_impl = gen_idl_gen_impl_for_struct(&account_strct, no_docs);
let idl_build_impl = gen_idl_build_impl_for_struct(&account_strct, no_docs);
return proc_macro::TokenStream::from(quote! {
#ret
#idl_gen_impl
#idl_build_impl
});
}

View File

@ -48,10 +48,10 @@ pub fn event(
#[cfg(feature = "idl-build")]
{
let idl_gen = anchor_syn::idl::build::gen_idl_print_function_for_event(&event_strct);
let idl_build = anchor_syn::idl::build::gen_idl_print_function_for_event(&event_strct);
return proc_macro::TokenStream::from(quote! {
#ret
#idl_gen
#idl_build
});
}

View File

@ -37,12 +37,12 @@ pub fn anchor_serialize(input: TokenStream) -> TokenStream {
{
let no_docs = get_no_docs();
let idl_gen_impl = match syn::parse(input).unwrap() {
Item::Struct(item) => gen_idl_gen_impl_for_struct(&item, no_docs),
Item::Enum(item) => gen_idl_gen_impl_for_enum(item, no_docs),
let idl_build_impl = match syn::parse(input).unwrap() {
Item::Struct(item) => gen_idl_build_impl_for_struct(&item, no_docs),
Item::Enum(item) => gen_idl_build_impl_for_enum(item, no_docs),
Item::Union(item) => {
// unions are not included in the IDL - TODO print a warning
idl_gen_impl_skeleton(quote! {None}, quote! {}, &item.ident, &item.generics)
idl_build_impl_skeleton(quote! {None}, quote! {}, &item.ident, &item.generics)
}
// Derive macros can only be defined on structs, enums, and unions.
_ => unreachable!(),
@ -50,7 +50,7 @@ pub fn anchor_serialize(input: TokenStream) -> TokenStream {
return TokenStream::from(quote! {
#ret
#idl_gen_impl
#idl_build_impl
});
};

View File

@ -50,19 +50,21 @@ pub use anchor_attribute_account::{account, declare_id, zero_copy};
pub use anchor_attribute_constant::constant;
pub use anchor_attribute_error::*;
pub use anchor_attribute_event::{emit, event};
#[cfg(feature = "event-cpi")]
pub use anchor_attribute_event::{emit_cpi, event_cpi};
pub use anchor_attribute_program::program;
pub use anchor_derive_accounts::Accounts;
pub use anchor_derive_serde::{AnchorDeserialize, AnchorSerialize};
pub use anchor_derive_space::InitSpace;
/// Borsh is the default serialization format for instructions and accounts.
pub use borsh::de::BorshDeserialize as AnchorDeserialize;
pub use borsh::ser::BorshSerialize as AnchorSerialize;
pub use solana_program;
#[cfg(feature = "event-cpi")]
pub use anchor_attribute_event::{emit_cpi, event_cpi};
#[cfg(feature = "idl-build")]
pub use anchor_syn;
pub use anchor_syn::{self, idl::build::IdlBuild};
pub type Result<T> = std::result::Result<T, error::Error>;
@ -353,8 +355,6 @@ pub mod prelude {
AccountsClose, AccountsExit, AnchorDeserialize, AnchorSerialize, Id, InitSpace, Key,
Lamports, Owner, ProgramData, Result, Space, ToAccountInfo, ToAccountInfos, ToAccountMetas,
};
#[cfg(feature = "event-cpi")]
pub use super::{emit_cpi, event_cpi};
pub use anchor_attribute_error::*;
pub use borsh;
pub use error::*;
@ -373,6 +373,12 @@ pub mod prelude {
pub use solana_program::sysvar::stake_history::StakeHistory;
pub use solana_program::sysvar::Sysvar as SolanaSysvar;
pub use thiserror;
#[cfg(feature = "event-cpi")]
pub use super::{emit_cpi, event_cpi};
#[cfg(feature = "idl-build")]
pub use super::IdlBuild;
}
/// Internal module used by macros and unstable apis.

View File

@ -36,10 +36,11 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
{
#![allow(warnings)]
let no_docs = crate::idl::build::get_no_docs();
let idl_gen_impl = crate::idl::build::gen_idl_gen_impl_for_accounts_strct(&accs, no_docs);
let idl_build_impl =
crate::idl::build::gen_idl_build_impl_for_accounts_struct(&accs, no_docs);
return quote! {
#ret
#idl_gen_impl
#idl_build_impl
};
}

View File

@ -103,10 +103,10 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
#[cfg(feature = "idl-build")]
{
let idl_gen = gen_idl_print_function_for_error(&error);
let idl_build = gen_idl_print_function_for_error(&error);
return quote! {
#ret
#idl_gen
#idl_build
};
};

View File

@ -40,11 +40,11 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
#[cfg(feature = "idl-build")]
{
let no_docs = crate::idl::build::get_no_docs();
let idl_gen = crate::idl::build::gen_idl_print_function_for_program(program, no_docs);
let idl_build = crate::idl::build::gen_idl_print_function_for_program(program, no_docs);
return quote! {
#ret
#idl_gen
#idl_build
};
};

View File

@ -1,10 +1,39 @@
pub use serde_json;
use crate::{parser::docs, AccountField, AccountsStruct, Error, Program};
use heck::MixedCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub use serde_json;
use syn::{Ident, ItemEnum, ItemStruct};
/// A trait that types must implement in order to generate the IDL via compilation.
///
/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize`
/// proc macro. Note that manually implementing the `AnchorSerialize` trait will **NOT** have the
/// same effect.
///
/// Types that don't implement this trait will cause a compile error during the IDL generation.
///
/// The methods have default implementation that allows the program to compile but the type will
/// **NOT** be included in the IDL.
pub trait IdlBuild {
/// Returns the full module path of the type.
fn __anchor_private_full_path() -> String {
String::default()
}
/// Returns the IDL type definition of the type or `None` if it doesn't exist.
fn __anchor_private_gen_idl_type() -> Option<super::types::IdlTypeDefinition> {
None
}
/// Insert the type definition to the defined types hashmap.
fn __anchor_private_insert_idl_defined(
_defined_types: &mut std::collections::HashMap<String, super::types::IdlTypeDefinition>,
) {
}
}
#[inline(always)]
fn get_module_paths() -> (TokenStream, TokenStream) {
(
@ -439,7 +468,7 @@ pub fn idl_type_definition_ts_from_syn_enum(
))
}
pub fn idl_gen_impl_skeleton(
pub fn idl_build_impl_skeleton(
idl_type_definition_ts: TokenStream,
insert_defined_ts: TokenStream,
ident: &Ident,
@ -448,18 +477,19 @@ pub fn idl_gen_impl_skeleton(
let (idl, _) = get_module_paths();
let name = ident.to_string();
let (impl_generics, ty_generics, where_clause) = input_generics.split_for_impl();
let idl_build_trait = quote! {anchor_lang::anchor_syn::idl::build::IdlBuild};
quote! {
impl #impl_generics #ident #ty_generics #where_clause {
pub fn __anchor_private_full_path() -> String {
impl #impl_generics #idl_build_trait for #ident #ty_generics #where_clause {
fn __anchor_private_full_path() -> String {
format!("{}::{}", std::module_path!(), #name)
}
pub fn __anchor_private_gen_idl_type() -> Option<#idl::IdlTypeDefinition> {
fn __anchor_private_gen_idl_type() -> Option<#idl::IdlTypeDefinition> {
#idl_type_definition_ts
}
pub fn __anchor_private_insert_idl_defined(
fn __anchor_private_insert_idl_defined(
defined_types: &mut std::collections::HashMap<String, #idl::IdlTypeDefinition>
) {
#insert_defined_ts
@ -469,7 +499,7 @@ pub fn idl_gen_impl_skeleton(
}
// generates the IDL generation impl for for a struct
pub fn gen_idl_gen_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenStream {
pub fn gen_idl_build_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenStream {
let idl_type_definition_ts: TokenStream;
let insert_defined_ts: TokenStream;
@ -492,7 +522,7 @@ pub fn gen_idl_gen_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenSt
let ident = &strct.ident;
let input_generics = &strct.generics;
idl_gen_impl_skeleton(
idl_build_impl_skeleton(
idl_type_definition_ts,
insert_defined_ts,
ident,
@ -501,7 +531,7 @@ pub fn gen_idl_gen_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenSt
}
// generates the IDL generation impl for for an enum
pub fn gen_idl_gen_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
pub fn gen_idl_build_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
let idl_type_definition_ts: TokenStream;
let insert_defined_ts: TokenStream;
@ -524,7 +554,7 @@ pub fn gen_idl_gen_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
let ident = &enm.ident;
let input_generics = &enm.generics;
idl_gen_impl_skeleton(
idl_build_impl_skeleton(
idl_type_definition_ts,
insert_defined_ts,
ident,
@ -533,7 +563,7 @@ pub fn gen_idl_gen_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
}
// generates the IDL generation impl for for an event
pub fn gen_idl_gen_impl_for_event(event_strct: &ItemStruct) -> TokenStream {
pub fn gen_idl_build_impl_for_event(event_strct: &ItemStruct) -> TokenStream {
fn parse_fields(
fields: &syn::FieldsNamed,
) -> Result<(Vec<TokenStream>, Vec<syn::TypePath>), ()> {
@ -601,7 +631,7 @@ pub fn gen_idl_gen_impl_for_event(event_strct: &ItemStruct) -> TokenStream {
}
// generates the IDL generation impl for the Accounts struct
pub fn gen_idl_gen_impl_for_accounts_strct(
pub fn gen_idl_build_impl_for_accounts_struct(
accs_strct: &AccountsStruct,
no_docs: bool,
) -> TokenStream {
@ -817,7 +847,7 @@ pub fn gen_idl_print_function_for_event(event: &ItemStruct) -> TokenStream {
let ident = &event.ident;
let fn_name = format_ident!("__anchor_private_print_idl_event_{}", ident.to_string());
let impl_gen = gen_idl_gen_impl_for_event(event);
let impl_gen = gen_idl_build_impl_for_event(event);
quote! {
#impl_gen

View File

@ -13,6 +13,7 @@ associated_token = ["spl-associated-token-account"]
dex = ["serum_dex"]
devnet = []
governance = []
idl-build = ["anchor-lang/idl-build"]
metadata = ["mpl-token-metadata"]
mint = []
shmem = []

View File

@ -54,5 +54,8 @@ macro_rules! vote_weight_record {
&mut self.0
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for VoterWeightRecord {}
};
}

View File

@ -782,6 +782,9 @@ impl Deref for MetadataAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for MetadataAccount {}
#[derive(Clone, Debug, PartialEq)]
pub struct MasterEditionAccount(mpl_token_metadata::state::MasterEditionV2);
@ -819,6 +822,9 @@ impl anchor_lang::Owner for MasterEditionAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for MasterEditionAccount {}
#[derive(Clone, Debug, PartialEq)]
pub struct TokenRecordAccount(mpl_token_metadata::state::TokenRecord);
@ -855,6 +861,9 @@ impl Deref for TokenRecordAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for TokenRecordAccount {}
#[derive(Clone)]
pub struct Metadata;

View File

@ -156,6 +156,9 @@ impl Deref for StakeAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for StakeAccount {}
#[derive(Clone)]
pub struct Stake;

View File

@ -486,6 +486,9 @@ impl Deref for TokenAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for TokenAccount {}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Mint(spl_token::state::Mint);
@ -517,6 +520,9 @@ impl Deref for Mint {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Mint {}
#[derive(Clone)]
pub struct Token;

View File

@ -32,6 +32,9 @@ impl Deref for TokenAccount {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for TokenAccount {}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Mint(spl_token_2022::state::Mint);
@ -59,6 +62,9 @@ impl Deref for Mint {
}
}
#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Mint {}
#[derive(Clone)]
pub struct TokenInterface;

View File

@ -61,6 +61,26 @@
"isMut": false,
"isSigner": false
},
{
"name": "tokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintAccount",
"isMut": false,
"isSigner": false
},
{
"name": "tokenInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "payer",
"isMut": true,
@ -111,6 +131,26 @@
"isMut": false,
"isSigner": false
},
{
"name": "tokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintAccount",
"isMut": false,
"isSigner": false
},
{
"name": "tokenInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "payer",
"isMut": true,

View File

@ -61,6 +61,26 @@
"isMut": false,
"isSigner": false
},
{
"name": "tokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintAccount",
"isMut": false,
"isSigner": false
},
{
"name": "tokenInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "payer",
"isMut": true,
@ -111,6 +131,26 @@
"isMut": false,
"isSigner": false
},
{
"name": "tokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintAccount",
"isMut": false,
"isSigner": false
},
{
"name": "tokenInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "mintInterfaceAccount",
"isMut": false,
"isSigner": false
},
{
"name": "payer",
"isMut": true,

View File

@ -13,11 +13,11 @@ no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
idl-build = ["anchor-lang/idl-build", "external/idl-build"]
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build", "external/idl-build"]
default = []
[dependencies]
anchor-lang = { path = "../../../../lang" }
anchor-spl = { path = "../../../../spl" }
bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]}
bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"] }
external = { path = "../external", features = ["no-entrypoint"] }

View File

@ -1,4 +1,5 @@
use anchor_lang::prelude::*;
use anchor_spl::{token, token_interface};
use std::str::FromStr;
declare_id!("id11111111111111111111111111111111111111111");
@ -274,6 +275,11 @@ pub struct Initialize<'info> {
nested: NestedAccounts<'info>,
zc_account: AccountLoader<'info, SomeZcAccount>,
token_account: Account<'info, token::TokenAccount>,
mint_account: Account<'info, token::Mint>,
token_interface_account: InterfaceAccount<'info, token_interface::TokenAccount>,
mint_interface_account: InterfaceAccount<'info, token_interface::Mint>,
#[account(mut)]
payer: Signer<'info>,
system_program: Program<'info, System>,