1#![deny(missing_docs)]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11
12mod api;
13pub mod error;
14mod ir;
15
16#[cfg(feature = "web")]
17use getrandom as _;
18
19use api::RuntimeGenerator;
20use proc_macro2::TokenStream as TokenStream2;
21use scale_typegen::typegen::settings::AllocCratePath;
22use scale_typegen::{
23 typegen::settings::substitutes::absolute_path, DerivesRegistry, TypeGeneratorSettings,
24 TypeSubstitutes, TypegenError,
25};
26use std::collections::HashMap;
27use syn::parse_quote;
28
29pub use error::CodegenError;
31pub use subxt_metadata::Metadata;
32pub use syn;
33
34pub struct CodegenBuilder {
56 crate_path: syn::Path,
57 use_default_derives: bool,
58 use_default_substitutions: bool,
59 generate_docs: bool,
60 runtime_types_only: bool,
61 item_mod: syn::ItemMod,
62 extra_global_derives: Vec<syn::Path>,
63 extra_global_attributes: Vec<syn::Attribute>,
64 type_substitutes: HashMap<syn::Path, syn::Path>,
65 derives_for_type: HashMap<syn::TypePath, Vec<syn::Path>>,
66 attributes_for_type: HashMap<syn::TypePath, Vec<syn::Attribute>>,
67 derives_for_type_recursive: HashMap<syn::TypePath, Vec<syn::Path>>,
68 attributes_for_type_recursive: HashMap<syn::TypePath, Vec<syn::Attribute>>,
69}
70
71impl Default for CodegenBuilder {
72 fn default() -> Self {
73 CodegenBuilder {
74 crate_path: syn::parse_quote!(::subxt::ext::subxt_core),
75 use_default_derives: true,
76 use_default_substitutions: true,
77 generate_docs: true,
78 runtime_types_only: false,
79 item_mod: syn::parse_quote!(
80 pub mod api {}
81 ),
82 extra_global_derives: Vec::new(),
83 extra_global_attributes: Vec::new(),
84 type_substitutes: HashMap::new(),
85 derives_for_type: HashMap::new(),
86 attributes_for_type: HashMap::new(),
87 derives_for_type_recursive: HashMap::new(),
88 attributes_for_type_recursive: HashMap::new(),
89 }
90 }
91}
92
93impl CodegenBuilder {
94 pub fn new() -> Self {
96 CodegenBuilder::default()
97 }
98
99 pub fn disable_default_derives(&mut self) {
106 self.use_default_derives = false;
107 }
108
109 pub fn disable_default_substitutes(&mut self) {
117 self.use_default_substitutions = false;
118 }
119
120 pub fn no_docs(&mut self) {
124 self.generate_docs = false;
125 }
126
127 pub fn runtime_types_only(&mut self) {
130 self.runtime_types_only = true;
131 }
132
133 pub fn set_additional_global_derives(&mut self, derives: Vec<syn::Path>) {
143 self.extra_global_derives = derives;
144 }
145
146 pub fn set_additional_global_attributes(&mut self, attributes: Vec<syn::Attribute>) {
153 self.extra_global_attributes = attributes;
154 }
155
156 pub fn add_derives_for_type(
163 &mut self,
164 ty: syn::TypePath,
165 derives: impl IntoIterator<Item = syn::Path>,
166 recursive: bool,
167 ) {
168 if recursive {
169 self.derives_for_type_recursive
170 .entry(ty)
171 .or_default()
172 .extend(derives);
173 } else {
174 self.derives_for_type.entry(ty).or_default().extend(derives);
175 }
176 }
177
178 pub fn add_attributes_for_type(
183 &mut self,
184 ty: syn::TypePath,
185 attributes: impl IntoIterator<Item = syn::Attribute>,
186 recursive: bool,
187 ) {
188 if recursive {
189 self.attributes_for_type_recursive
190 .entry(ty)
191 .or_default()
192 .extend(attributes);
193 } else {
194 self.attributes_for_type
195 .entry(ty)
196 .or_default()
197 .extend(attributes);
198 }
199 }
200
201 pub fn set_type_substitute(&mut self, ty: syn::Path, with: syn::Path) {
208 self.type_substitutes.insert(ty, with);
209 }
210
211 pub fn set_target_module(&mut self, item_mod: syn::ItemMod) {
216 self.item_mod = item_mod;
217 }
218
219 pub fn set_subxt_crate_path(&mut self, crate_path: syn::Path) {
225 if absolute_path(crate_path.clone()).is_err() {
226 panic!("The provided crate path must be an absolute path, ie prefixed with '::' or 'crate'");
229 }
230 self.crate_path = crate_path;
231 }
232
233 pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
237 let crate_path = self.crate_path;
238
239 let mut derives_registry: DerivesRegistry = if self.use_default_derives {
240 default_derives(&crate_path)
241 } else {
242 DerivesRegistry::new()
243 };
244
245 derives_registry.add_derives_for_all(self.extra_global_derives);
246 derives_registry.add_attributes_for_all(self.extra_global_attributes);
247
248 for (ty, derives) in self.derives_for_type {
249 derives_registry.add_derives_for(ty, derives, false);
250 }
251 for (ty, derives) in self.derives_for_type_recursive {
252 derives_registry.add_derives_for(ty, derives, true);
253 }
254 for (ty, attributes) in self.attributes_for_type {
255 derives_registry.add_attributes_for(ty, attributes, false);
256 }
257 for (ty, attributes) in self.attributes_for_type_recursive {
258 derives_registry.add_attributes_for(ty, attributes, true);
259 }
260
261 let mut type_substitutes: TypeSubstitutes = if self.use_default_substitutions {
262 default_substitutes(&crate_path)
263 } else {
264 TypeSubstitutes::new()
265 };
266
267 for (from, with) in self.type_substitutes {
268 let abs_path = absolute_path(with).map_err(TypegenError::from)?;
269 type_substitutes
270 .insert(from, abs_path)
271 .map_err(TypegenError::from)?;
272 }
273
274 let item_mod = self.item_mod;
275 let generator = RuntimeGenerator::new(metadata);
276 let should_gen_docs = self.generate_docs;
277
278 if self.runtime_types_only {
279 generator.generate_runtime_types(
280 item_mod,
281 derives_registry,
282 type_substitutes,
283 crate_path,
284 should_gen_docs,
285 )
286 } else {
287 generator.generate_runtime(
288 item_mod,
289 derives_registry,
290 type_substitutes,
291 crate_path,
292 should_gen_docs,
293 )
294 }
295 }
296}
297
298pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
301 let crate_path: syn::Path = parse_quote!(::subxt::ext::subxt_core);
302 let derives = default_derives(&crate_path);
303 let substitutes = default_substitutes(&crate_path);
304 subxt_type_gen_settings(derives, substitutes, &crate_path, true)
305}
306
307fn subxt_type_gen_settings(
308 derives: scale_typegen::DerivesRegistry,
309 substitutes: scale_typegen::TypeSubstitutes,
310 crate_path: &syn::Path,
311 should_gen_docs: bool,
312) -> TypeGeneratorSettings {
313 TypeGeneratorSettings {
314 types_mod_ident: parse_quote!(runtime_types),
315 should_gen_docs,
316 derives,
317 substitutes,
318 decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
319 compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
320 compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
321 insert_codec_attributes: true,
322 alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
323 }
324}
325
326fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
327 let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
328 let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
329
330 let derives: [syn::Path; 5] = [
331 parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
332 parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
333 parse_quote!(#crate_path::ext::codec::Encode),
334 parse_quote!(#crate_path::ext::codec::Decode),
335 parse_quote!(Debug),
336 ];
337
338 let attributes: [syn::Attribute; 4] = [
339 parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
340 parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
341 parse_quote!(#[codec(crate = #crate_path::ext::codec)]),
342 parse_quote!(#[codec(dumb_trait_bound)]),
343 ];
344
345 let mut derives_registry = DerivesRegistry::new();
346 derives_registry.add_derives_for_all(derives);
347 derives_registry.add_attributes_for_all(attributes);
348 derives_registry
349}
350
351fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
352 let mut type_substitutes = TypeSubstitutes::new();
353
354 let defaults: [(syn::Path, syn::Path); 13] = [
355 (
356 parse_quote!(bitvec::order::Lsb0),
357 parse_quote!(#crate_path::utils::bits::Lsb0),
358 ),
359 (
360 parse_quote!(bitvec::order::Msb0),
361 parse_quote!(#crate_path::utils::bits::Msb0),
362 ),
363 (
364 parse_quote!(sp_core::crypto::AccountId32),
365 parse_quote!(#crate_path::utils::AccountId32),
366 ),
367 (
368 parse_quote!(fp_account::AccountId20),
369 parse_quote!(#crate_path::utils::AccountId20),
370 ),
371 (
372 parse_quote!(sp_runtime::multiaddress::MultiAddress),
373 parse_quote!(#crate_path::utils::MultiAddress),
374 ),
375 (
376 parse_quote!(primitive_types::H160),
377 parse_quote!(#crate_path::utils::H160),
378 ),
379 (
380 parse_quote!(primitive_types::H256),
381 parse_quote!(#crate_path::utils::H256),
382 ),
383 (
384 parse_quote!(primitive_types::H512),
385 parse_quote!(#crate_path::utils::H512),
386 ),
387 (
388 parse_quote!(frame_support::traits::misc::WrapperKeepOpaque),
389 parse_quote!(#crate_path::utils::WrapperKeepOpaque),
390 ),
391 (
396 parse_quote!(BTreeMap),
397 parse_quote!(#crate_path::utils::KeyedVec),
398 ),
399 (
400 parse_quote!(BinaryHeap),
401 parse_quote!(#crate_path::alloc::vec::Vec),
402 ),
403 (
404 parse_quote!(BTreeSet),
405 parse_quote!(#crate_path::alloc::vec::Vec),
406 ),
407 (
414 parse_quote!(sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic),
415 parse_quote!(#crate_path::utils::UncheckedExtrinsic),
416 ),
417 ];
418
419 let defaults = defaults.into_iter().map(|(from, to)| {
420 (
421 from,
422 absolute_path(to).expect("default substitutes above are absolute paths; qed"),
423 )
424 });
425 type_substitutes
426 .extend(defaults)
427 .expect("default substitutes can always be parsed; qed");
428 type_substitutes
429}