idl: Move IDL types from the `anchor-syn` crate to the new IDL crate (#2882)
This commit is contained in:
parent
475c694355
commit
c138a55b72
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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<IdlTypeDef> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Insert all types that are included in the current type definition to the given map.
|
||||
fn insert_types(_types: &mut BTreeMap<String, IdlTypeDef>) {}
|
||||
|
||||
/// 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::<Self>().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate IDL via compilation.
|
||||
pub fn build_idl(
|
||||
program_path: impl AsRef<Path>,
|
||||
|
|
|
@ -4,3 +4,6 @@ pub mod types;
|
|||
|
||||
#[cfg(feature = "build")]
|
||||
pub mod build;
|
||||
|
||||
#[cfg(feature = "build")]
|
||||
pub use serde_json;
|
||||
|
|
487
idl/src/types.rs
487
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<String>,
|
||||
pub instructions: Vec<IdlInstruction>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub accounts: Vec<IdlAccount>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub events: Vec<IdlEvent>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub errors: Vec<IdlErrorCode>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub types: Vec<IdlTypeDef>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub constants: Vec<IdlConst>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub repository: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub dependencies: Vec<IdlDependency>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub contact: Option<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
pub discriminator: IdlDiscriminator,
|
||||
pub accounts: Vec<IdlInstructionAccountItem>,
|
||||
pub args: Vec<IdlField>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub returns: Option<IdlType>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub pda: Option<IdlPda>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub relations: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlInstructionAccounts {
|
||||
pub name: String,
|
||||
pub accounts: Vec<IdlInstructionAccountItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlPda {
|
||||
pub seeds: Vec<IdlSeed>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub program: Option<IdlSeed>,
|
||||
}
|
||||
|
||||
#[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<u8>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlField {
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub docs: Vec<String>,
|
||||
#[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<String>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub serialization: IdlSerialization,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub repr: Option<IdlRepr>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub generics: Vec<IdlTypeDefGeneric>,
|
||||
#[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<usize>,
|
||||
}
|
||||
|
||||
#[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<IdlDefinedFields>,
|
||||
},
|
||||
Enum {
|
||||
variants: Vec<IdlEnumVariant>,
|
||||
},
|
||||
Type {
|
||||
alias: IdlType,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEnumVariant {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub fields: Option<IdlDefinedFields>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum IdlDefinedFields {
|
||||
Named(Vec<IdlField>),
|
||||
Tuple(Vec<IdlType>),
|
||||
}
|
||||
|
||||
#[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<IdlType>),
|
||||
Vec(Box<IdlType>),
|
||||
Array(Box<IdlType>, IdlArrayLen),
|
||||
Defined {
|
||||
name: String,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
generics: Vec<IdlGenericArg>,
|
||||
},
|
||||
Generic(String),
|
||||
}
|
||||
|
||||
impl FromStr for IdlType {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<u8>" => 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::<usize>() {
|
||||
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::<bool>().is_ok()
|
||||
|| g.parse::<u128>().is_ok()
|
||||
|| g.parse::<i128>().is_ok()
|
||||
|| g.parse::<char>().is_ok()
|
||||
{
|
||||
Ok(IdlGenericArg::Const { value: g })
|
||||
} else {
|
||||
Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty })
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)
|
||||
} else {
|
||||
(s.to_owned(), vec![])
|
||||
};
|
||||
|
||||
IdlType::Defined { name, generics }
|
||||
}
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub type IdlDiscriminator = Vec<u8>;
|
||||
|
||||
/// Get whether the given data is the default of its type.
|
||||
fn is_default<T: Default + PartialEq>(it: &T) -> bool {
|
||||
*it == T::default()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Option<bool>").unwrap(),
|
||||
IdlType::Option(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Vec<bool>").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<Pubkey, u64, 8>").unwrap(),
|
||||
IdlType::Defined {
|
||||
name: "MyStruct".into(),
|
||||
generics: vec![
|
||||
IdlGenericArg::Type {
|
||||
ty: IdlType::Pubkey
|
||||
},
|
||||
IdlGenericArg::Type { ty: IdlType::U64 },
|
||||
IdlGenericArg::Const { value: "8".into() },
|
||||
],
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_syn::idl::types::{
|
||||
use anchor_idl::types::{
|
||||
Idl, IdlArrayLen, IdlDefinedFields, IdlField, IdlGenericArg, IdlRepr, IdlSerialization,
|
||||
IdlType, IdlTypeDef, IdlTypeDefGeneric, IdlTypeDefTy,
|
||||
};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_syn::idl::types::Idl;
|
||||
use anchor_idl::types::Idl;
|
||||
use quote::quote;
|
||||
|
||||
use super::common::gen_accounts_common;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use anchor_syn::idl::types::Idl;
|
||||
use anchor_idl::types::Idl;
|
||||
use heck::CamelCase;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -79,3 +79,6 @@ impl IdlAccount {
|
|||
"anchor:idl"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub use anchor_idl::{build::IdlBuild, *};
|
||||
|
|
|
@ -65,7 +65,7 @@ pub use solana_program;
|
|||
pub use anchor_attribute_event::{emit_cpi, event_cpi};
|
||||
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub use anchor_syn::{self, idl::build::IdlBuild};
|
||||
pub use idl::IdlBuild;
|
||||
|
||||
#[cfg(feature = "interface-instructions")]
|
||||
pub use anchor_attribute_program::interface;
|
||||
|
@ -423,7 +423,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;
|
||||
|
|
|
@ -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 = []
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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 {
|
|
@ -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};
|
||||
use crate::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<IdlTypeDef> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Insert all types that are included in the current type definition to the given map.
|
||||
fn insert_types(_types: &mut BTreeMap<String, IdlTypeDef>) {}
|
||||
|
||||
/// 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::<Self>().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)) => (
|
|
@ -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;
|
||||
|
|
|
@ -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<String>,
|
||||
pub instructions: Vec<IdlInstruction>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub accounts: Vec<IdlAccount>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub events: Vec<IdlEvent>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub errors: Vec<IdlErrorCode>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub types: Vec<IdlTypeDef>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub constants: Vec<IdlConst>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub repository: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub dependencies: Vec<IdlDependency>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub contact: Option<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
pub discriminator: IdlDiscriminator,
|
||||
pub accounts: Vec<IdlInstructionAccountItem>,
|
||||
pub args: Vec<IdlField>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub returns: Option<IdlType>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub pda: Option<IdlPda>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub relations: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlInstructionAccounts {
|
||||
pub name: String,
|
||||
pub accounts: Vec<IdlInstructionAccountItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlPda {
|
||||
pub seeds: Vec<IdlSeed>,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub program: Option<IdlSeed>,
|
||||
}
|
||||
|
||||
#[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<u8>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlField {
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub docs: Vec<String>,
|
||||
#[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<String>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub serialization: IdlSerialization,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub repr: Option<IdlRepr>,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
pub generics: Vec<IdlTypeDefGeneric>,
|
||||
#[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<usize>,
|
||||
}
|
||||
|
||||
#[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<IdlDefinedFields>,
|
||||
},
|
||||
Enum {
|
||||
variants: Vec<IdlEnumVariant>,
|
||||
},
|
||||
Type {
|
||||
alias: IdlType,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct IdlEnumVariant {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
pub fields: Option<IdlDefinedFields>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum IdlDefinedFields {
|
||||
Named(Vec<IdlField>),
|
||||
Tuple(Vec<IdlType>),
|
||||
}
|
||||
|
||||
#[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<IdlType>),
|
||||
Vec(Box<IdlType>),
|
||||
Array(Box<IdlType>, IdlArrayLen),
|
||||
Defined {
|
||||
name: String,
|
||||
#[serde(default, skip_serializing_if = "is_default")]
|
||||
generics: Vec<IdlGenericArg>,
|
||||
},
|
||||
Generic(String),
|
||||
}
|
||||
|
||||
impl FromStr for IdlType {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<u8>" => 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::<usize>() {
|
||||
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::<bool>().is_ok()
|
||||
|| g.parse::<u128>().is_ok()
|
||||
|| g.parse::<i128>().is_ok()
|
||||
|| g.parse::<char>().is_ok()
|
||||
{
|
||||
Ok(IdlGenericArg::Const { value: g })
|
||||
} else {
|
||||
Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty })
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)
|
||||
} else {
|
||||
(s.to_owned(), vec![])
|
||||
};
|
||||
|
||||
IdlType::Defined { name, generics }
|
||||
}
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
|
||||
pub type IdlDiscriminator = Vec<u8>;
|
||||
|
||||
/// Get whether the given data is the default of its type.
|
||||
fn is_default<T: Default + PartialEq>(it: &T) -> bool {
|
||||
*it == T::default()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Option<bool>").unwrap(),
|
||||
IdlType::Option(Box::new(IdlType::Bool))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vector() {
|
||||
assert_eq!(
|
||||
IdlType::from_str("Vec<bool>").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<Pubkey, u64, 8>").unwrap(),
|
||||
IdlType::Defined {
|
||||
name: "MyStruct".into(),
|
||||
generics: vec![
|
||||
IdlGenericArg::Type {
|
||||
ty: IdlType::Pubkey
|
||||
},
|
||||
IdlGenericArg::Type { ty: IdlType::U64 },
|
||||
IdlGenericArg::Const { value: "8".into() },
|
||||
],
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
pub mod codegen;
|
||||
pub mod parser;
|
||||
|
||||
#[cfg(feature = "idl-types")]
|
||||
#[cfg(feature = "idl-build")]
|
||||
pub mod idl;
|
||||
|
||||
#[cfg(feature = "hash")]
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue