diff --git a/codegen/src/api/constants.rs b/codegen/src/api/constants.rs new file mode 100644 index 0000000000..7cbb988450 --- /dev/null +++ b/codegen/src/api/constants.rs @@ -0,0 +1,56 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use crate::types::TypeGenerator; +use frame_metadata::PalletConstantMetadata; +use heck::SnakeCase as _; +use proc_macro2::TokenStream as TokenStream2; +use quote::{ + format_ident, + quote, +}; +use scale_info::form::PortableForm; + +pub fn generate_constants( + type_gen: &TypeGenerator, + constants: &[PalletConstantMetadata], + types_mod_ident: &syn::Ident, +) -> TokenStream2 { + let constant_fns = constants.iter().map(|constant| { + let fn_name = format_ident!("{}", constant.name.to_snake_case()); + let return_ty = type_gen.resolve_type_path(constant.ty.id(), &[]); + + let ref_slice = constant.value.as_slice(); + + quote! { + pub fn #fn_name(&self) -> ::core::result::Result<#return_ty, ::subxt::BasicError> { + Ok(::subxt::codec::Decode::decode(&mut &[#(#ref_slice,)*][..])?) + } + } + }); + + quote! { + pub mod constants { + use super::#types_mod_ident; + + pub struct ConstantsApi; + + impl ConstantsApi { + #(#constant_fns)* + } + } + } +} diff --git a/codegen/src/api/mod.rs b/codegen/src/api/mod.rs index ea8e73c45f..3b4c4dd365 100644 --- a/codegen/src/api/mod.rs +++ b/codegen/src/api/mod.rs @@ -15,6 +15,7 @@ // along with subxt. If not, see . mod calls; +mod constants; mod errors; mod events; mod storage; @@ -173,12 +174,23 @@ impl RuntimeGenerator { quote!() }; + let constants_mod = if !pallet.constants.is_empty() { + constants::generate_constants( + &type_gen, + &pallet.constants, + types_mod_ident, + ) + } else { + quote!() + }; + quote! { pub mod #mod_name { use super::#types_mod_ident; #calls #event #storage_mod + #constants_mod } } }); @@ -204,6 +216,12 @@ impl RuntimeGenerator { }; let mod_ident = item_mod_ir.ident; + let pallets_with_constants = + pallets_with_mod_names + .iter() + .filter_map(|(pallet, pallet_mod_name)| { + (!pallet.constants.is_empty()).then(|| pallet_mod_name) + }); let pallets_with_storage = pallets_with_mod_names .iter() @@ -270,6 +288,10 @@ impl RuntimeGenerator { T: ::subxt::Config, X: ::subxt::SignedExtra, { + pub fn constants(&'a self) -> ConstantsApi { + ConstantsApi + } + pub fn storage(&'a self) -> StorageApi<'a, T> { StorageApi { client: &self.client } } @@ -279,6 +301,17 @@ impl RuntimeGenerator { } } + pub struct ConstantsApi; + + impl ConstantsApi + { + #( + pub fn #pallets_with_constants(&self) -> #pallets_with_constants::constants::ConstantsApi { + #pallets_with_constants::constants::ConstantsApi + } + )* + } + pub struct StorageApi<'a, T: ::subxt::Config> { client: &'a ::subxt::Client, } diff --git a/tests/integration/frame/balances.rs b/tests/integration/frame/balances.rs index 91dbcc353e..405ca90fc1 100644 --- a/tests/integration/frame/balances.rs +++ b/tests/integration/frame/balances.rs @@ -261,4 +261,12 @@ async fn constant_existential_deposit() { let constant_metadata = balances_metadata.constant("ExistentialDeposit").unwrap(); let existential_deposit = u128::decode(&mut &constant_metadata.value[..]).unwrap(); assert_eq!(existential_deposit, 100_000_000_000_000); + assert_eq!( + existential_deposit, + cxt.api + .constants() + .balances() + .existential_deposit() + .unwrap() + ); }