diff --git a/cli/src/commands/codegen.rs b/cli/src/commands/codegen.rs index eb2b10f33d..a44e13e80c 100644 --- a/cli/src/commands/codegen.rs +++ b/cli/src/commands/codegen.rs @@ -56,6 +56,11 @@ pub struct Opts { /// Defaults to `false` (default trait derivations are provided). #[clap(long)] no_default_derives: bool, + /// Do not provide default substitutions for the generated types. + /// + /// Defaults to `false` (default substitutions are provided). + #[clap(long)] + no_default_substitutions: bool, } fn derive_for_type_parser(src: &str) -> Result<(String, String), String> { @@ -96,6 +101,7 @@ pub async fn run(opts: Opts) -> color_eyre::Result<()> { opts.no_docs, opts.runtime_types_only, opts.no_default_derives, + opts.no_default_substitutions, )?; Ok(()) } @@ -121,6 +127,7 @@ fn codegen( no_docs: bool, runtime_types_only: bool, no_default_derives: bool, + no_default_substitutions: bool, ) -> color_eyre::Result<()> { let item_mod = syn::parse_quote!( pub mod api {} @@ -155,7 +162,12 @@ fn codegen( derives.extend_for_type(ty, vec![], std::iter::once(attribute.0)); } - let mut type_substitutes = TypeSubstitutes::new(&crate_path); + let mut type_substitutes = if no_default_substitutions { + TypeSubstitutes::new() + } else { + TypeSubstitutes::with_default_substitutes(&crate_path) + }; + for (from_str, to_str) in substitute_types { let from: syn::Path = syn::parse_str(&from_str)?; let to: syn::Path = syn::parse_str(&to_str)?; diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index d0fb06ff89..fde77ceb9c 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -34,7 +34,7 @@ //! // Default module derivatives. //! let mut derives = DerivesRegistry::with_default_derives(&CratePath::default()); //! // Default type substitutes. -//! let substs = TypeSubstitutes::new(&CratePath::default()); +//! let substs = TypeSubstitutes::with_default_substitutes(&CratePath::default()); //! // Generate the Runtime API. //! let generator = subxt_codegen::RuntimeGenerator::new(metadata); //! // Include metadata documentation in the Runtime API. diff --git a/codegen/src/types/substitutes.rs b/codegen/src/types/substitutes.rs index 6bbbdc1b0e..683bfe1e9b 100644 --- a/codegen/src/types/substitutes.rs +++ b/codegen/src/types/substitutes.rs @@ -37,9 +37,25 @@ macro_rules! path_segments { } } +impl Default for TypeSubstitutes { + fn default() -> Self { + Self::new() + } +} + impl TypeSubstitutes { - /// Create a new set of type substitutes with some default substitutions in place. - pub fn new(crate_path: &CratePath) -> Self { + /// Creates a new `TypeSubstitutes` with no default derives. + pub fn new() -> Self { + Self { + substitutes: HashMap::new(), + } + } + + /// Creates a new `TypeSubstitutes` with some default substitutions in place. + /// + /// The `crate_path` denotes the `subxt` crate access path in the + /// generated code. + pub fn with_default_substitutes(crate_path: &CratePath) -> Self { // Some hardcoded default type substitutes, can be overridden by user let defaults = [ ( @@ -163,11 +179,11 @@ impl TypeSubstitutes { src_path: &syn::Path, target_path: &syn::Path, ) -> Result { - let Some(syn::PathSegment { arguments: src_path_args, ..}) = src_path.segments.last() else { - return Err(TypeSubstitutionError::EmptySubstitutePath(src_path.span())) + let Some(syn::PathSegment { arguments: src_path_args, .. }) = src_path.segments.last() else { + return Err(TypeSubstitutionError::EmptySubstitutePath(src_path.span())); }; - let Some(syn::PathSegment { arguments: target_path_args, ..}) = target_path.segments.last() else { - return Err(TypeSubstitutionError::EmptySubstitutePath(target_path.span())) + let Some(syn::PathSegment { arguments: target_path_args, .. }) = target_path.segments.last() else { + return Err(TypeSubstitutionError::EmptySubstitutePath(target_path.span())); }; // Get hold of the generic args for the "from" type, erroring if they aren't valid. @@ -331,14 +347,14 @@ fn replace_path_params_recursively, P: Borrow>( ) { for segment in &mut path.segments { let syn::PathArguments::AngleBracketed(args) = &mut segment.arguments else { - continue + continue; }; for arg in &mut args.args { let syn::GenericArgument::Type(ty) = arg else { - continue + continue; }; let syn::Type::Path(path) = ty else { - continue + continue; }; if let Some(ident) = get_ident_from_type_path(path) { if let Some((_, replacement)) = params.iter().find(|(i, _)| ident == i.borrow()) { @@ -356,7 +372,7 @@ fn replace_path_params_recursively, P: Borrow>( fn get_valid_to_substitution_type(arg: &syn::GenericArgument) -> Option<&syn::TypePath> { let syn::GenericArgument::Type(syn::Type::Path(type_path)) = arg else { // We are looking for a type, not a lifetime or anything else - return None + return None; }; Some(type_path) } @@ -366,7 +382,7 @@ fn get_valid_to_substitution_type(arg: &syn::GenericArgument) -> Option<&syn::Ty fn get_valid_from_substitution_type(arg: &syn::GenericArgument) -> Option<&syn::Ident> { let syn::GenericArgument::Type(syn::Type::Path(type_path)) = arg else { // We are looking for a type, not a lifetime or anything else - return None + return None; }; get_ident_from_type_path(type_path) } @@ -387,7 +403,7 @@ fn get_ident_from_type_path(type_path: &syn::TypePath) -> Option<&syn::Ident> { } let Some(segment) = type_path.path.segments.last() else { // Get the single ident (should be infallible) - return None + return None; }; if !segment.arguments.is_empty() { // The ident shouldn't have any of it's own generic args like A diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index 01a238ef7b..e1f4caddc5 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -38,7 +38,7 @@ fn generate_struct_with_primitives() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -63,7 +63,7 @@ fn generate_struct_with_primitives() { } } } - .to_string() + .to_string() ) } @@ -90,7 +90,7 @@ fn generate_struct_with_a_struct_field() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -122,7 +122,7 @@ fn generate_struct_with_a_struct_field() { } } } - .to_string() + .to_string() ) } @@ -144,7 +144,7 @@ fn generate_tuple_struct() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -153,8 +153,8 @@ fn generate_tuple_struct() { let tests_mod = get_mod(&types, MOD_PATH).unwrap(); assert_eq!( - tests_mod.into_token_stream().to_string(), - quote! { + tests_mod.into_token_stream().to_string(), + quote! { pub mod tests { use super::root; @@ -171,8 +171,8 @@ fn generate_tuple_struct() { pub struct Parent(pub ::core::primitive::bool, pub root::subxt_codegen::types::tests::Child,); } } - .to_string() - ) + .to_string() + ) } #[test] @@ -235,7 +235,7 @@ fn derive_compact_as_for_uint_wrapper_structs() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -310,7 +310,7 @@ fn derive_compact_as_for_uint_wrapper_structs() { pub struct TSu8(pub ::core::primitive::u8,); } } - .to_string() + .to_string() ) } @@ -332,7 +332,7 @@ fn generate_enum() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -359,7 +359,7 @@ fn generate_enum() { } } } - .to_string() + .to_string() ) } @@ -396,7 +396,7 @@ fn compact_fields() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -438,7 +438,7 @@ fn compact_fields() { pub struct TupleStruct(#[codec(compact)] pub ::core::primitive::u32,); } } - .to_string() + .to_string() ) } @@ -464,7 +464,7 @@ fn compact_generic_parameter() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -511,7 +511,7 @@ fn generate_array_field() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -533,7 +533,7 @@ fn generate_array_field() { } } } - .to_string() + .to_string() ) } @@ -554,7 +554,7 @@ fn option_fields() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -577,7 +577,7 @@ fn option_fields() { } } } - .to_string() + .to_string() ) } @@ -600,7 +600,7 @@ fn box_fields_struct() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -623,7 +623,7 @@ fn box_fields_struct() { } } } - .to_string() + .to_string() ) } @@ -646,7 +646,7 @@ fn box_fields_enum() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -671,7 +671,7 @@ fn box_fields_enum() { } } } - .to_string() + .to_string() ) } @@ -692,7 +692,7 @@ fn range_fields() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -715,7 +715,7 @@ fn range_fields() { } } } - .to_string() + .to_string() ) } @@ -742,7 +742,7 @@ fn generics() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -772,7 +772,7 @@ fn generics() { } } } - .to_string() + .to_string() ) } @@ -799,7 +799,7 @@ fn generics_nested() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -830,7 +830,7 @@ fn generics_nested() { } } } - .to_string() + .to_string() ) } @@ -856,7 +856,7 @@ fn generate_bitvec() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -879,7 +879,7 @@ fn generate_bitvec() { } } } - .to_string() + .to_string() ) } @@ -915,7 +915,7 @@ fn generics_with_alias_adds_phantom_data_marker() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -924,8 +924,8 @@ fn generics_with_alias_adds_phantom_data_marker() { let tests_mod = get_mod(&types, MOD_PATH).unwrap(); assert_eq!( - tests_mod.into_token_stream().to_string(), - quote! { + tests_mod.into_token_stream().to_string(), + quote! { pub mod tests { use super::root; #[derive(::subxt_path::ext::codec::CompactAs, ::subxt_path::ext::codec::Decode, ::subxt_path::ext::codec::Encode, ::subxt_path::ext::scale_decode::DecodeAsType, ::subxt_path::ext::scale_encode::EncodeAsType, Debug)] @@ -948,8 +948,8 @@ fn generics_with_alias_adds_phantom_data_marker() { ); } } - .to_string() - ) + .to_string() + ) } #[test] @@ -986,7 +986,7 @@ fn modules() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -1037,7 +1037,7 @@ fn modules() { } } } - .to_string() + .to_string() ) } @@ -1055,7 +1055,7 @@ fn dont_force_struct_names_camel_case() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), DerivesRegistry::with_default_derives(&crate_path), crate_path, true, @@ -1076,7 +1076,7 @@ fn dont_force_struct_names_camel_case() { pub struct AB; } } - .to_string() + .to_string() ) } @@ -1105,7 +1105,7 @@ fn apply_user_defined_derives_for_all_types() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), derives, crate_path, true, @@ -1181,7 +1181,7 @@ fn apply_user_defined_derives_for_specific_types() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), derives, crate_path, true, @@ -1249,7 +1249,7 @@ fn opt_out_from_default_derives() { let type_gen = TypeGenerator::new( &portable_types, "root", - TypeSubstitutes::new(&crate_path), + TypeSubstitutes::with_default_substitutes(&crate_path), derives, crate_path, true, @@ -1276,3 +1276,48 @@ fn opt_out_from_default_derives() { .to_string() ) } + +/// By default a BTreeMap would be replaced by a KeyedVec. +/// This test demonstrates that it does not happen if we opt out of default type substitutes. +#[test] +fn opt_out_from_default_substitutes() { + use std::collections::BTreeMap; + + #[allow(unused)] + #[derive(TypeInfo)] + struct S { + map: BTreeMap, + } + + let mut registry = Registry::new(); + registry.register_type(&meta_type::()); + let portable_types: PortableRegistry = registry.into(); + + let crate_path = "::subxt_path".into(); + let type_gen = TypeGenerator::new( + &portable_types, + "root", + TypeSubstitutes::new(), + DerivesRegistry::with_default_derives(&crate_path), + crate_path, + true, + ); + let types = type_gen.generate_types_mod().expect("Valid type mod; qed"); + let tests_mod = get_mod(&types, MOD_PATH).unwrap(); + + assert_eq!( + tests_mod.into_token_stream().to_string(), + quote! { + pub mod tests { + use super::root; + #[derive(::subxt_path::ext::codec::Decode, ::subxt_path::ext::codec::Encode, ::subxt_path::ext::scale_decode::DecodeAsType, ::subxt_path::ext::scale_encode::EncodeAsType, Debug)] + #[codec(crate = ::subxt_path::ext::codec)] + #[decode_as_type(crate_path = ":: subxt_path :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt_path :: ext :: scale_encode")] + pub struct S { + pub map: ::std::collections::BTreeMap<:: core :: primitive :: u8,:: core :: primitive :: u8>, + } + } + }.to_string() + ) +} diff --git a/macro/src/lib.rs b/macro/src/lib.rs index afb4759dbd..bb0ac0b7fb 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -152,6 +152,8 @@ struct RuntimeMetadataArgs { runtime_types_only: bool, #[darling(default)] no_default_derives: bool, + #[darling(default)] + no_default_substitutions: bool, } #[derive(Debug, FromMeta)] @@ -213,7 +215,11 @@ pub fn subxt(args: TokenStream, input: TokenStream) -> TokenStream { ) } - let mut type_substitutes = TypeSubstitutes::new(&crate_path); + let mut type_substitutes = if args.no_default_substitutions { + TypeSubstitutes::new() + } else { + TypeSubstitutes::with_default_substitutes(&crate_path) + }; let substitute_args_res: Result<(), _> = args.substitute_type.into_iter().try_for_each(|sub| { sub.with .try_into() diff --git a/testing/integration-tests/src/codegen/codegen_documentation.rs b/testing/integration-tests/src/codegen/codegen_documentation.rs index 0319711db6..be4a534f1c 100644 --- a/testing/integration-tests/src/codegen/codegen_documentation.rs +++ b/testing/integration-tests/src/codegen/codegen_documentation.rs @@ -53,7 +53,7 @@ fn generate_runtime_interface(crate_path: CratePath, should_gen_docs: bool) -> S pub mod api {} ); let derives = DerivesRegistry::with_default_derives(&crate_path); - let type_substitutes = TypeSubstitutes::new(&crate_path); + let type_substitutes = TypeSubstitutes::with_default_substitutes(&crate_path); generator .generate_runtime( item_mod, @@ -143,7 +143,7 @@ fn check_root_attrs_preserved() { // Generate a runtime interface from the provided metadata. let generator = RuntimeGenerator::new(metadata); let derives = DerivesRegistry::with_default_derives(&CratePath::default()); - let type_substitutes = TypeSubstitutes::new(&CratePath::default()); + let type_substitutes = TypeSubstitutes::with_default_substitutes(&CratePath::default()); let generated_code = generator .generate_runtime( item_mod,