Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IdlBuild trait #2629

Merged
merged 2 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading