diff --git a/crates/iota-sdk-ffi/src/types/mod.rs b/crates/iota-sdk-ffi/src/types/mod.rs index 654ee46ed..3492e314b 100644 --- a/crates/iota-sdk-ffi/src/types/mod.rs +++ b/crates/iota-sdk-ffi/src/types/mod.rs @@ -11,5 +11,6 @@ pub mod gas; pub mod graphql; pub mod object; pub mod signature; +pub mod struct_tag; pub mod transaction; pub mod type_tag; diff --git a/crates/iota-sdk-ffi/src/types/struct_tag.rs b/crates/iota-sdk-ffi/src/types/struct_tag.rs new file mode 100644 index 000000000..4741016cf --- /dev/null +++ b/crates/iota-sdk-ffi/src/types/struct_tag.rs @@ -0,0 +1,127 @@ +// Copyright (c) 2025 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use crate::types::{address::Address, type_tag::TypeTag}; + +#[derive(Clone, Debug, derive_more::From, uniffi::Record)] +pub struct TypeParseError { + source: String, +} + +impl From for iota_types::TypeParseError { + fn from(value: TypeParseError) -> Self { + iota_types::TypeParseError { + source: value.source, + } + } +} + +impl From for TypeParseError { + fn from(value: iota_types::TypeParseError) -> Self { + TypeParseError { + source: value.source, + } + } +} + +/// A move identifier +/// +/// # BCS +/// +/// The BCS serialized form for this type is defined by the following ABNF: +/// +/// ```text +/// identifier = %x01-80 ; length of the identifier +/// (ALPHA *127(ALPHA / DIGIT / UNDERSCORE)) / +/// (UNDERSCORE 1*127(ALPHA / DIGIT / UNDERSCORE)) +/// +/// UNDERSCORE = %x95 +/// ``` +#[derive(Clone, Debug, derive_more::From, uniffi::Object)] +pub struct Identifier(iota_types::Identifier); + +impl Identifier { + #[uniffi::constructor] + pub fn new(identifier: impl AsRef) -> Result { + Ok(Self(iota_types::Identifier::new(identifier)?)) + } + + pub fn into_inner(self) -> Box { + self.0.into_inner() + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +/// Type information for a move struct +/// +/// # BCS +/// +/// The BCS serialized form for this type is defined by the following ABNF: +/// +/// ```text +/// struct-tag = address ; address of the package +/// identifier ; name of the module +/// identifier ; name of the type +/// (vector type-tag) ; type parameters +/// ``` +#[derive(Clone, Debug, derive_more::From, uniffi::Object)] +pub struct StructTag(pub iota_types::StructTag); + +#[uniffi::export] +impl StructTag { + #[uniffi::constructor] + pub fn new( + address: &Address, + module: &Identifier, + name: &Identifier, + type_params: Vec>, + ) -> Self { + Self(iota_types::StructTag { + address: address.0, + module: module.0.clone(), + name: name.0.clone(), + type_params: type_params + .iter() + .map(|type_tag| type_tag.0.clone()) + .collect(), + }) + } + + #[uniffi::constructor] + pub fn coin(type_tag: &TypeTag) -> Self { + Self(iota_types::StructTag::coin(type_tag.0.clone())) + } + + /// Checks if this is a Coin type + pub fn coin_type_opt(&self) -> Option> { + self.0 + .coin_type_opt() + .cloned() + .map(Into::into) + .map(Arc::new) + } + + /// Checks if this is a Coin type + pub fn coin_type(&self) -> TypeTag { + self.0.coin_type().clone().into() + } + + #[uniffi::constructor] + pub fn gas_coin() -> Self { + Self(iota_types::StructTag::gas_coin()) + } + + #[uniffi::constructor] + pub fn staked_iota() -> Self { + Self(iota_types::StructTag::staked_iota()) + } + + pub fn address(&self) -> Address { + self.0.address().into() + } +} diff --git a/crates/iota-sdk-ffi/src/types/type_tag.rs b/crates/iota-sdk-ffi/src/types/type_tag.rs index 3f472c0b7..9a154a4ce 100644 --- a/crates/iota-sdk-ffi/src/types/type_tag.rs +++ b/crates/iota-sdk-ffi/src/types/type_tag.rs @@ -1,5 +1,181 @@ // Copyright (c) 2025 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +use std::sync::Arc; + +use crate::types::struct_tag::StructTag; + +/// Type of a move value +/// +/// # BCS +/// +/// The BCS serialized form for this type is defined by the following ABNF: +/// +/// ```text +/// type-tag = type-tag-u8 \ +/// type-tag-u16 \ +/// type-tag-u32 \ +/// type-tag-u64 \ +/// type-tag-u128 \ +/// type-tag-u256 \ +/// type-tag-bool \ +/// type-tag-address \ +/// type-tag-signer \ +/// type-tag-vector \ +/// type-tag-struct +/// +/// type-tag-u8 = %x01 +/// type-tag-u16 = %x08 +/// type-tag-u32 = %x09 +/// type-tag-u64 = %x02 +/// type-tag-u128 = %x03 +/// type-tag-u256 = %x0a +/// type-tag-bool = %x00 +/// type-tag-address = %x04 +/// type-tag-signer = %x05 +/// type-tag-vector = %x06 type-tag +/// type-tag-struct = %x07 struct-tag +/// ``` #[derive(Clone, Debug, derive_more::From, uniffi::Object)] pub struct TypeTag(pub iota_types::TypeTag); + +#[uniffi::export] +impl TypeTag { + #[inline] + pub fn is_u8(&self) -> bool { + self.0.is_u8() + } + + #[inline] + pub fn is_u16(&self) -> bool { + self.0.is_u16() + } + + #[inline] + pub fn is_u32(&self) -> bool { + self.0.is_u32() + } + + #[inline] + pub fn is_u64(&self) -> bool { + self.0.is_u64() + } + + #[inline] + pub fn is_u128(&self) -> bool { + self.0.is_u128() + } + + #[inline] + pub fn is_u256(&self) -> bool { + self.0.is_u256() + } + + #[inline] + pub fn is_bool(&self) -> bool { + self.0.is_bool() + } + + #[inline] + pub fn is_address(&self) -> bool { + self.0.is_address() + } + + #[inline] + pub fn is_signer(&self) -> bool { + self.0.is_signer() + } + + #[inline] + pub fn is_vector(&self) -> bool { + self.0.is_vector() + } + + #[inline] + pub fn as_vector_type_tag_opt(&self) -> Option> { + self.0 + .as_vector_type_tag_opt() + .cloned() + .map(Into::into) + .map(Arc::new) + } + + #[inline] + pub fn as_vector_type_tag(&self) -> TypeTag { + self.0.as_vector_type_tag().clone().into() + } + + #[inline] + pub fn is_struct(&self) -> bool { + self.0.is_struct() + } + + #[inline] + pub fn as_struct_tag_opt(&self) -> Option> { + self.0 + .as_struct_tag_opt() + .cloned() + .map(Into::into) + .map(Arc::new) + } + + #[inline] + pub fn as_struct_tag(&self) -> StructTag { + self.0.as_struct_tag().clone().into() + } + + #[uniffi::constructor] + pub fn u8() -> Self { + Self(iota_types::TypeTag::U8) + } + + #[uniffi::constructor] + pub fn u16() -> Self { + Self(iota_types::TypeTag::U16) + } + + #[uniffi::constructor] + pub fn u32() -> Self { + Self(iota_types::TypeTag::U32) + } + + #[uniffi::constructor] + pub fn u64() -> Self { + Self(iota_types::TypeTag::U64) + } + + #[uniffi::constructor] + pub fn u128() -> Self { + Self(iota_types::TypeTag::U128) + } + + #[uniffi::constructor] + pub fn u256() -> Self { + Self(iota_types::TypeTag::U256) + } + + #[uniffi::constructor] + pub fn bool() -> Self { + Self(iota_types::TypeTag::Bool) + } + + #[uniffi::constructor] + pub fn address() -> Self { + Self(iota_types::TypeTag::Address) + } + + #[uniffi::constructor] + pub fn signer() -> Self { + Self(iota_types::TypeTag::Signer) + } + + #[uniffi::constructor] + pub fn vector(type_tag: &TypeTag) -> Self { + Self(iota_types::TypeTag::Vector(Box::new(type_tag.0.clone()))) + } + + #[uniffi::constructor] + pub fn struct_tag(struct_tag: &StructTag) -> Self { + Self(iota_types::TypeTag::Struct(Box::new(struct_tag.0.clone()))) + } +} diff --git a/crates/iota-sdk-types/src/type_tag/mod.rs b/crates/iota-sdk-types/src/type_tag/mod.rs index 9b3e513b0..839e90b1b 100644 --- a/crates/iota-sdk-types/src/type_tag/mod.rs +++ b/crates/iota-sdk-types/src/type_tag/mod.rs @@ -61,11 +61,11 @@ pub enum TypeTag { impl TypeTag { crate::def_is!(U8, U16, U32, U64, U128, U256, Bool, Address, Signer); - pub fn is_vector_type(&self) -> bool { + pub fn is_vector(&self) -> bool { matches!(self, Self::Vector(_)) } - pub fn as_vector_type_opt(&self) -> Option<&TypeTag> { + pub fn as_vector_type_tag_opt(&self) -> Option<&TypeTag> { if let Self::Vector(inner) = self { Some(inner) } else { @@ -73,11 +73,11 @@ impl TypeTag { } } - pub fn as_vector_type(&self) -> &TypeTag { - self.as_vector_type_opt().expect("not a Vector") + pub fn as_vector_type_tag(&self) -> &TypeTag { + self.as_vector_type_tag_opt().expect("not a Vector") } - pub fn into_vector_type_opt(self) -> Option { + pub fn into_vector_type_tag_opt(self) -> Option { if let Self::Vector(inner) = self { Some(*inner) } else { @@ -85,8 +85,8 @@ impl TypeTag { } } - pub fn into_vector_type(self) -> TypeTag { - self.into_vector_type_opt().expect("not a Vector type") + pub fn into_vector_type_tag(self) -> TypeTag { + self.into_vector_type_tag_opt().expect("not a Vector") } pub fn is_struct(&self) -> bool { @@ -190,7 +190,7 @@ impl From for TypeTag { #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct TypeParseError { - source: String, + pub source: String, } impl std::fmt::Display for TypeParseError {