moverox_codegen/move_struct/
mod.rs1use std::collections::HashMap;
2
3use proc_macro2::{Ident, TokenStream};
4use quote::quote;
5use unsynn::LiteralString;
6
7mod braced;
8mod tuple;
9
10use braced::BracedStructExt as _;
11use tuple::TupleStructExt as _;
12
13use crate::generics::GenericsExt;
14
15pub(super) trait StructGen {
16 fn to_rust(
19 &self,
20 thecrate: &TokenStream,
21 package: Option<&LiteralString>,
22 module: Option<&Ident>,
23 address_map: &HashMap<Ident, TokenStream>,
24 ) -> TokenStream;
25}
26
27impl StructGen for move_syn::Struct {
28 fn to_rust(
29 &self,
30 thecrate: &TokenStream,
31 package: Option<&LiteralString>,
32 module: Option<&Ident>,
33 address_map: &HashMap<Ident, TokenStream>,
34 ) -> TokenStream {
35 let decl = self.rust_declaration(thecrate, package, module, address_map);
36 let impl_new = self.impl_new(address_map);
37 let impl_has_key_maybe = self.impl_has_key(thecrate).unwrap_or_default();
38 quote! {
39 #decl
40 #impl_new
41 #impl_has_key_maybe
42 }
43 }
44}
45
46trait StructExt {
47 fn rust_declaration(
48 &self,
49 thecrate: &TokenStream,
50 package: Option<&LiteralString>,
51 module: Option<&Ident>,
52 address_map: &HashMap<Ident, TokenStream>,
53 ) -> TokenStream;
54
55 fn impl_new(&self, address_map: &HashMap<Ident, TokenStream>) -> TokenStream;
57
58 fn impl_has_key(&self, thecrate: &TokenStream) -> Option<TokenStream>;
61
62 fn extra_derives(&self) -> Option<TokenStream>;
67
68 fn type_generics(&self) -> TokenStream;
72
73 fn phantom_types(&self) -> impl Iterator<Item = &Ident>;
75}
76
77impl StructExt for move_syn::Struct {
78 fn rust_declaration(
79 &self,
80 thecrate: &TokenStream,
81 package: Option<&LiteralString>,
82 module: Option<&Ident>,
83 address_map: &HashMap<Ident, TokenStream>,
84 ) -> TokenStream {
85 use move_syn::StructKind as K;
86 let Self { ident, kind, .. } = self;
87
88 let extra_attrs: TokenStream = package
89 .into_iter()
90 .map(unsynn::ToTokens::to_token_stream)
91 .map(|addr| quote!(#[move_(address = #addr)]))
92 .chain(module.map(|ident| quote!(#[move_(module = #ident)])))
93 .collect();
94 let extra_derives = self.extra_derives().unwrap_or_default();
95 let generics = self.type_generics();
96 let contents = match kind {
97 K::Braced(braced) => braced.to_rust_contents(self.phantom_types(), address_map),
98 K::Tuple(tuple) => tuple.to_rust_contents(self.phantom_types(), address_map),
99 };
100 let serde_crate = format!("{thecrate}::serde").replace(" ", "");
103 quote! {
104 #[derive(
105 #extra_derives
106 Clone,
107 Debug,
108 PartialEq,
109 Eq,
110 Hash,
111 #thecrate::traits::MoveDatatype,
112 #thecrate::serde::Deserialize,
113 #thecrate::serde::Serialize,
114 )]
115 #[move_(crate = #thecrate::traits)]
116 #[serde(crate = #serde_crate)]
117 #extra_attrs
118 #[allow(non_snake_case)]
119 pub struct #ident #generics #contents
120 }
121 }
122
123 fn impl_new(&self, address_map: &HashMap<Ident, TokenStream>) -> TokenStream {
124 use move_syn::StructKind;
125 let Self { ident, kind, .. } = self;
126 let generics = self.type_generics();
127 let (args, assignments) = match kind {
128 StructKind::Braced(braced) => braced.impl_new(self.phantom_types(), address_map),
129 StructKind::Tuple(tuple) => tuple.impl_new(self.phantom_types(), address_map),
130 };
131 quote! {
132 impl #generics #ident #generics {
133 #[allow(clippy::just_underscores_and_digits, clippy::too_many_arguments)]
134 pub const fn new(#args) -> Self {
135 Self #assignments
136 }
137 }
138 }
139 }
140
141 fn impl_has_key(&self, thecrate: &TokenStream) -> Option<TokenStream> {
152 use move_syn::Ability;
153 if !self.abilities().any(|a| matches!(a, Ability::Key(_))) {
154 return None;
155 }
156 let ident = &self.ident;
157 let generics = self.type_generics();
158 Some(quote! {
159 impl #generics #thecrate::traits::HasKey for #ident #generics {
160 fn address(&self) -> #thecrate::types::Address {
161 self.id.id.bytes
162 }
163 }
164 })
165 }
166
167 fn extra_derives(&self) -> Option<TokenStream> {
168 use move_syn::StructKind;
169 let is_empty = match &self.kind {
170 StructKind::Braced(braced) => braced.is_empty(),
171 StructKind::Tuple(tuple) => tuple.is_empty(),
172 };
173 is_empty.then_some(quote!(Default,))
174 }
175
176 fn type_generics(&self) -> TokenStream {
177 self.generics
178 .as_ref()
179 .map(GenericsExt::to_rust)
180 .unwrap_or_default()
181 }
182
183 fn phantom_types(&self) -> impl Iterator<Item = &Ident> {
184 self.generics
185 .as_ref()
186 .into_iter()
187 .flat_map(GenericsExt::phantoms)
188 }
189}