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