// Copyright 2019-2025 Parity Technologies (UK) Ltd. // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. use heck::ToSnakeCase as _; use pezkuwi_subxt_metadata::PalletMetadata; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use scale_typegen::{TypeGenerator, typegen::ir::ToTokensWithSettings}; use super::CodegenError; /// Generate constants from the provided pallet's metadata. /// /// The function creates a new module named `constants` under the pallet's module. /// ```rust,ignore /// pub mod PalletName { /// pub mod constants { /// ... /// } /// } /// ``` /// /// The constants are exposed via the `ConstantsApi` wrapper. /// /// Although the constants are defined in the provided static metadata, the API /// ensures that the constants are returned from the runtime metadata of the node. /// This ensures that if the node's constants change value, we'll always see the latest values. /// /// # Arguments /// /// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the /// runtime metadata. /// - `pallet` - Pallet metadata from which the constants are generated. /// - `crate_path` - The crate path under which the `subxt-core` crate is located, e.g. /// `::pezkuwi_subxt::ext::pezkuwi_subxt_core` when using subxt as a dependency. pub fn generate_constants( type_gen: &TypeGenerator, pallet: &PalletMetadata, crate_path: &syn::Path, ) -> Result { // Early return if the pallet has no constants. if pallet.constants().len() == 0 { return Ok(quote!()); } let constant_fns = pallet .constants() .map(|constant| { let fn_name = format_ident!("{}", constant.name().to_snake_case()); let pallet_name = pallet.name(); let constant_name = constant.name(); let Some(constant_hash) = pallet.constant_hash(constant_name) else { return Err(CodegenError::MissingConstantMetadata( constant_name.into(), pallet_name.into(), )); }; let return_ty = type_gen.resolve_type_path(constant.ty())?.to_token_stream(type_gen.settings()); let docs = constant.docs(); let docs = type_gen .settings() .should_gen_docs .then_some(quote! { #( #[doc = #docs ] )* }) .unwrap_or_default(); Ok(quote! { #docs pub fn #fn_name(&self) -> #crate_path::constants::address::StaticAddress<#return_ty> { #crate_path::constants::address::StaticAddress::new_static( #pallet_name, #constant_name, [#(#constant_hash,)*] ) } }) }) .collect::, _>>()?; let types_mod_ident = type_gen.types_mod_ident(); Ok(quote! { pub mod constants { use super::#types_mod_ident; pub struct ConstantsApi; impl ConstantsApi { #(#constant_fns)* } } }) }