From dd1bb4b7af8e05dc0ee3b857371a31e9d2864bed Mon Sep 17 00:00:00 2001 From: acheron Date: Tue, 2 Apr 2024 18:17:47 +0200 Subject: [PATCH 1/3] idl: Move IDL types from the `anchor-syn` crate to the new IDL crate --- Cargo.lock | 3 +- idl/Cargo.toml | 15 +- idl/src/build.rs | 32 ++ idl/src/lib.rs | 3 + idl/src/types.rs | 487 +++++++++++++++++- lang/Cargo.toml | 6 +- lang/attribute/account/src/lib.rs | 4 +- lang/attribute/constant/src/lib.rs | 2 +- lang/attribute/event/src/lib.rs | 2 +- lang/attribute/program/Cargo.toml | 3 +- .../program/src/declare_program/common.rs | 2 +- .../program/src/declare_program/mod.rs | 2 +- .../src/declare_program/mods/accounts.rs | 2 +- .../src/declare_program/mods/client.rs | 2 +- .../src/declare_program/mods/constants.rs | 2 +- .../program/src/declare_program/mods/cpi.rs | 2 +- .../src/declare_program/mods/events.rs | 2 +- .../src/declare_program/mods/internal.rs | 2 +- .../program/src/declare_program/mods/types.rs | 2 +- lang/derive/serde/src/lib.rs | 2 +- lang/src/bpf_upgradeable_state.rs | 2 +- lang/src/idl.rs | 3 + lang/src/lib.rs | 5 +- lang/syn/Cargo.toml | 3 +- lang/syn/src/codegen/accounts/mod.rs | 2 +- lang/syn/src/codegen/error.rs | 2 +- lang/syn/src/codegen/program/mod.rs | 2 +- lang/syn/src/idl/{build => }/accounts.rs | 0 lang/syn/src/idl/{build => }/address.rs | 0 lang/syn/src/idl/build/mod.rs | 21 - lang/syn/src/idl/{build => }/common.rs | 4 +- lang/syn/src/idl/{build => }/constant.rs | 0 lang/syn/src/idl/{build => }/defined.rs | 46 +- lang/syn/src/idl/{build => }/error.rs | 0 lang/syn/src/idl/{build => }/event.rs | 0 lang/syn/src/idl/{build => }/external.rs | 0 lang/syn/src/idl/mod.rs | 21 +- lang/syn/src/idl/{build => }/program.rs | 0 lang/syn/src/idl/types.rs | 486 ----------------- lang/syn/src/lib.rs | 2 +- tests/idl/programs/new-idl/src/lib.rs | 2 +- 41 files changed, 583 insertions(+), 595 deletions(-) rename lang/syn/src/idl/{build => }/accounts.rs (100%) rename lang/syn/src/idl/{build => }/address.rs (100%) delete mode 100644 lang/syn/src/idl/build/mod.rs rename lang/syn/src/idl/{build => }/common.rs (90%) rename lang/syn/src/idl/{build => }/constant.rs (100%) rename lang/syn/src/idl/{build => }/defined.rs (93%) rename lang/syn/src/idl/{build => }/error.rs (100%) rename lang/syn/src/idl/{build => }/event.rs (100%) rename lang/syn/src/idl/{build => }/external.rs (100%) rename lang/syn/src/idl/{build => }/program.rs (100%) delete mode 100644 lang/syn/src/idl/types.rs diff --git a/Cargo.lock b/Cargo.lock index feb5516902..b20730dc56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,7 @@ dependencies = [ name = "anchor-attribute-program" version = "0.29.0" dependencies = [ + "anchor-idl", "anchor-syn", "anyhow", "bs58 0.5.0", @@ -286,7 +287,7 @@ dependencies = [ "anchor-derive-accounts", "anchor-derive-serde", "anchor-derive-space", - "anchor-syn", + "anchor-idl", "arrayref", "base64 0.21.7", "bincode", diff --git a/idl/Cargo.toml b/idl/Cargo.toml index 1447e31bcc..524323d774 100644 --- a/idl/Cargo.toml +++ b/idl/Cargo.toml @@ -13,18 +13,13 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] -build = [ - "anyhow", - "regex", - "serde", - "serde_json", -] +build = ["anchor-syn", "regex"] [dependencies] -anchor-syn = { path = "../lang/syn", version = "0.29.0", features = ["idl-types"] } +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" # `build` feature only -anyhow = { version = "1", optional = true } +anchor-syn = { path = "../lang/syn", version = "0.29.0", optional = true } regex = { version = "1", optional = true } -serde = { version = "1", features = ["derive"], optional = true } -serde_json = { version = "1", optional = true } diff --git a/idl/src/build.rs b/idl/src/build.rs index 4758011a86..497183c7a9 100644 --- a/idl/src/build.rs +++ b/idl/src/build.rs @@ -12,6 +12,38 @@ use serde::Deserialize; use crate::types::{Idl, IdlEvent, IdlTypeDef}; +/// A trait that types must implement in order to include the type in the IDL definition. +/// +/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize` +/// proc macro. Note that manually implementing the `AnchorSerialize` trait does **NOT** have the +/// same effect. +/// +/// Types that don't implement this trait will cause a compile error during the IDL generation. +/// +/// The default implementation of the trait allows the program to compile but the type does **NOT** +/// get included in the IDL. +pub trait IdlBuild { + /// Create an IDL type definition for the type. + /// + /// The type is only included in the IDL if this method returns `Some`. + fn create_type() -> Option { + None + } + + /// Insert all types that are included in the current type definition to the given map. + fn insert_types(_types: &mut BTreeMap) {} + + /// Get the full module path of the type. + /// + /// The full path will be used in the case of a conflicting type definition, e.g. when there + /// are multiple structs with the same name. + /// + /// The default implementation covers most cases. + fn get_full_path() -> String { + std::any::type_name::().into() + } +} + /// Generate IDL via compilation. pub fn build_idl( program_path: impl AsRef, diff --git a/idl/src/lib.rs b/idl/src/lib.rs index 2a713d9e4b..0ba2ddf4cf 100644 --- a/idl/src/lib.rs +++ b/idl/src/lib.rs @@ -4,3 +4,6 @@ pub mod types; #[cfg(feature = "build")] pub mod build; + +#[cfg(feature = "build")] +pub use serde_json; diff --git a/idl/src/types.rs b/idl/src/types.rs index 5579096aae..a145f8261d 100644 --- a/idl/src/types.rs +++ b/idl/src/types.rs @@ -1,3 +1,486 @@ -//! IDL types are re-exported from [`anchor_syn`]. +use std::str::FromStr; -pub use anchor_syn::idl::types::*; +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; + +/// IDL specification Semantic Version +pub const IDL_SPEC: &str = "0.1.0"; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Idl { + pub address: String, + pub metadata: IdlMetadata, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + pub instructions: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub accounts: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub events: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub errors: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub types: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub constants: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlMetadata { + pub name: String, + pub version: String, + pub spec: String, + #[serde(skip_serializing_if = "is_default")] + pub description: Option, + #[serde(skip_serializing_if = "is_default")] + pub repository: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub dependencies: Vec, + #[serde(skip_serializing_if = "is_default")] + pub contact: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlDependency { + pub name: String, + pub version: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstruction { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + pub discriminator: IdlDiscriminator, + pub accounts: Vec, + pub args: Vec, + #[serde(skip_serializing_if = "is_default")] + pub returns: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum IdlInstructionAccountItem { + Composite(IdlInstructionAccounts), + Single(IdlInstructionAccount), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstructionAccount { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub writable: bool, + #[serde(default, skip_serializing_if = "is_default")] + pub signer: bool, + #[serde(default, skip_serializing_if = "is_default")] + pub optional: bool, + #[serde(skip_serializing_if = "is_default")] + pub address: Option, + #[serde(skip_serializing_if = "is_default")] + pub pda: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub relations: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstructionAccounts { + pub name: String, + pub accounts: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlPda { + pub seeds: Vec, + #[serde(skip_serializing_if = "is_default")] + pub program: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlSeed { + Const(IdlSeedConst), + Arg(IdlSeedArg), + Account(IdlSeedAccount), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedConst { + pub value: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedArg { + pub path: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedAccount { + pub path: String, + #[serde(skip_serializing_if = "is_default")] + pub account: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlAccount { + pub name: String, + pub discriminator: IdlDiscriminator, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlEvent { + pub name: String, + pub discriminator: IdlDiscriminator, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlConst { + pub name: String, + #[serde(rename = "type")] + pub ty: IdlType, + pub value: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct IdlErrorCode { + pub code: u32, + pub name: String, + #[serde(skip_serializing_if = "is_default")] + pub msg: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlField { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(rename = "type")] + pub ty: IdlType, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlTypeDef { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub serialization: IdlSerialization, + #[serde(skip_serializing_if = "is_default")] + pub repr: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub generics: Vec, + #[serde(rename = "type")] + pub ty: IdlTypeDefTy, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)] +#[serde(rename_all = "lowercase")] +pub enum IdlSerialization { + #[default] + Borsh, + Bytemuck, + BytemuckUnsafe, + Custom(String), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlRepr { + Rust(IdlReprModifier), + C(IdlReprModifier), + Transparent, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlReprModifier { + #[serde(default, skip_serializing_if = "is_default")] + pub packed: bool, + #[serde(skip_serializing_if = "is_default")] + pub align: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlTypeDefGeneric { + Type { + name: String, + }, + Const { + name: String, + #[serde(rename = "type")] + ty: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlTypeDefTy { + Struct { + #[serde(skip_serializing_if = "is_default")] + fields: Option, + }, + Enum { + variants: Vec, + }, + Type { + alias: IdlType, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlEnumVariant { + pub name: String, + #[serde(skip_serializing_if = "is_default")] + pub fields: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum IdlDefinedFields { + Named(Vec), + Tuple(Vec), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum IdlArrayLen { + Generic(String), + #[serde(untagged)] + Value(usize), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlGenericArg { + Type { + #[serde(rename = "type")] + ty: IdlType, + }, + Const { + value: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum IdlType { + Bool, + U8, + I8, + U16, + I16, + U32, + I32, + F32, + U64, + I64, + F64, + U128, + I128, + U256, + I256, + Bytes, + String, + Pubkey, + Option(Box), + Vec(Box), + Array(Box, IdlArrayLen), + Defined { + name: String, + #[serde(default, skip_serializing_if = "is_default")] + generics: Vec, + }, + Generic(String), +} + +impl FromStr for IdlType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let mut s = s.to_owned(); + s.retain(|c| !c.is_whitespace()); + + let r = match s.as_str() { + "bool" => IdlType::Bool, + "u8" => IdlType::U8, + "i8" => IdlType::I8, + "u16" => IdlType::U16, + "i16" => IdlType::I16, + "u32" => IdlType::U32, + "i32" => IdlType::I32, + "f32" => IdlType::F32, + "u64" => IdlType::U64, + "i64" => IdlType::I64, + "f64" => IdlType::F64, + "u128" => IdlType::U128, + "i128" => IdlType::I128, + "u256" => IdlType::U256, + "i256" => IdlType::I256, + "Vec" => IdlType::Bytes, + "String" | "&str" | "&'staticstr" => IdlType::String, + "Pubkey" => IdlType::Pubkey, + _ => { + if let Some(inner) = s.strip_prefix("Option<") { + let inner_ty = Self::from_str( + inner + .strip_suffix('>') + .ok_or_else(|| anyhow!("Invalid Option"))?, + )?; + return Ok(IdlType::Option(Box::new(inner_ty))); + } + + if let Some(inner) = s.strip_prefix("Vec<") { + let inner_ty = Self::from_str( + inner + .strip_suffix('>') + .ok_or_else(|| anyhow!("Invalid Vec"))?, + )?; + return Ok(IdlType::Vec(Box::new(inner_ty))); + } + + if s.starts_with('[') { + fn array_from_str(inner: &str) -> IdlType { + match inner.strip_suffix(']') { + Some(nested_inner) => array_from_str(&nested_inner[1..]), + None => { + let (raw_type, raw_length) = inner.rsplit_once(';').unwrap(); + let ty = IdlType::from_str(raw_type).unwrap(); + let len = match raw_length.replace('_', "").parse::() { + Ok(len) => IdlArrayLen::Value(len), + Err(_) => IdlArrayLen::Generic(raw_length.to_owned()), + }; + IdlType::Array(Box::new(ty), len) + } + } + } + return Ok(array_from_str(&s)); + } + + // Defined + let (name, generics) = if let Some(i) = s.find('<') { + ( + s.get(..i).unwrap().to_owned(), + s.get(i + 1..) + .unwrap() + .strip_suffix('>') + .unwrap() + .split(',') + .map(|g| g.trim().to_owned()) + .map(|g| { + if g.parse::().is_ok() + || g.parse::().is_ok() + || g.parse::().is_ok() + || g.parse::().is_ok() + { + Ok(IdlGenericArg::Const { value: g }) + } else { + Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty }) + } + }) + .collect::, _>>()?, + ) + } else { + (s.to_owned(), vec![]) + }; + + IdlType::Defined { name, generics } + } + }; + Ok(r) + } +} + +pub type IdlDiscriminator = Vec; + +/// Get whether the given data is the default of its type. +fn is_default(it: &T) -> bool { + *it == T::default() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn option() { + assert_eq!( + IdlType::from_str("Option").unwrap(), + IdlType::Option(Box::new(IdlType::Bool)) + ) + } + + #[test] + fn vector() { + assert_eq!( + IdlType::from_str("Vec").unwrap(), + IdlType::Vec(Box::new(IdlType::Bool)) + ) + } + + #[test] + fn array() { + assert_eq!( + IdlType::from_str("[Pubkey; 16]").unwrap(), + IdlType::Array(Box::new(IdlType::Pubkey), IdlArrayLen::Value(16)) + ); + } + + #[test] + fn array_with_underscored_length() { + assert_eq!( + IdlType::from_str("[u8; 50_000]").unwrap(), + IdlType::Array(Box::new(IdlType::U8), IdlArrayLen::Value(50000)) + ); + } + + #[test] + fn multidimensional_array() { + assert_eq!( + IdlType::from_str("[[u8; 16]; 32]").unwrap(), + IdlType::Array( + Box::new(IdlType::Array( + Box::new(IdlType::U8), + IdlArrayLen::Value(16) + )), + IdlArrayLen::Value(32) + ) + ); + } + + #[test] + fn generic_array() { + assert_eq!( + IdlType::from_str("[u64; T]").unwrap(), + IdlType::Array(Box::new(IdlType::U64), IdlArrayLen::Generic("T".into())) + ); + } + + #[test] + fn defined() { + assert_eq!( + IdlType::from_str("MyStruct").unwrap(), + IdlType::Defined { + name: "MyStruct".into(), + generics: vec![] + } + ) + } + + #[test] + fn defined_with_generics() { + assert_eq!( + IdlType::from_str("MyStruct").unwrap(), + IdlType::Defined { + name: "MyStruct".into(), + generics: vec![ + IdlGenericArg::Type { + ty: IdlType::Pubkey + }, + IdlGenericArg::Type { ty: IdlType::U64 }, + IdlGenericArg::Const { value: "8".into() }, + ], + } + ) + } +} diff --git a/lang/Cargo.toml b/lang/Cargo.toml index 485cb4f489..c3f7d7b931 100644 --- a/lang/Cargo.toml +++ b/lang/Cargo.toml @@ -33,7 +33,7 @@ idl-build = [ "anchor-attribute-program/idl-build", "anchor-derive-accounts/idl-build", "anchor-derive-serde/idl-build", - "anchor-syn/idl-build", + "anchor-idl/build", ] init-if-needed = ["anchor-derive-accounts/init-if-needed"] interface-instructions = ["anchor-attribute-program/interface-instructions"] @@ -49,8 +49,8 @@ anchor-derive-accounts = { path = "./derive/accounts", version = "0.29.0" } anchor-derive-serde = { path = "./derive/serde", version = "0.29.0" } anchor-derive-space = { path = "./derive/space", version = "0.29.0" } -# `anchor-syn` should only be included with `idl-build` feature -anchor-syn = { path = "./syn", version = "0.29.0", optional = true } +# `anchor-idl` should only be included with `idl-build` feature +anchor-idl = { path = "../idl", version = "0.29.0", optional = true } arrayref = "0.3" base64 = "0.21" diff --git a/lang/attribute/account/src/lib.rs b/lang/attribute/account/src/lib.rs index 72f567809f..777257996a 100644 --- a/lang/attribute/account/src/lib.rs +++ b/lang/attribute/account/src/lib.rs @@ -413,7 +413,7 @@ pub fn zero_copy( #ret }) .unwrap(); - let idl_build_impl = anchor_syn::idl::build::impl_idl_build_struct(&zc_struct); + let idl_build_impl = anchor_syn::idl::impl_idl_build_struct(&zc_struct); return proc_macro::TokenStream::from(quote! { #ret #idl_build_impl @@ -436,7 +436,7 @@ pub fn declare_id(input: proc_macro::TokenStream) -> proc_macro::TokenStream { #[cfg(feature = "idl-build")] { - let idl_print = anchor_syn::idl::build::gen_idl_print_fn_address(address); + let idl_print = anchor_syn::idl::gen_idl_print_fn_address(address); return proc_macro::TokenStream::from(quote! { #ret #idl_print diff --git a/lang/attribute/constant/src/lib.rs b/lang/attribute/constant/src/lib.rs index edf15c39d8..685e5faafe 100644 --- a/lang/attribute/constant/src/lib.rs +++ b/lang/attribute/constant/src/lib.rs @@ -13,7 +13,7 @@ pub fn constant( let ts = match syn::parse(input).unwrap() { syn::Item::Const(item) => { - let idl_print = anchor_syn::idl::build::gen_idl_print_fn_constant(&item); + let idl_print = anchor_syn::idl::gen_idl_print_fn_constant(&item); quote! { #item #idl_print diff --git a/lang/attribute/event/src/lib.rs b/lang/attribute/event/src/lib.rs index 8edf1cf2df..f3641d9569 100644 --- a/lang/attribute/event/src/lib.rs +++ b/lang/attribute/event/src/lib.rs @@ -46,7 +46,7 @@ pub fn event( #[cfg(feature = "idl-build")] { - let idl_build = anchor_syn::idl::build::gen_idl_print_fn_event(&event_strct); + let idl_build = anchor_syn::idl::gen_idl_print_fn_event(&event_strct); return proc_macro::TokenStream::from(quote! { #ret #idl_build diff --git a/lang/attribute/program/Cargo.toml b/lang/attribute/program/Cargo.toml index e72fec8221..e17e3d23c0 100644 --- a/lang/attribute/program/Cargo.toml +++ b/lang/attribute/program/Cargo.toml @@ -17,7 +17,8 @@ idl-build = ["anchor-syn/idl-build"] interface-instructions = ["anchor-syn/interface-instructions"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0", features = ["idl-types"] } +anchor-idl = { path = "../../../idl", version = "0.29.0" } +anchor-syn = { path = "../../syn", version = "0.29.0" } anyhow = "1" bs58 = "0.5" heck = "0.3" diff --git a/lang/attribute/program/src/declare_program/common.rs b/lang/attribute/program/src/declare_program/common.rs index 2be500a535..f2c0ea710b 100644 --- a/lang/attribute/program/src/declare_program/common.rs +++ b/lang/attribute/program/src/declare_program/common.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::{ +use anchor_idl::types::{ Idl, IdlArrayLen, IdlDefinedFields, IdlField, IdlGenericArg, IdlRepr, IdlSerialization, IdlType, IdlTypeDef, IdlTypeDefGeneric, IdlTypeDefTy, }; diff --git a/lang/attribute/program/src/declare_program/mod.rs b/lang/attribute/program/src/declare_program/mod.rs index ad809f291f..ec60ad4468 100644 --- a/lang/attribute/program/src/declare_program/mod.rs +++ b/lang/attribute/program/src/declare_program/mod.rs @@ -1,7 +1,7 @@ mod common; mod mods; -use anchor_syn::idl::types::Idl; +use anchor_idl::types::Idl; use anyhow::anyhow; use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream}; diff --git a/lang/attribute/program/src/declare_program/mods/accounts.rs b/lang/attribute/program/src/declare_program/mods/accounts.rs index 111807e850..ba9f849820 100644 --- a/lang/attribute/program/src/declare_program/mods/accounts.rs +++ b/lang/attribute/program/src/declare_program/mods/accounts.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::{Idl, IdlSerialization}; +use anchor_idl::types::{Idl, IdlSerialization}; use quote::{format_ident, quote}; use super::common::{convert_idl_type_def_to_ts, gen_discriminator, get_canonical_program_id}; diff --git a/lang/attribute/program/src/declare_program/mods/client.rs b/lang/attribute/program/src/declare_program/mods/client.rs index 840f1d18c0..7c9a08ca72 100644 --- a/lang/attribute/program/src/declare_program/mods/client.rs +++ b/lang/attribute/program/src/declare_program/mods/client.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::Idl; +use anchor_idl::types::Idl; use quote::quote; use super::common::gen_accounts_common; diff --git a/lang/attribute/program/src/declare_program/mods/constants.rs b/lang/attribute/program/src/declare_program/mods/constants.rs index c4fe8970e8..cbde4b92dd 100644 --- a/lang/attribute/program/src/declare_program/mods/constants.rs +++ b/lang/attribute/program/src/declare_program/mods/constants.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::{Idl, IdlType}; +use anchor_idl::types::{Idl, IdlType}; use quote::{format_ident, quote, ToTokens}; use super::common::convert_idl_type_to_str; diff --git a/lang/attribute/program/src/declare_program/mods/cpi.rs b/lang/attribute/program/src/declare_program/mods/cpi.rs index fc14af2fc5..180c1b8879 100644 --- a/lang/attribute/program/src/declare_program/mods/cpi.rs +++ b/lang/attribute/program/src/declare_program/mods/cpi.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::Idl; +use anchor_idl::types::Idl; use heck::CamelCase; use quote::{format_ident, quote}; diff --git a/lang/attribute/program/src/declare_program/mods/events.rs b/lang/attribute/program/src/declare_program/mods/events.rs index f6730ee0f0..f2c4ca4cff 100644 --- a/lang/attribute/program/src/declare_program/mods/events.rs +++ b/lang/attribute/program/src/declare_program/mods/events.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::Idl; +use anchor_idl::types::Idl; use quote::{format_ident, quote}; use super::common::{convert_idl_type_def_to_ts, gen_discriminator}; diff --git a/lang/attribute/program/src/declare_program/mods/internal.rs b/lang/attribute/program/src/declare_program/mods/internal.rs index 69e3c7e70a..eefdf2032b 100644 --- a/lang/attribute/program/src/declare_program/mods/internal.rs +++ b/lang/attribute/program/src/declare_program/mods/internal.rs @@ -1,6 +1,6 @@ +use anchor_idl::types::{Idl, IdlInstructionAccountItem}; use anchor_syn::{ codegen::accounts::{__client_accounts, __cpi_client_accounts}, - idl::types::{Idl, IdlInstructionAccountItem}, parser::accounts, AccountsStruct, }; diff --git a/lang/attribute/program/src/declare_program/mods/types.rs b/lang/attribute/program/src/declare_program/mods/types.rs index c2dd2970ac..441454c87e 100644 --- a/lang/attribute/program/src/declare_program/mods/types.rs +++ b/lang/attribute/program/src/declare_program/mods/types.rs @@ -1,4 +1,4 @@ -use anchor_syn::idl::types::Idl; +use anchor_idl::types::Idl; use quote::quote; use super::common::convert_idl_type_def_to_ts; diff --git a/lang/derive/serde/src/lib.rs b/lang/derive/serde/src/lib.rs index 75996f1e5c..7326697b44 100644 --- a/lang/derive/serde/src/lib.rs +++ b/lang/derive/serde/src/lib.rs @@ -32,7 +32,7 @@ pub fn anchor_serialize(input: TokenStream) -> TokenStream { #[cfg(feature = "idl-build")] { - use anchor_syn::idl::build::*; + use anchor_syn::idl::*; use quote::quote; let idl_build_impl = match syn::parse(input).unwrap() { diff --git a/lang/src/bpf_upgradeable_state.rs b/lang/src/bpf_upgradeable_state.rs index 845f391487..2bf76ef2dd 100644 --- a/lang/src/bpf_upgradeable_state.rs +++ b/lang/src/bpf_upgradeable_state.rs @@ -77,7 +77,7 @@ impl AccountDeserialize for UpgradeableLoaderState { mod idl_build { use super::*; - impl crate::IdlBuild for ProgramData {} + impl crate::idl::IdlBuild for ProgramData {} impl crate::Discriminator for ProgramData { const DISCRIMINATOR: [u8; 8] = [u8::MAX; 8]; } diff --git a/lang/src/idl.rs b/lang/src/idl.rs index 24544bd482..7c2bd75164 100644 --- a/lang/src/idl.rs +++ b/lang/src/idl.rs @@ -79,3 +79,6 @@ impl IdlAccount { "anchor:idl" } } + +#[cfg(feature = "idl-build")] +pub use anchor_idl::{build::IdlBuild, *}; diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 15afd68673..7fb7947bba 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -64,9 +64,6 @@ 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::{self, idl::build::IdlBuild}; - #[cfg(feature = "interface-instructions")] pub use anchor_attribute_program::interface; @@ -423,7 +420,7 @@ pub mod prelude { pub use super::{emit_cpi, event_cpi}; #[cfg(feature = "idl-build")] - pub use super::IdlBuild; + pub use super::idl::IdlBuild; #[cfg(feature = "interface-instructions")] pub use super::interface; diff --git a/lang/syn/Cargo.toml b/lang/syn/Cargo.toml index 5904a8091b..fcf859f41e 100644 --- a/lang/syn/Cargo.toml +++ b/lang/syn/Cargo.toml @@ -17,8 +17,7 @@ allow-missing-optionals = [] anchor-debug = [] event-cpi = [] hash = [] -idl-build = ["idl-types", "cargo_toml"] -idl-types = [] +idl-build = ["cargo_toml"] init-if-needed = [] interface-instructions = [] diff --git a/lang/syn/src/codegen/accounts/mod.rs b/lang/syn/src/codegen/accounts/mod.rs index 5789262e9b..b3c48101e3 100644 --- a/lang/syn/src/codegen/accounts/mod.rs +++ b/lang/syn/src/codegen/accounts/mod.rs @@ -37,7 +37,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream { #[cfg(feature = "idl-build")] { - let idl_build_impl = crate::idl::build::gen_idl_build_impl_accounts_struct(accs); + let idl_build_impl = crate::idl::gen_idl_build_impl_accounts_struct(accs); return quote! { #ret #idl_build_impl diff --git a/lang/syn/src/codegen/error.rs b/lang/syn/src/codegen/error.rs index f61212e3b8..aa30e57418 100644 --- a/lang/syn/src/codegen/error.rs +++ b/lang/syn/src/codegen/error.rs @@ -100,7 +100,7 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream { #[cfg(feature = "idl-build")] { - let idl_print = crate::idl::build::gen_idl_print_fn_error(&error); + let idl_print = crate::idl::gen_idl_print_fn_error(&error); return quote! { #ret #idl_print diff --git a/lang/syn/src/codegen/program/mod.rs b/lang/syn/src/codegen/program/mod.rs index 6c456e2c17..ed2c9bbb46 100644 --- a/lang/syn/src/codegen/program/mod.rs +++ b/lang/syn/src/codegen/program/mod.rs @@ -39,7 +39,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream { #[cfg(feature = "idl-build")] { - let idl_build_impl = crate::idl::build::gen_idl_print_fn_program(program); + let idl_build_impl = crate::idl::gen_idl_print_fn_program(program); return quote! { #ret #idl_build_impl diff --git a/lang/syn/src/idl/build/accounts.rs b/lang/syn/src/idl/accounts.rs similarity index 100% rename from lang/syn/src/idl/build/accounts.rs rename to lang/syn/src/idl/accounts.rs diff --git a/lang/syn/src/idl/build/address.rs b/lang/syn/src/idl/address.rs similarity index 100% rename from lang/syn/src/idl/build/address.rs rename to lang/syn/src/idl/address.rs diff --git a/lang/syn/src/idl/build/mod.rs b/lang/syn/src/idl/build/mod.rs deleted file mode 100644 index e2974da54e..0000000000 --- a/lang/syn/src/idl/build/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(dead_code)] - -mod accounts; -mod address; -mod common; -mod constant; -mod defined; -mod error; -mod event; -mod external; -mod program; - -pub use accounts::gen_idl_build_impl_accounts_struct; -pub use address::gen_idl_print_fn_address; -pub use constant::gen_idl_print_fn_constant; -pub use defined::{impl_idl_build_enum, impl_idl_build_struct, impl_idl_build_union, IdlBuild}; -pub use error::gen_idl_print_fn_error; -pub use event::gen_idl_print_fn_event; -pub use program::gen_idl_print_fn_program; - -pub use serde_json; diff --git a/lang/syn/src/idl/build/common.rs b/lang/syn/src/idl/common.rs similarity index 90% rename from lang/syn/src/idl/build/common.rs rename to lang/syn/src/idl/common.rs index e3de92ed39..ff395b4b5b 100644 --- a/lang/syn/src/idl/build/common.rs +++ b/lang/syn/src/idl/common.rs @@ -26,11 +26,11 @@ pub fn get_no_docs() -> bool { } pub fn get_idl_module_path() -> TokenStream { - quote!(anchor_lang::anchor_syn::idl::types) + quote!(anchor_lang::idl::types) } pub fn get_serde_json_module_path() -> TokenStream { - quote!(anchor_lang::anchor_syn::idl::build::serde_json) + quote!(anchor_lang::idl::serde_json) } pub fn gen_print_section(name: &str, value: impl ToTokens) -> TokenStream { diff --git a/lang/syn/src/idl/build/constant.rs b/lang/syn/src/idl/constant.rs similarity index 100% rename from lang/syn/src/idl/build/constant.rs rename to lang/syn/src/idl/constant.rs diff --git a/lang/syn/src/idl/build/defined.rs b/lang/syn/src/idl/defined.rs similarity index 93% rename from lang/syn/src/idl/build/defined.rs rename to lang/syn/src/idl/defined.rs index 0bdf3e9134..82c1d95879 100644 --- a/lang/syn/src/idl/build/defined.rs +++ b/lang/syn/src/idl/defined.rs @@ -1,55 +1,21 @@ -use std::collections::BTreeMap; - use anyhow::{anyhow, Result}; use proc_macro2::TokenStream; use quote::quote; use super::common::{get_idl_module_path, get_no_docs}; -use crate::{idl::types::IdlTypeDef, parser::docs}; - -/// A trait that types must implement in order to include the type in the IDL definition. -/// -/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize` -/// proc macro. Note that manually implementing the `AnchorSerialize` trait does **NOT** have the -/// same effect. -/// -/// Types that don't implement this trait will cause a compile error during the IDL generation. -/// -/// The default implementation of the trait allows the program to compile but the type does **NOT** -/// get included in the IDL. -pub trait IdlBuild { - /// Create an IDL type definition for the type. - /// - /// The type is only included in the IDL if this method returns `Some`. - fn create_type() -> Option { - None - } - - /// Insert all types that are included in the current type definition to the given map. - fn insert_types(_types: &mut BTreeMap) {} - - /// Get the full module path of the type. - /// - /// The full path will be used in the case of a conflicting type definition, e.g. when there - /// are multiple structs with the same name. - /// - /// The default implementation covers most cases. - fn get_full_path() -> String { - std::any::type_name::().into() - } -} +use crate::parser::docs; -/// Generate [`IdlBuild`] impl for a struct. +/// Generate `IdlBuild` impl for a struct. pub fn impl_idl_build_struct(item: &syn::ItemStruct) -> TokenStream { impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_struct(item)) } -/// Generate [`IdlBuild`] impl for an enum. +/// Generate `IdlBuild` impl for an enum. pub fn impl_idl_build_enum(item: &syn::ItemEnum) -> TokenStream { impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_enum(item)) } -/// Generate [`IdlBuild`] impl for a union. +/// Generate `IdlBuild` impl for a union. /// /// Unions are not currently supported in the IDL. pub fn impl_idl_build_union(item: &syn::ItemUnion) -> TokenStream { @@ -60,7 +26,7 @@ pub fn impl_idl_build_union(item: &syn::ItemUnion) -> TokenStream { ) } -/// Generate [`IdlBuild`] implementation. +/// Generate `IdlBuild` implementation. fn impl_idl_build( ident: &syn::Ident, generics: &syn::Generics, @@ -68,7 +34,7 @@ fn impl_idl_build( ) -> TokenStream { let idl = get_idl_module_path(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let idl_build_trait = quote!(anchor_lang::anchor_syn::idl::build::IdlBuild); + let idl_build_trait = quote!(anchor_lang::idl::build::IdlBuild); let (idl_type_def, insert_defined) = match type_def { Ok((ts, defined)) => ( diff --git a/lang/syn/src/idl/build/error.rs b/lang/syn/src/idl/error.rs similarity index 100% rename from lang/syn/src/idl/build/error.rs rename to lang/syn/src/idl/error.rs diff --git a/lang/syn/src/idl/build/event.rs b/lang/syn/src/idl/event.rs similarity index 100% rename from lang/syn/src/idl/build/event.rs rename to lang/syn/src/idl/event.rs diff --git a/lang/syn/src/idl/build/external.rs b/lang/syn/src/idl/external.rs similarity index 100% rename from lang/syn/src/idl/build/external.rs rename to lang/syn/src/idl/external.rs diff --git a/lang/syn/src/idl/mod.rs b/lang/syn/src/idl/mod.rs index 8a3bb7a883..42c7dbe77e 100644 --- a/lang/syn/src/idl/mod.rs +++ b/lang/syn/src/idl/mod.rs @@ -1,4 +1,19 @@ -pub mod types; +#![allow(dead_code)] -#[cfg(feature = "idl-build")] -pub mod build; +mod accounts; +mod address; +mod common; +mod constant; +mod defined; +mod error; +mod event; +mod external; +mod program; + +pub use accounts::gen_idl_build_impl_accounts_struct; +pub use address::gen_idl_print_fn_address; +pub use constant::gen_idl_print_fn_constant; +pub use defined::{impl_idl_build_enum, impl_idl_build_struct, impl_idl_build_union}; +pub use error::gen_idl_print_fn_error; +pub use event::gen_idl_print_fn_event; +pub use program::gen_idl_print_fn_program; diff --git a/lang/syn/src/idl/build/program.rs b/lang/syn/src/idl/program.rs similarity index 100% rename from lang/syn/src/idl/build/program.rs rename to lang/syn/src/idl/program.rs diff --git a/lang/syn/src/idl/types.rs b/lang/syn/src/idl/types.rs deleted file mode 100644 index a145f8261d..0000000000 --- a/lang/syn/src/idl/types.rs +++ /dev/null @@ -1,486 +0,0 @@ -use std::str::FromStr; - -use anyhow::anyhow; -use serde::{Deserialize, Serialize}; - -/// IDL specification Semantic Version -pub const IDL_SPEC: &str = "0.1.0"; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Idl { - pub address: String, - pub metadata: IdlMetadata, - #[serde(default, skip_serializing_if = "is_default")] - pub docs: Vec, - pub instructions: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub accounts: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub events: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub errors: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub types: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub constants: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlMetadata { - pub name: String, - pub version: String, - pub spec: String, - #[serde(skip_serializing_if = "is_default")] - pub description: Option, - #[serde(skip_serializing_if = "is_default")] - pub repository: Option, - #[serde(default, skip_serializing_if = "is_default")] - pub dependencies: Vec, - #[serde(skip_serializing_if = "is_default")] - pub contact: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlDependency { - pub name: String, - pub version: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlInstruction { - pub name: String, - #[serde(default, skip_serializing_if = "is_default")] - pub docs: Vec, - pub discriminator: IdlDiscriminator, - pub accounts: Vec, - pub args: Vec, - #[serde(skip_serializing_if = "is_default")] - pub returns: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum IdlInstructionAccountItem { - Composite(IdlInstructionAccounts), - Single(IdlInstructionAccount), -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlInstructionAccount { - pub name: String, - #[serde(default, skip_serializing_if = "is_default")] - pub docs: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub writable: bool, - #[serde(default, skip_serializing_if = "is_default")] - pub signer: bool, - #[serde(default, skip_serializing_if = "is_default")] - pub optional: bool, - #[serde(skip_serializing_if = "is_default")] - pub address: Option, - #[serde(skip_serializing_if = "is_default")] - pub pda: Option, - #[serde(default, skip_serializing_if = "is_default")] - pub relations: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlInstructionAccounts { - pub name: String, - pub accounts: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlPda { - pub seeds: Vec, - #[serde(skip_serializing_if = "is_default")] - pub program: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum IdlSeed { - Const(IdlSeedConst), - Arg(IdlSeedArg), - Account(IdlSeedAccount), -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlSeedConst { - pub value: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlSeedArg { - pub path: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlSeedAccount { - pub path: String, - #[serde(skip_serializing_if = "is_default")] - pub account: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlAccount { - pub name: String, - pub discriminator: IdlDiscriminator, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlEvent { - pub name: String, - pub discriminator: IdlDiscriminator, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlConst { - pub name: String, - #[serde(rename = "type")] - pub ty: IdlType, - pub value: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct IdlErrorCode { - pub code: u32, - pub name: String, - #[serde(skip_serializing_if = "is_default")] - pub msg: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlField { - pub name: String, - #[serde(default, skip_serializing_if = "is_default")] - pub docs: Vec, - #[serde(rename = "type")] - pub ty: IdlType, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlTypeDef { - pub name: String, - #[serde(default, skip_serializing_if = "is_default")] - pub docs: Vec, - #[serde(default, skip_serializing_if = "is_default")] - pub serialization: IdlSerialization, - #[serde(skip_serializing_if = "is_default")] - pub repr: Option, - #[serde(default, skip_serializing_if = "is_default")] - pub generics: Vec, - #[serde(rename = "type")] - pub ty: IdlTypeDefTy, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)] -#[serde(rename_all = "lowercase")] -pub enum IdlSerialization { - #[default] - Borsh, - Bytemuck, - BytemuckUnsafe, - Custom(String), -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum IdlRepr { - Rust(IdlReprModifier), - C(IdlReprModifier), - Transparent, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlReprModifier { - #[serde(default, skip_serializing_if = "is_default")] - pub packed: bool, - #[serde(skip_serializing_if = "is_default")] - pub align: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum IdlTypeDefGeneric { - Type { - name: String, - }, - Const { - name: String, - #[serde(rename = "type")] - ty: String, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum IdlTypeDefTy { - Struct { - #[serde(skip_serializing_if = "is_default")] - fields: Option, - }, - Enum { - variants: Vec, - }, - Type { - alias: IdlType, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct IdlEnumVariant { - pub name: String, - #[serde(skip_serializing_if = "is_default")] - pub fields: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(untagged)] -pub enum IdlDefinedFields { - Named(Vec), - Tuple(Vec), -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum IdlArrayLen { - Generic(String), - #[serde(untagged)] - Value(usize), -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum IdlGenericArg { - Type { - #[serde(rename = "type")] - ty: IdlType, - }, - Const { - value: String, - }, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum IdlType { - Bool, - U8, - I8, - U16, - I16, - U32, - I32, - F32, - U64, - I64, - F64, - U128, - I128, - U256, - I256, - Bytes, - String, - Pubkey, - Option(Box), - Vec(Box), - Array(Box, IdlArrayLen), - Defined { - name: String, - #[serde(default, skip_serializing_if = "is_default")] - generics: Vec, - }, - Generic(String), -} - -impl FromStr for IdlType { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - let mut s = s.to_owned(); - s.retain(|c| !c.is_whitespace()); - - let r = match s.as_str() { - "bool" => IdlType::Bool, - "u8" => IdlType::U8, - "i8" => IdlType::I8, - "u16" => IdlType::U16, - "i16" => IdlType::I16, - "u32" => IdlType::U32, - "i32" => IdlType::I32, - "f32" => IdlType::F32, - "u64" => IdlType::U64, - "i64" => IdlType::I64, - "f64" => IdlType::F64, - "u128" => IdlType::U128, - "i128" => IdlType::I128, - "u256" => IdlType::U256, - "i256" => IdlType::I256, - "Vec" => IdlType::Bytes, - "String" | "&str" | "&'staticstr" => IdlType::String, - "Pubkey" => IdlType::Pubkey, - _ => { - if let Some(inner) = s.strip_prefix("Option<") { - let inner_ty = Self::from_str( - inner - .strip_suffix('>') - .ok_or_else(|| anyhow!("Invalid Option"))?, - )?; - return Ok(IdlType::Option(Box::new(inner_ty))); - } - - if let Some(inner) = s.strip_prefix("Vec<") { - let inner_ty = Self::from_str( - inner - .strip_suffix('>') - .ok_or_else(|| anyhow!("Invalid Vec"))?, - )?; - return Ok(IdlType::Vec(Box::new(inner_ty))); - } - - if s.starts_with('[') { - fn array_from_str(inner: &str) -> IdlType { - match inner.strip_suffix(']') { - Some(nested_inner) => array_from_str(&nested_inner[1..]), - None => { - let (raw_type, raw_length) = inner.rsplit_once(';').unwrap(); - let ty = IdlType::from_str(raw_type).unwrap(); - let len = match raw_length.replace('_', "").parse::() { - Ok(len) => IdlArrayLen::Value(len), - Err(_) => IdlArrayLen::Generic(raw_length.to_owned()), - }; - IdlType::Array(Box::new(ty), len) - } - } - } - return Ok(array_from_str(&s)); - } - - // Defined - let (name, generics) = if let Some(i) = s.find('<') { - ( - s.get(..i).unwrap().to_owned(), - s.get(i + 1..) - .unwrap() - .strip_suffix('>') - .unwrap() - .split(',') - .map(|g| g.trim().to_owned()) - .map(|g| { - if g.parse::().is_ok() - || g.parse::().is_ok() - || g.parse::().is_ok() - || g.parse::().is_ok() - { - Ok(IdlGenericArg::Const { value: g }) - } else { - Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty }) - } - }) - .collect::, _>>()?, - ) - } else { - (s.to_owned(), vec![]) - }; - - IdlType::Defined { name, generics } - } - }; - Ok(r) - } -} - -pub type IdlDiscriminator = Vec; - -/// Get whether the given data is the default of its type. -fn is_default(it: &T) -> bool { - *it == T::default() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn option() { - assert_eq!( - IdlType::from_str("Option").unwrap(), - IdlType::Option(Box::new(IdlType::Bool)) - ) - } - - #[test] - fn vector() { - assert_eq!( - IdlType::from_str("Vec").unwrap(), - IdlType::Vec(Box::new(IdlType::Bool)) - ) - } - - #[test] - fn array() { - assert_eq!( - IdlType::from_str("[Pubkey; 16]").unwrap(), - IdlType::Array(Box::new(IdlType::Pubkey), IdlArrayLen::Value(16)) - ); - } - - #[test] - fn array_with_underscored_length() { - assert_eq!( - IdlType::from_str("[u8; 50_000]").unwrap(), - IdlType::Array(Box::new(IdlType::U8), IdlArrayLen::Value(50000)) - ); - } - - #[test] - fn multidimensional_array() { - assert_eq!( - IdlType::from_str("[[u8; 16]; 32]").unwrap(), - IdlType::Array( - Box::new(IdlType::Array( - Box::new(IdlType::U8), - IdlArrayLen::Value(16) - )), - IdlArrayLen::Value(32) - ) - ); - } - - #[test] - fn generic_array() { - assert_eq!( - IdlType::from_str("[u64; T]").unwrap(), - IdlType::Array(Box::new(IdlType::U64), IdlArrayLen::Generic("T".into())) - ); - } - - #[test] - fn defined() { - assert_eq!( - IdlType::from_str("MyStruct").unwrap(), - IdlType::Defined { - name: "MyStruct".into(), - generics: vec![] - } - ) - } - - #[test] - fn defined_with_generics() { - assert_eq!( - IdlType::from_str("MyStruct").unwrap(), - IdlType::Defined { - name: "MyStruct".into(), - generics: vec![ - IdlGenericArg::Type { - ty: IdlType::Pubkey - }, - IdlGenericArg::Type { ty: IdlType::U64 }, - IdlGenericArg::Const { value: "8".into() }, - ], - } - ) - } -} diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 4fc1182453..618c43494f 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -3,7 +3,7 @@ pub mod codegen; pub mod parser; -#[cfg(feature = "idl-types")] +#[cfg(feature = "idl-build")] pub mod idl; #[cfg(feature = "hash")] diff --git a/tests/idl/programs/new-idl/src/lib.rs b/tests/idl/programs/new-idl/src/lib.rs index 9624f6e08b..7e706d25f3 100644 --- a/tests/idl/programs/new-idl/src/lib.rs +++ b/tests/idl/programs/new-idl/src/lib.rs @@ -366,7 +366,7 @@ mod wrapped { use super::*; #[cfg(feature = "idl-build")] - use anchor_lang::anchor_syn::idl::types::*; + use anchor_lang::idl::types::*; pub struct Feature(anchor_lang::solana_program::feature::Feature); From 8abd0c423f329d139a867bdeb92e4b1b40f59e2a Mon Sep 17 00:00:00 2001 From: acheron Date: Tue, 2 Apr 2024 19:42:56 +0200 Subject: [PATCH 2/3] lang: Re-export `IdlBuild` trait from the root --- lang/src/bpf_upgradeable_state.rs | 2 +- lang/src/lib.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lang/src/bpf_upgradeable_state.rs b/lang/src/bpf_upgradeable_state.rs index 2bf76ef2dd..845f391487 100644 --- a/lang/src/bpf_upgradeable_state.rs +++ b/lang/src/bpf_upgradeable_state.rs @@ -77,7 +77,7 @@ impl AccountDeserialize for UpgradeableLoaderState { mod idl_build { use super::*; - impl crate::idl::IdlBuild for ProgramData {} + impl crate::IdlBuild for ProgramData {} impl crate::Discriminator for ProgramData { const DISCRIMINATOR: [u8; 8] = [u8::MAX; 8]; } diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 7fb7947bba..bb3766cc99 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -64,6 +64,9 @@ pub use solana_program; #[cfg(feature = "event-cpi")] pub use anchor_attribute_event::{emit_cpi, event_cpi}; +#[cfg(feature = "idl-build")] +pub use idl::IdlBuild; + #[cfg(feature = "interface-instructions")] pub use anchor_attribute_program::interface; From cc47b39a9ceaabfec8e2038515ce2aff9455e576 Mon Sep 17 00:00:00 2001 From: acheron Date: Tue, 2 Apr 2024 19:43:23 +0200 Subject: [PATCH 3/3] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dec8f940b6..36de9be268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ The minor version will be incremented upon a breaking change and the patch versi - ts: `Program` instances use camelCase for everything ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). - ts: Remove discriminator functions ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). - ts: Remove `programId` parameter of the `Program` constructor ([#2864](https://github.com/coral-xyz/anchor/pull/2864)). +- idl, syn: Move IDL types from the `anchor-syn` crate to the new IDL crate ([#2882](https://github.com/coral-xyz/anchor/pull/2882)). ## [0.29.0] - 2023-10-16