moverox_traits/
lib.rs

1#![cfg_attr(all(doc, not(doctest)), feature(doc_auto_cfg))]
2
3//! Traits for rusty Move types and their type tags.
4//!
5//! The core items are [`MoveType`](crate::MoveType) and [`MoveTypeTag`](crate::MoveTypeTag). These
6//! are useful trait bounds to use when dealing with generic off-chain Move type representations.
7//! They are implemented for the primitive types that correspond to Move's primitives
8//! (integers/bool).
9//!
10//! For Move structs, [`MoveDatatype`](crate::MoveDatatype) should be used as it has an
11//! associated [`MoveDatatypeTag`](crate::MoveDatatypeTag). The
12//! [`MoveDatatype`](moverox_traits_derive::MoveDatatype) derive macro is exported for automatically
13//! creating a `MoveDatatypeTag` implementation from normal Rust struct declarations.
14use std::error::Error as StdError;
15use std::fmt::Debug;
16
17#[cfg(feature = "derive")]
18pub use moverox_traits_derive::MoveDatatype;
19use moverox_types::{Address, IdentStr, Identifier, StructTag, TypeTag};
20
21#[cfg(feature = "derive")]
22#[doc(hidden)]
23pub mod external;
24mod primitives;
25mod vector;
26
27pub use self::primitives::{
28    AddressTypeTag,
29    BoolTypeTag,
30    U8TypeTag,
31    U16TypeTag,
32    U32TypeTag,
33    U64TypeTag,
34    U128TypeTag,
35    U256TypeTag,
36};
37pub use self::vector::VecTypeTag;
38
39// =============================================================================
40//  MoveType
41// =============================================================================
42
43/// Marker for a Move type with its associated type tag.
44pub trait MoveType {
45    type TypeTag: MoveTypeTag;
46}
47
48/// A specialized Move type tag, convertible from/to a generic [`TypeTag`] by reference.
49pub trait MoveTypeTag {
50    fn to_type_tag(&self) -> TypeTag;
51
52    fn from_type_tag(value: &TypeTag) -> Result<Self, TypeTagError>
53    where
54        Self: Sized;
55}
56
57impl<T> MoveTypeTag for T
58where
59    T: MoveDatatypeTag,
60{
61    fn from_type_tag(value: &TypeTag) -> Result<Self, TypeTagError>
62    where
63        Self: Sized,
64    {
65        match value {
66            TypeTag::Struct(stag) => Ok(Self::from_struct_tag(stag)?),
67            other => Err(TypeTagError::Variant {
68                expected: "Struct(_)".to_owned(),
69                got: type_tag_variant_name(other),
70            }),
71        }
72    }
73
74    fn to_type_tag(&self) -> TypeTag {
75        TypeTag::Struct(Box::new(self.to_struct_tag()))
76    }
77}
78
79// =============================================================================
80//  MoveDatatype
81// =============================================================================
82
83/// Marker for a Move datatype with its associated struct tag.
84pub trait MoveDatatype: MoveType<TypeTag = Self::StructTag> {
85    type StructTag: MoveDatatypeTag;
86}
87
88/// A specialized Move type tag for datatypes, convertible from/to a generic [`StructTag`] by
89/// reference.
90pub trait MoveDatatypeTag: MoveTypeTag {
91    fn to_struct_tag(&self) -> StructTag;
92
93    fn from_struct_tag(value: &StructTag) -> Result<Self, StructTagError>
94    where
95        Self: Sized;
96}
97
98// =============================================================================
99//  Abilities
100// =============================================================================
101
102/// An oxidized object, i.e., originally a Move type with the `key` ability.
103pub trait HasKey {
104    /// This object's address on-chain.
105    fn address(&self) -> Address;
106}
107
108// =============================================================================
109//  Static attributes
110// =============================================================================
111
112/// Struct tag with a constant address.
113pub trait ConstAddress {
114    const ADDRESS: Address;
115}
116
117/// Struct tag with a constant module.
118pub trait ConstModule {
119    const MODULE: &IdentStr;
120}
121
122/// Struct tag with a constant name.
123pub trait ConstName {
124    const NAME: &IdentStr;
125}
126
127/// [`MoveType`] with a constant type tag.
128pub trait ConstTypeTag: MoveType {
129    const TYPE_TAG: Self::TypeTag;
130}
131
132impl<T> ConstTypeTag for T
133where
134    T: ConstStructTag,
135{
136    const TYPE_TAG: Self::TypeTag = Self::STRUCT_TAG;
137}
138
139/// [`MoveDatatype`] with a constant struct tag.
140pub trait ConstStructTag: MoveDatatype {
141    const STRUCT_TAG: Self::StructTag;
142}
143
144// =============================================================================
145//  Errors used in traits
146// =============================================================================
147
148#[derive(thiserror::Error, Debug)]
149pub enum TypeTagError {
150    #[error("Wrong TypeTag variant: expected {expected}, got {got}")]
151    Variant { expected: String, got: String },
152    #[error("StructTag params: {0}")]
153    StructTag(#[from] StructTagError),
154}
155
156#[derive(thiserror::Error, Debug)]
157pub enum StructTagError {
158    #[error("Wrong address: expected {expected}, got {got}")]
159    Address { expected: Address, got: Address },
160    #[error("Wrong module: expected {expected}, got {got}")]
161    Module {
162        expected: Identifier,
163        got: Identifier,
164    },
165    #[error("Wrong name: expected {expected}, got {got}")]
166    Name {
167        expected: Identifier,
168        got: Identifier,
169    },
170    #[error("Wrong type parameters: {0}")]
171    TypeParams(#[from] TypeParamsError),
172}
173
174#[derive(thiserror::Error, Debug)]
175pub enum TypeParamsError {
176    #[error("Wrong number of generics: expected {expected}, got {got}")]
177    Number { expected: usize, got: usize },
178    #[error("Wrong type for generic: {0}")]
179    TypeTag(Box<TypeTagError>),
180}
181
182impl From<TypeTagError> for TypeParamsError {
183    fn from(value: TypeTagError) -> Self {
184        Self::TypeTag(Box::new(value))
185    }
186}
187
188// =============================================================================
189//  Errors used in derived impls
190// =============================================================================
191
192#[derive(thiserror::Error, Debug)]
193pub enum ParseTypeTagError {
194    #[error("Parsing TypeTag: {0}")]
195    FromStr(Box<dyn StdError + Send + Sync + 'static>),
196    #[error("Converting from TypeTag: {0}")]
197    TypeTag(#[from] TypeTagError),
198}
199
200impl ParseTypeTagError {
201    fn from_str(err: impl StdError + Send + Sync + 'static) -> Self {
202        Self::FromStr(err.into())
203    }
204}
205
206#[derive(thiserror::Error, Debug)]
207pub enum ParseStructTagError {
208    #[error("Parsing StructTag: {0}")]
209    FromStr(Box<dyn StdError + Send + Sync + 'static>),
210    #[error("Converting from StructTag: {0}")]
211    StructTag(#[from] StructTagError),
212}
213
214// =============================================================================
215//  Internals
216// =============================================================================
217
218fn type_tag_variant_name(this: &TypeTag) -> String {
219    match this {
220        TypeTag::U8 => "U8",
221        TypeTag::U16 => "U16",
222        TypeTag::U32 => "U32",
223        TypeTag::U64 => "U64",
224        TypeTag::U128 => "U128",
225        TypeTag::U256 => "U256",
226        TypeTag::Bool => "Bool",
227        TypeTag::Address => "Address",
228        TypeTag::Signer => "Signer",
229        TypeTag::Vector(_) => "Vector",
230        TypeTag::Struct(_) => "Struct",
231    }
232    .to_owned()
233}