scrypto_bindgen/
ast.rs

1use proc_macro2::*;
2use quote::*;
3use radix_common::prelude::*;
4
5use crate::token_stream_from_str;
6
7pub struct PackageStub {
8    pub blueprints: Vec<BlueprintStub>,
9    pub auxiliary_types: Vec<AuxiliaryType>,
10}
11
12impl ToTokens for PackageStub {
13    fn to_tokens(&self, tokens: &mut TokenStream) {
14        let blueprints = &self.blueprints;
15        let auxiliary_types = &self.auxiliary_types;
16        quote! {
17            #(#blueprints)*
18            #(#auxiliary_types)*
19        }
20        .to_tokens(tokens)
21    }
22}
23
24/// Objects of this struct are generated as part of the generation process. This struct can then be
25/// used inside the quote macro and printed out.
26pub struct BlueprintStub {
27    pub blueprint_name: String,
28    pub fn_signatures: Vec<FnSignature>,
29    pub package_address: PackageAddress,
30}
31
32impl ToTokens for BlueprintStub {
33    fn to_tokens(&self, tokens: &mut TokenStream) {
34        let package_address_bytes = self.package_address.to_vec();
35        let blueprint_name = self.blueprint_name.clone();
36        let owned_blueprint_name = format!("Owned{}", self.blueprint_name);
37        let global_blueprint_name = format!("Global{}", self.blueprint_name);
38
39        let blueprint_name_ident = Ident::new(&self.blueprint_name, Span::call_site());
40        let blueprint_functions_name_ident = Ident::new(
41            format!("{}Functions", &self.blueprint_name).as_str(),
42            Span::call_site(),
43        );
44
45        let functions = self
46            .fn_signatures
47            .iter()
48            .filter(|func| matches!(func.fn_type, FnType::Function))
49            .collect::<Vec<_>>();
50        let methods = self
51            .fn_signatures
52            .iter()
53            .filter(|func| matches!(func.fn_type, FnType::Method { .. }))
54            .collect::<Vec<_>>();
55
56        quote! {
57            extern_blueprint_internal! {
58                PackageAddress::new_or_panic([ #(#package_address_bytes),* ]),
59                #blueprint_name_ident,
60                #blueprint_name,
61                #owned_blueprint_name,
62                #global_blueprint_name,
63                #blueprint_functions_name_ident
64                {
65                    #(#functions;)*
66                },
67                {
68                    #(#methods;)*
69                }
70            }
71        }
72        .to_tokens(tokens)
73    }
74}
75
76pub struct FnSignature {
77    pub ident: syn::Ident,
78    pub inputs: Vec<(syn::Ident, TokenStream)>,
79    pub output: TokenStream,
80    pub fn_type: FnType,
81}
82
83pub enum FnType {
84    Function,
85    Method { is_mutable_receiver: bool },
86}
87
88impl ToTokens for FnSignature {
89    fn to_tokens(&self, tokens: &mut TokenStream) {
90        let ident = &self.ident;
91        let input_names = &self.inputs.iter().map(|(k, _)| k).collect::<Vec<_>>();
92        let input_types = &self.inputs.iter().map(|(_, v)| v).collect::<Vec<_>>();
93        let output = &self.output;
94
95        let sep = if self.inputs.is_empty() {
96            quote! {}
97        } else {
98            quote! {,}
99        };
100
101        match self.fn_type {
102            FnType::Function => quote! {
103                fn #ident( #( #input_names: #input_types ),* ) -> #output
104            }
105            .to_tokens(tokens),
106            FnType::Method {
107                is_mutable_receiver: true,
108            } => quote! {
109                fn #ident( &mut self #sep #( #input_names: #input_types ),* ) -> #output
110            }
111            .to_tokens(tokens),
112            FnType::Method {
113                is_mutable_receiver: false,
114            } => quote! {
115                fn #ident( &self #sep #( #input_names: #input_types ),* ) -> #output
116            }
117            .to_tokens(tokens),
118        }
119    }
120}
121
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub enum AuxiliaryType {
124    TupleStruct {
125        struct_name: String,
126        field_types: Vec<String>,
127    },
128    NamedFieldsStruct {
129        struct_name: String,
130        fields: IndexMap<String, String>,
131    },
132    Enum {
133        enum_name: String,
134        variants: Vec<EnumVariant>,
135    },
136}
137
138impl ToTokens for AuxiliaryType {
139    fn to_tokens(&self, tokens: &mut TokenStream) {
140        match self {
141            Self::TupleStruct {
142                struct_name,
143                field_types,
144            } => {
145                let struct_name = token_stream_from_str!(struct_name);
146                let field_types = field_types
147                    .iter()
148                    .map(|string| token_stream_from_str!(string));
149
150                quote! {
151                    #[derive(::scrypto::prelude::ScryptoSbor)]
152                    pub struct #struct_name(
153                        #(
154                            #field_types
155                        ),*
156                    );
157                }
158                .to_tokens(tokens)
159            }
160            Self::NamedFieldsStruct {
161                struct_name,
162                fields,
163            } => {
164                let struct_name = token_stream_from_str!(struct_name);
165                let field_names = fields.keys().map(|string| token_stream_from_str!(string));
166                let field_types = fields.values().map(|string| token_stream_from_str!(string));
167
168                quote! {
169                    #[derive(::scrypto::prelude::ScryptoSbor)]
170                    pub struct #struct_name {
171                        #(
172                            #field_names: #field_types
173                        ),*
174                    }
175                }
176                .to_tokens(tokens)
177            }
178            Self::Enum {
179                enum_name,
180                variants,
181            } => {
182                let enum_name = token_stream_from_str!(enum_name);
183
184                quote! {
185                    #[derive(::scrypto::prelude::ScryptoSbor)]
186                    pub enum #enum_name {
187                        #(
188                            #variants
189                        ),*
190                    }
191                }
192                .to_tokens(tokens)
193            }
194        }
195    }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq)]
199pub enum EnumVariant {
200    Unit {
201        variant_name: String,
202        variant_index: u8,
203    },
204    Tuple {
205        variant_name: String,
206        variant_index: u8,
207        field_types: Vec<String>,
208    },
209    NamedFields {
210        variant_name: String,
211        variant_index: u8,
212        fields: IndexMap<String, String>,
213    },
214}
215
216impl ToTokens for EnumVariant {
217    fn to_tokens(&self, tokens: &mut TokenStream) {
218        match self {
219            Self::Unit {
220                variant_name,
221                variant_index,
222            } => {
223                let variant_name = token_stream_from_str!(variant_name);
224                quote! {
225                    #[sbor(discriminator( #variant_index ))]
226                    #variant_name
227                }
228                .to_tokens(tokens)
229            }
230            Self::Tuple {
231                variant_name,
232                variant_index,
233                field_types,
234            } => {
235                let variant_name = token_stream_from_str!(variant_name);
236                let field_types = field_types
237                    .iter()
238                    .map(|string| token_stream_from_str!(string));
239                quote! {
240                    #[sbor(discriminator( #variant_index ))]
241                    #variant_name (
242                        #(
243                            #field_types
244                        ),*
245                    )
246                }
247                .to_tokens(tokens)
248            }
249            Self::NamedFields {
250                variant_name,
251                variant_index,
252                fields,
253            } => {
254                let variant_name = token_stream_from_str!(variant_name);
255                let field_names = fields.keys().map(|string| token_stream_from_str!(string));
256                let field_types = fields.values().map(|string| token_stream_from_str!(string));
257
258                quote! {
259                    #[sbor(discriminator( #variant_index ))]
260                    #variant_name {
261                        #(
262                            #field_names: #field_types
263                        ),*
264                    }
265                }
266                .to_tokens(tokens)
267            }
268        }
269    }
270}