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::{
22 typegen::settings::{substitutes::absolute_path, AllocCratePath},
23 DerivesRegistry, TypeGeneratorSettings, TypeSubstitutes, TypegenError,
24};
25use std::collections::HashMap;
26use syn::parse_quote;
27
28pub use error::CodegenError;
30pub use pezkuwi_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!(::pezkuwi_subxt::ext::pezkuwi_subxt_core),
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.entry(ty).or_default().extend(derives);
169 } else {
170 self.derives_for_type.entry(ty).or_default().extend(derives);
171 }
172 }
173
174 pub fn add_attributes_for_type(
179 &mut self,
180 ty: syn::TypePath,
181 attributes: impl IntoIterator<Item = syn::Attribute>,
182 recursive: bool,
183 ) {
184 if recursive {
185 self.attributes_for_type_recursive.entry(ty).or_default().extend(attributes);
186 } else {
187 self.attributes_for_type.entry(ty).or_default().extend(attributes);
188 }
189 }
190
191 pub fn set_type_substitute(&mut self, ty: syn::Path, with: syn::Path) {
198 self.type_substitutes.insert(ty, with);
199 }
200
201 pub fn set_target_module(&mut self, item_mod: syn::ItemMod) {
206 self.item_mod = item_mod;
207 }
208
209 pub fn set_subxt_crate_path(&mut self, crate_path: syn::Path) {
216 if absolute_path(crate_path.clone()).is_err() {
217 panic!(
220 "The provided crate path must be an absolute path, ie prefixed with '::' or 'crate'"
221 );
222 }
223 self.crate_path = crate_path;
224 }
225
226 pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
230 let crate_path = self.crate_path;
231
232 let mut derives_registry: DerivesRegistry = if self.use_default_derives {
233 default_derives(&crate_path)
234 } else {
235 DerivesRegistry::new()
236 };
237
238 derives_registry.add_derives_for_all(self.extra_global_derives);
239 derives_registry.add_attributes_for_all(self.extra_global_attributes);
240
241 for (ty, derives) in self.derives_for_type {
242 derives_registry.add_derives_for(ty, derives, false);
243 }
244 for (ty, derives) in self.derives_for_type_recursive {
245 derives_registry.add_derives_for(ty, derives, true);
246 }
247 for (ty, attributes) in self.attributes_for_type {
248 derives_registry.add_attributes_for(ty, attributes, false);
249 }
250 for (ty, attributes) in self.attributes_for_type_recursive {
251 derives_registry.add_attributes_for(ty, attributes, true);
252 }
253
254 let mut type_substitutes: TypeSubstitutes = if self.use_default_substitutions {
255 default_substitutes(&crate_path)
256 } else {
257 TypeSubstitutes::new()
258 };
259
260 for (from, with) in self.type_substitutes {
261 let abs_path = absolute_path(with).map_err(TypegenError::from)?;
262 type_substitutes.insert(from, abs_path).map_err(TypegenError::from)?;
263 }
264
265 let item_mod = self.item_mod;
266 let generator = RuntimeGenerator::new(metadata);
267 let should_gen_docs = self.generate_docs;
268
269 if self.runtime_types_only {
270 generator.generate_runtime_types(
271 item_mod,
272 derives_registry,
273 type_substitutes,
274 crate_path,
275 should_gen_docs,
276 )
277 } else {
278 generator.generate_runtime(
279 item_mod,
280 derives_registry,
281 type_substitutes,
282 crate_path,
283 should_gen_docs,
284 )
285 }
286 }
287}
288
289pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
292 let crate_path: syn::Path = parse_quote!(::pezkuwi_subxt::ext::pezkuwi_subxt_core);
293 let derives = default_derives(&crate_path);
294 let substitutes = default_substitutes(&crate_path);
295 subxt_type_gen_settings(derives, substitutes, &crate_path, true)
296}
297
298fn subxt_type_gen_settings(
299 derives: scale_typegen::DerivesRegistry,
300 substitutes: scale_typegen::TypeSubstitutes,
301 crate_path: &syn::Path,
302 should_gen_docs: bool,
303) -> TypeGeneratorSettings {
304 let are_codec_derives_used = derives.default_derives().derives().iter().any(|path| {
306 let mut segments_backwards = path.segments.iter().rev();
307 let ident = segments_backwards.next();
308 let module = segments_backwards.next();
309
310 let is_ident_match = ident.is_some_and(|s| s.ident == "Encode" || s.ident == "Decode");
311 let is_module_match = module.is_some_and(|s| s.ident == "codec");
312
313 is_ident_match && is_module_match
314 });
315
316 let compact_as_type_path =
318 are_codec_derives_used.then(|| parse_quote!(#crate_path::ext::codec::CompactAs));
319
320 TypeGeneratorSettings {
321 types_mod_ident: parse_quote!(runtime_types),
322 should_gen_docs,
323 derives,
324 substitutes,
325 decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
326 compact_as_type_path,
327 compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
328 alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
329 insert_codec_attributes: true,
333 }
334}
335
336fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
337 let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
338 let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
339
340 let derives: [syn::Path; 3] = [
341 parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
342 parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
343 parse_quote!(Debug),
344 ];
345
346 let attributes: [syn::Attribute; 2] = [
347 parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
348 parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
349 ];
350
351 let mut derives_registry = DerivesRegistry::new();
352 derives_registry.add_derives_for_all(derives);
353 derives_registry.add_attributes_for_all(attributes);
354 derives_registry
355}
356
357fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
358 let mut type_substitutes = TypeSubstitutes::new();
359
360 let defaults: [(syn::Path, syn::Path); 13] = [
361 (parse_quote!(bitvec::order::Lsb0), parse_quote!(#crate_path::utils::bits::Lsb0)),
362 (parse_quote!(bitvec::order::Msb0), parse_quote!(#crate_path::utils::bits::Msb0)),
363 (
364 parse_quote!(pezsp_core::crypto::AccountId32),
365 parse_quote!(#crate_path::utils::AccountId32),
366 ),
367 (parse_quote!(fp_account::AccountId20), parse_quote!(#crate_path::utils::AccountId20)),
368 (
369 parse_quote!(pezsp_runtime::multiaddress::MultiAddress),
370 parse_quote!(#crate_path::utils::MultiAddress),
371 ),
372 (parse_quote!(primitive_types::H160), parse_quote!(#crate_path::utils::H160)),
373 (parse_quote!(primitive_types::H256), parse_quote!(#crate_path::utils::H256)),
374 (parse_quote!(primitive_types::H512), parse_quote!(#crate_path::utils::H512)),
375 (
376 parse_quote!(pezframe_support::traits::misc::WrapperKeepOpaque),
377 parse_quote!(#crate_path::utils::WrapperKeepOpaque),
378 ),
379 (parse_quote!(BTreeMap), parse_quote!(#crate_path::utils::KeyedVec)),
384 (parse_quote!(BinaryHeap), parse_quote!(#crate_path::alloc::vec::Vec)),
385 (parse_quote!(BTreeSet), parse_quote!(#crate_path::alloc::vec::Vec)),
386 (
394 parse_quote!(pezsp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic),
395 parse_quote!(#crate_path::utils::UncheckedExtrinsic),
396 ),
397 ];
398
399 let defaults = defaults.into_iter().map(|(from, to)| {
400 (from, absolute_path(to).expect("default substitutes above are absolute paths; qed"))
401 });
402 type_substitutes
403 .extend(defaults)
404 .expect("default substitutes can always be parsed; qed");
405 type_substitutes
406}