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