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 DerivesRegistry, TypeGeneratorSettings, TypeSubstitutes, TypegenError,
24 typegen::settings::substitutes::absolute_path,
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!(
229 "The provided crate path must be an absolute path, ie prefixed with '::' or 'crate'"
230 );
231 }
232 self.crate_path = crate_path;
233 }
234
235 pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
239 let crate_path = self.crate_path;
240
241 let mut derives_registry: DerivesRegistry = if self.use_default_derives {
242 default_derives(&crate_path)
243 } else {
244 DerivesRegistry::new()
245 };
246
247 derives_registry.add_derives_for_all(self.extra_global_derives);
248 derives_registry.add_attributes_for_all(self.extra_global_attributes);
249
250 for (ty, derives) in self.derives_for_type {
251 derives_registry.add_derives_for(ty, derives, false);
252 }
253 for (ty, derives) in self.derives_for_type_recursive {
254 derives_registry.add_derives_for(ty, derives, true);
255 }
256 for (ty, attributes) in self.attributes_for_type {
257 derives_registry.add_attributes_for(ty, attributes, false);
258 }
259 for (ty, attributes) in self.attributes_for_type_recursive {
260 derives_registry.add_attributes_for(ty, attributes, true);
261 }
262
263 let mut type_substitutes: TypeSubstitutes = if self.use_default_substitutions {
264 default_substitutes(&crate_path)
265 } else {
266 TypeSubstitutes::new()
267 };
268
269 for (from, with) in self.type_substitutes {
270 let abs_path = absolute_path(with).map_err(TypegenError::from)?;
271 type_substitutes
272 .insert(from, abs_path)
273 .map_err(TypegenError::from)?;
274 }
275
276 let item_mod = self.item_mod;
277 let generator = RuntimeGenerator::new(metadata);
278 let should_gen_docs = self.generate_docs;
279
280 if self.runtime_types_only {
281 generator.generate_runtime_types(
282 item_mod,
283 derives_registry,
284 type_substitutes,
285 crate_path,
286 should_gen_docs,
287 )
288 } else {
289 generator.generate_runtime(
290 item_mod,
291 derives_registry,
292 type_substitutes,
293 crate_path,
294 should_gen_docs,
295 )
296 }
297 }
298}
299
300pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
303 let crate_path: syn::Path = parse_quote!(::subxt::ext::subxt_core);
304 let derives = default_derives(&crate_path);
305 let substitutes = default_substitutes(&crate_path);
306 subxt_type_gen_settings(derives, substitutes, &crate_path, true)
307}
308
309fn subxt_type_gen_settings(
310 derives: scale_typegen::DerivesRegistry,
311 substitutes: scale_typegen::TypeSubstitutes,
312 crate_path: &syn::Path,
313 should_gen_docs: bool,
314) -> TypeGeneratorSettings {
315 let are_codec_derives_used = derives.default_derives().derives().iter().any(|path| {
317 let mut segments_backwards = path.segments.iter().rev();
318 let ident = segments_backwards.next();
319 let module = segments_backwards.next();
320
321 let is_ident_match = ident.is_some_and(|s| s.ident == "Encode" || s.ident == "Decode");
322 let is_module_match = module.is_some_and(|s| s.ident == "codec");
323
324 is_ident_match && is_module_match
325 });
326
327 let compact_as_type_path =
329 are_codec_derives_used.then(|| parse_quote!(#crate_path::ext::codec::CompactAs));
330
331 TypeGeneratorSettings {
332 types_mod_ident: parse_quote!(runtime_types),
333 should_gen_docs,
334 derives,
335 substitutes,
336 decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
337 compact_as_type_path,
338 compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
339 alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
340 insert_codec_attributes: true,
343 }
344}
345
346fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
347 let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
348 let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
349
350 let derives: [syn::Path; 3] = [
351 parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
352 parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
353 parse_quote!(Debug),
354 ];
355
356 let attributes: [syn::Attribute; 2] = [
357 parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
358 parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
359 ];
360
361 let mut derives_registry = DerivesRegistry::new();
362 derives_registry.add_derives_for_all(derives);
363 derives_registry.add_attributes_for_all(attributes);
364 derives_registry
365}
366
367fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
368 let mut type_substitutes = TypeSubstitutes::new();
369
370 let defaults: [(syn::Path, syn::Path); 13] = [
371 (
372 parse_quote!(bitvec::order::Lsb0),
373 parse_quote!(#crate_path::utils::bits::Lsb0),
374 ),
375 (
376 parse_quote!(bitvec::order::Msb0),
377 parse_quote!(#crate_path::utils::bits::Msb0),
378 ),
379 (
380 parse_quote!(sp_core::crypto::AccountId32),
381 parse_quote!(#crate_path::utils::AccountId32),
382 ),
383 (
384 parse_quote!(fp_account::AccountId20),
385 parse_quote!(#crate_path::utils::AccountId20),
386 ),
387 (
388 parse_quote!(sp_runtime::multiaddress::MultiAddress),
389 parse_quote!(#crate_path::utils::MultiAddress),
390 ),
391 (
392 parse_quote!(primitive_types::H160),
393 parse_quote!(#crate_path::utils::H160),
394 ),
395 (
396 parse_quote!(primitive_types::H256),
397 parse_quote!(#crate_path::utils::H256),
398 ),
399 (
400 parse_quote!(primitive_types::H512),
401 parse_quote!(#crate_path::utils::H512),
402 ),
403 (
404 parse_quote!(frame_support::traits::misc::WrapperKeepOpaque),
405 parse_quote!(#crate_path::utils::WrapperKeepOpaque),
406 ),
407 (
412 parse_quote!(BTreeMap),
413 parse_quote!(#crate_path::utils::KeyedVec),
414 ),
415 (
416 parse_quote!(BinaryHeap),
417 parse_quote!(#crate_path::alloc::vec::Vec),
418 ),
419 (
420 parse_quote!(BTreeSet),
421 parse_quote!(#crate_path::alloc::vec::Vec),
422 ),
423 (
430 parse_quote!(sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic),
431 parse_quote!(#crate_path::utils::UncheckedExtrinsic),
432 ),
433 ];
434
435 let defaults = defaults.into_iter().map(|(from, to)| {
436 (
437 from,
438 absolute_path(to).expect("default substitutes above are absolute paths; qed"),
439 )
440 });
441 type_substitutes
442 .extend(defaults)
443 .expect("default substitutes can always be parsed; qed");
444 type_substitutes
445}