1#![cfg_attr(nightly, feature(doc_cfg))]
2
3use std::collections::HashMap;
13
14use move_syn::{Attributes, Item, Module};
15use proc_macro2::{Ident, TokenStream};
16use quote::quote;
17use unsynn::LiteralString;
18
19mod attributes;
20mod generics;
21mod move_enum;
22mod move_struct;
23mod move_type;
24mod named_fields;
25mod positional_fields;
26#[cfg(test)]
27mod tests;
28
29use self::move_struct::StructGen as _;
30
31type BoxError = Box<dyn std::error::Error + 'static>;
32type Result<T = (), E = BoxError> = std::result::Result<T, E>;
33
34#[sealed::sealed]
35pub trait ModuleGen {
36 fn to_rust(
37 &self,
38 thecrate: &TokenStream,
39 package: Option<&LiteralString>,
40 address_map: &HashMap<Ident, TokenStream>,
41 ) -> Result<TokenStream>;
42}
43
44#[sealed::sealed]
45impl ModuleGen for Module {
46 fn to_rust(
47 &self,
48 thecrate: &TokenStream,
49 package: Option<&LiteralString>,
50 address_map: &HashMap<Ident, TokenStream>,
51 ) -> Result<TokenStream> {
52 let (docs, other) = crate::attributes::extract(&self.attrs)
53 .map_err(|err| format!("Parsing `moverox` attributes: {err}"))?;
54
55 if !other.is_empty() {
56 return Err("Move modules cannot have custom `moverox` attributes".into());
57 }
58
59 let ident = &self.ident;
60 let item_ctx = ItemContext {
61 thecrate,
62 package,
63 module: Some(ident),
64 address_map,
65 };
66 let datatypes: TokenStream = self
67 .items()
68 .map(|item| item.to_rust(item_ctx))
69 .collect::<Result<_>>()?;
70
71 Ok(quote! {
72 #docs
73 #[allow(rustdoc::all)]
74 pub mod #ident {
75 #[allow(non_camel_case_types, unused)]
76 type address = #thecrate::types::Address;
77 #[allow(non_camel_case_types, unused)]
78 type u256 = #thecrate::types::U256;
79 #[allow(non_camel_case_types, unused)]
80 type vector<T> = ::std::vec::Vec<T>;
81
82 #datatypes
83 }
84 })
85 }
86}
87
88#[derive(Clone, Copy)]
90pub struct ItemContext<'a> {
91 pub thecrate: &'a TokenStream,
97 pub package: Option<&'a LiteralString>,
99 pub module: Option<&'a Ident>,
101 pub address_map: &'a HashMap<Ident, TokenStream>,
105}
106
107#[sealed::sealed]
108pub trait ItemGen {
109 fn to_rust(&self, ctx: ItemContext<'_>) -> Result<TokenStream>;
110}
111
112#[sealed::sealed]
113impl ItemGen for Item {
114 fn to_rust(&self, ctx: ItemContext<'_>) -> Result<TokenStream> {
115 use move_syn::ItemKind as K;
116 let Self { attrs, kind, .. } = self;
117
118 let (docs, generated) = match kind {
119 K::Struct(s) => {
120 let err_ctx = |err| format!("struct {}: {err}", s.ident);
121 let (docs, otw_types) = crate::attributes::extract(attrs).map_err(err_ctx)?;
122 let generated = s.to_rust(otw_types, ctx).map_err(err_ctx)?;
123 (docs, generated)
124 }
125 K::Enum(e) => {
126 let err_ctx = |err| format!("enum {}: {err}", e.ident);
127 let (docs, otw_types) = crate::attributes::extract(attrs).map_err(err_ctx)?;
128 let generated = self::move_enum::to_rust(e, otw_types, ctx).map_err(err_ctx)?;
129 (docs, generated)
130 }
131 _ => return non_datatype_gen(attrs),
132 };
133
134 Ok(quote! {
135 #docs
136 #generated
137 })
138 }
139}
140
141fn non_datatype_gen(attrs: &[Attributes]) -> Result<TokenStream> {
142 if attrs.iter().flat_map(self::attributes::as_moverox).count() > 0 {
143 return Err(
144 "Move items other than enums/structs cannot be annotated with custom \
145 `moverox` attributes"
146 .into(),
147 );
148 }
149 Ok(TokenStream::new())
150}