#![cfg_attr(nightly, feature(doc_cfg))]
use std::error::Error as StdError;
use std::fmt::Debug;
#[cfg(feature = "derive")]
pub use moverox_traits_derive::MoveDatatype;
use moverox_types::{Address, IdentStr, Identifier, StructTag, TypeTag};
#[cfg(feature = "derive")]
#[doc(hidden)]
pub mod external;
mod primitives;
mod vector;
pub use self::primitives::{
AddressTypeTag,
BoolTypeTag,
U8TypeTag,
U16TypeTag,
U32TypeTag,
U64TypeTag,
U128TypeTag,
U256TypeTag,
};
pub use self::vector::VecTypeTag;
pub mod prelude {
#[doc(inline)]
pub use crate::{
ConstAddress,
ConstModule,
ConstName,
ConstStructTag,
ConstTypeTag,
HasKey,
MoveDatatype,
MoveDatatypeTag,
MoveType,
MoveTypeTag,
};
}
pub trait MoveType {
type TypeTag: MoveTypeTag;
}
pub trait MoveTypeTag {
fn as_datatype_tag(&self) -> Option<&dyn MoveDatatypeTag>;
fn to_type_tag(&self) -> TypeTag;
fn from_type_tag(value: &TypeTag) -> Result<Self, TypeTagError>
where
Self: Sized;
}
impl<T> MoveTypeTag for T
where
T: MoveDatatypeTag,
{
fn as_datatype_tag(&self) -> Option<&dyn MoveDatatypeTag> {
Some(self as _)
}
fn from_type_tag(value: &TypeTag) -> Result<Self, TypeTagError>
where
Self: Sized,
{
match value {
TypeTag::Struct(stag) => Ok(Self::from_struct_tag(stag)?),
other => Err(TypeTagError::Variant {
expected: "Struct(_)".to_owned(),
got: type_tag_variant_name(other),
}),
}
}
fn to_type_tag(&self) -> TypeTag {
TypeTag::Struct(Box::new(self.to_struct_tag()))
}
}
pub trait MoveDatatype: MoveType<TypeTag = Self::StructTag> {
type StructTag: MoveDatatypeTag;
}
pub trait MoveDatatypeTag: MoveTypeTag {
fn address(&self) -> Address;
fn module(&self) -> &IdentStr;
fn name(&self) -> &IdentStr;
fn type_params(&self) -> Box<[&dyn MoveTypeTag]>;
fn to_struct_tag(&self) -> StructTag {
StructTag {
address: self.address(),
module: self.module().to_owned(),
name: self.name().to_owned(),
type_params: self.type_params().iter().map(|t| t.to_type_tag()).collect(),
}
}
fn from_struct_tag(value: &StructTag) -> Result<Self, StructTagError>
where
Self: Sized;
}
pub trait HasKey {
fn address(&self) -> Address;
}
pub trait ConstAddress {
const ADDRESS: Address;
}
pub trait ConstModule {
const MODULE: &IdentStr;
}
pub trait ConstName {
const NAME: &IdentStr;
}
pub trait ConstTypeTag: MoveType {
const TYPE_TAG: Self::TypeTag;
}
impl<T> ConstTypeTag for T
where
T: ConstStructTag,
{
const TYPE_TAG: Self::TypeTag = Self::STRUCT_TAG;
}
pub trait ConstStructTag: MoveDatatype {
const STRUCT_TAG: Self::StructTag;
}
#[derive(thiserror::Error, Debug)]
pub enum TypeTagError {
#[error("Wrong TypeTag variant: expected {expected}, got {got}")]
Variant { expected: String, got: String },
#[error("StructTag params: {0}")]
StructTag(#[from] StructTagError),
}
#[derive(thiserror::Error, Debug)]
pub enum StructTagError {
#[error("Wrong address: expected {expected}, got {got}")]
Address { expected: Address, got: Address },
#[error("Wrong module: expected {expected}, got {got}")]
Module {
expected: Identifier,
got: Identifier,
},
#[error("Wrong name: expected {expected}, got {got}")]
Name {
expected: Identifier,
got: Identifier,
},
#[error("Wrong type parameters: {0}")]
TypeParams(#[from] TypeParamsError),
}
#[derive(thiserror::Error, Debug)]
pub enum TypeParamsError {
#[error("Wrong number of generics: expected {expected}, got {got}")]
Number { expected: usize, got: usize },
#[error("Wrong type for generic: {0}")]
TypeTag(Box<TypeTagError>),
}
impl From<TypeTagError> for TypeParamsError {
fn from(value: TypeTagError) -> Self {
Self::TypeTag(Box::new(value))
}
}
#[derive(thiserror::Error, Debug)]
pub enum ParseTypeTagError {
#[error("Parsing TypeTag: {0}")]
FromStr(Box<dyn StdError + Send + Sync + 'static>),
#[error("Converting from TypeTag: {0}")]
TypeTag(#[from] TypeTagError),
}
impl ParseTypeTagError {
fn from_str(err: impl StdError + Send + Sync + 'static) -> Self {
Self::FromStr(err.into())
}
}
#[derive(thiserror::Error, Debug)]
pub enum ParseStructTagError {
#[error("Parsing StructTag: {0}")]
FromStr(Box<dyn StdError + Send + Sync + 'static>),
#[error("Converting from StructTag: {0}")]
StructTag(#[from] StructTagError),
}
fn type_tag_variant_name(this: &TypeTag) -> String {
match this {
TypeTag::U8 => "U8",
TypeTag::U16 => "U16",
TypeTag::U32 => "U32",
TypeTag::U64 => "U64",
TypeTag::U128 => "U128",
TypeTag::U256 => "U256",
TypeTag::Bool => "Bool",
TypeTag::Address => "Address",
TypeTag::Signer => "Signer",
TypeTag::Vector(_) => "Vector",
TypeTag::Struct(_) => "Struct",
}
.to_owned()
}