moverox_traits_derive/lib.rs
1#![cfg_attr(nightly, feature(doc_cfg))]
2
3//! Derive macros for `moverox-traits`.
4
5use proc_macro2::TokenStream;
6use quote::quote;
7
8use crate::datatype::Datatype;
9
10mod attributes;
11mod datatype;
12mod type_tag;
13
14/// Derives `moverox_traits` trait implementations for an oxidized Move datatype.
15///
16/// Creates the `_TypeTag` struct related to the type being annotated, with conversion traits
17/// between the former and the generic `StructTag` type, with errors like 'expected module to be x'
18/// or 'expected struct name to be y', if we know those things at compile time (see the
19/// [Attributes](#attributes) section for configurations around those checks).
20///
21/// # Attributes
22///
23/// - `#[move_(crate = ...)]`: sets the path of the `moverox_traits` crate, which can be useful if
24/// using this inside other macros.
25/// - `#[move_(address = "...")]`: sets a static package address for the generated type tag.
26/// Deserialization of the latter will fail if the package addresses do not match.
27/// - `#[move_(module = "...")]`: sets a static module name for the generated type tag.
28/// Deserialization of the latter will fail if the module names do not match.
29/// - `#[move_(nameless)]`: make the datatype name dynamic for the generated type tag. Upon the
30/// deserializing the latter, any Move datatype name will be accepted. Otherwise, deserialization
31/// will fail if the incoming datatype name is not equal to the Rust type's name.
32///
33/// # Type tag derivation
34///
35/// For a struct `Name<T: MoveType>`, the macro will create a `NameTypeTag` struct with fields:
36/// - `address: Address`, unless the `#[move_(address = "...")]` attribute is present
37/// - `module: Identifier`, unless the `#[move_(module = "...")]` attribute is present
38/// - `name: Identifier` only if the `#[move_(nameless)]` attribute is present
39/// - `type_t: <T as MoveType>::TypeTag`
40///
41/// The macro will also create custom `Into<StructTag>`, `Into<TypeTag>`, `TryFrom<&StructTag>`,
42/// `TryFrom<StructTag>`, `TryFrom<&TypeTag>`, `TryFrom<TypeTag>`, `Display` and `FromStr` impls for
43/// `NameTypeTag`.
44///
45/// # Derived traits
46///
47/// For the annotated type:
48/// - `moverox_traits::MoveDatatype`
49///
50/// For the generated `_TypeTag` struct:
51/// - `moverox_traits::ConstAddress` if `#[move_(address = "...")]` is specified
52/// - `moverox_traits::ConstModule` if `#[move_(module = "...")]` is specified
53/// - `moverox_traits::ConstName` if `#[move_(nameless)]` was **not** specified
54#[proc_macro_derive(MoveDatatype, attributes(move_))]
55pub fn move_datatype_derive_macro(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
56 impl_move_datatype(item.into())
57 .unwrap_or_else(syn::Error::into_compile_error)
58 .into()
59}
60
61fn impl_move_datatype(item: TokenStream) -> syn::Result<TokenStream> {
62 let datatype = Datatype::parse(item)?;
63
64 let type_tag_decl = datatype.type_tag.struct_declaration();
65 let type_tag_impl_move_datatype_tag = datatype.type_tag.impl_move_datatype_tag();
66 let type_tag_deserialize = datatype.type_tag.impl_deserialize();
67 let type_tag_serialize = datatype.type_tag.impl_serialize();
68 let type_tag_impl_const_address = datatype.type_tag.impl_const_address();
69 let type_tag_impl_const_module = datatype.type_tag.impl_const_module();
70 let type_tag_impl_const_name = datatype.type_tag.impl_const_name();
71 let type_tag_impl_from_str = datatype.type_tag.impl_from_str();
72 let type_tag_impl_display = datatype.type_tag.impl_display();
73
74 let impl_move_datatype = datatype.impl_move_datatype();
75 let impl_type_tag_constructor = datatype.impl_type_tag_constructor();
76 let impl_const_struct_tag = datatype.impl_const_struct_tag().unwrap_or_default();
77
78 Ok(quote! {
79 #type_tag_decl
80 #type_tag_impl_move_datatype_tag
81 #type_tag_deserialize
82 #type_tag_serialize
83 #type_tag_impl_const_address
84 #type_tag_impl_const_module
85 #type_tag_impl_const_name
86 #type_tag_impl_from_str
87 #type_tag_impl_display
88
89 #impl_move_datatype
90 #impl_type_tag_constructor
91 #impl_const_struct_tag
92 })
93}