Skip to content

Commit

Permalink
Add IdlBuild trait (#2629)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Sep 15, 2023
1 parent fdda604 commit b5f4796
Show file tree
Hide file tree
Showing 19 changed files with 188 additions and 35 deletions.
2 changes: 2 additions & 0 deletions lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions lang/attribute/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}

Expand Down
4 changes: 2 additions & 2 deletions lang/attribute/event/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}

Expand Down
10 changes: 5 additions & 5 deletions lang/derive/serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ 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!(),
};

return TokenStream::from(quote! {
#ret
#idl_gen_impl
#idl_build_impl
});
};

Expand Down
16 changes: 11 additions & 5 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;

Expand Down Expand Up @@ -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::*;
Expand All @@ -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.
Expand Down
5 changes: 3 additions & 2 deletions lang/syn/src/codegen/accounts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}

Expand Down
4 changes: 2 additions & 2 deletions lang/syn/src/codegen/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
};

Expand Down
4 changes: 2 additions & 2 deletions lang/syn/src/codegen/program/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
};

Expand Down
56 changes: 43 additions & 13 deletions lang/syn/src/idl/build.rs
Original file line number Diff line number Diff line change
@@ -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) {
(
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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;

Expand All @@ -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,
Expand All @@ -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;

Expand All @@ -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,
Expand All @@ -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>), ()> {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions spl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
3 changes: 3 additions & 0 deletions spl/src/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,8 @@ macro_rules! vote_weight_record {
&mut self.0
}
}

#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for VoterWeightRecord {}
};
}
9 changes: 9 additions & 0 deletions spl/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -855,6 +861,9 @@ impl Deref for TokenRecordAccount {
}
}

#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for TokenRecordAccount {}

#[derive(Clone)]
pub struct Metadata;

Expand Down
3 changes: 3 additions & 0 deletions spl/src/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ impl Deref for StakeAccount {
}
}

#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for StakeAccount {}

#[derive(Clone)]
pub struct Stake;

Expand Down
6 changes: 6 additions & 0 deletions spl/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -517,6 +520,9 @@ impl Deref for Mint {
}
}

#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Mint {}

#[derive(Clone)]
pub struct Token;

Expand Down
6 changes: 6 additions & 0 deletions spl/src/token_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -59,6 +62,9 @@ impl Deref for Mint {
}
}

#[cfg(feature = "idl-build")]
impl anchor_lang::IdlBuild for Mint {}

#[derive(Clone)]
pub struct TokenInterface;

Expand Down
Loading

1 comment on commit b5f4796

@vercel
Copy link

@vercel vercel bot commented on b5f4796 Sep 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

anchor-docs – ./

anchor-docs-200ms.vercel.app
www.anchor-lang.com
anchor-docs-git-master-200ms.vercel.app
anchor-lang.com

Please sign in to comment.