Add 'Static' type and improve type substitution codegen to accept it (#886)

* Add Static type which defers to Encode/Decode and impls EncodeAsType/DecodeAsType

* rename to static_type and impl Deref/Mut

* Improve type substitution in codegen so that concrete types can be swapped in

* A couple of comment tweaks and no need for a macro export

* Extend type substitution logic to work recursively on destination type

* cargo fmt

* Fix a couple of comments

* update ui test outpuot

* Add docs and missing_docs lint

* Add test for replacing multiple of Ident

* Update codegen/src/error.rs

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>

* update copyright year and fix ui test

* simplify another error

---------

Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
This commit is contained in:
James Wilson
2023-03-31 16:56:19 +01:00
committed by GitHub
parent 42bcddeecb
commit a2b8dde5e6
132 changed files with 5810 additions and 5442 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::api::CodegenError;
use crate::error::CodegenError;
use super::{CratePath, Derives, Field, TypeDefParameters, TypeGenerator, TypeParameter, TypePath};
use proc_macro2::TokenStream;
+10 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
@@ -7,6 +7,9 @@ use syn::{parse_quote, Path};
use std::collections::{HashMap, HashSet};
/// A struct containing the derives that we'll be applying to types;
/// a combination of some common derives for all types, plus type
/// specific derives.
#[derive(Debug, Clone)]
pub struct DerivesRegistry {
default_derives: Derives,
@@ -62,6 +65,8 @@ impl DerivesRegistry {
}
}
/// A struct storing the set of derives and derive attributes that we'll apply
/// to generated types.
#[derive(Debug, Clone)]
pub struct Derives {
derives: HashSet<syn::Path>,
@@ -113,16 +118,19 @@ impl Derives {
self.insert_derive(parse_quote!(#crate_path::ext::codec::CompactAs));
}
pub fn append(&mut self, derives: impl Iterator<Item = syn::Path>) {
/// Extend the set of derives by providing an iterator of paths to derive macros.
pub fn extend(&mut self, derives: impl Iterator<Item = syn::Path>) {
for derive in derives {
self.insert_derive(derive)
}
}
/// Insert a single derive.
pub fn insert_derive(&mut self, derive: syn::Path) {
self.derives.insert(derive);
}
/// Insert a single attribute to be applied to types.
pub fn insert_attribute(&mut self, attribute: syn::Attribute) {
self.attributes.insert(attribute);
}
+9 -13
View File
@@ -1,4 +1,4 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
@@ -17,7 +17,7 @@ use quote::{quote, ToTokens};
use scale_info::{form::PortableForm, PortableRegistry, Type, TypeDef};
use std::collections::BTreeMap;
use crate::api::CodegenError;
use crate::error::CodegenError;
pub use self::{
composite_def::{CompositeDef, CompositeDefFieldType, CompositeDefFields},
@@ -77,11 +77,12 @@ impl<'a> TypeGenerator<'a> {
let path = ty.ty().path();
// Don't generate a type if it was substituted - the target type might
// not be in the type registry + our resolution already performs the substitution.
if self.type_substitutes.for_path(path).is_some() {
if self.type_substitutes.contains(path) {
continue;
}
let namespace = path.namespace();
// prelude types e.g. Option/Result have no namespace, so we don't generate them
if namespace.is_empty() {
continue;
@@ -163,7 +164,7 @@ impl<'a> TypeGenerator<'a> {
.iter()
.find(|tp| tp.concrete_type_id == id)
{
return TypePath::Parameter(parent_type_param.clone());
return TypePath::from_parameter(parent_type_param.clone());
}
let mut ty = self.resolve_type(id);
@@ -188,17 +189,11 @@ impl<'a> TypeGenerator<'a> {
let ty = match ty.type_def() {
TypeDef::Composite(_) | TypeDef::Variant(_) => {
if let Some((path, params)) = self
if let Some(ty) = self
.type_substitutes
.for_path_with_params(ty.path(), &params)
{
TypePathType::Path {
path: syn::TypePath {
qself: None,
path: path.clone(),
},
params: params.to_vec(),
}
ty
} else {
TypePathType::from_type_def_path(
ty.path(),
@@ -256,7 +251,7 @@ impl<'a> TypeGenerator<'a> {
},
};
TypePath::Type(ty)
TypePath::from_type(ty)
}
/// Returns the derives to be applied to all generated types.
@@ -332,6 +327,7 @@ impl Module {
}
}
/// A newtype wrapper which stores the path to the Subxt crate.
#[derive(Debug, Clone)]
pub struct CratePath(syn::Path);
+301 -84
View File
@@ -2,12 +2,14 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{api::CodegenError, CratePath};
use std::{borrow::Cow, collections::HashMap};
use crate::{error::TypeSubstitutionError, CratePath};
use std::{borrow::Borrow, collections::HashMap};
use syn::{parse_quote, spanned::Spanned as _};
use super::TypePath;
use super::{TypePath, TypePathType};
/// A map of type substitutes. We match on the paths to generated types in order
/// to figure out when to swap said type with some provided substitute.
#[derive(Debug)]
pub struct TypeSubstitutes {
substitutes: HashMap<PathSegments, Substitute>,
@@ -21,11 +23,12 @@ struct Substitute {
#[derive(Debug)]
enum TypeParamMapping {
None,
Specified(Vec<u8>),
// Pass any generics from source to target type
PassThrough,
// Replace any ident seen in the path with the input generic type at this index
Specified(Vec<(syn::Ident, usize)>),
}
#[macro_export]
macro_rules! path_segments {
($($ident: ident)::*) => {
PathSegments(
@@ -35,6 +38,7 @@ macro_rules! path_segments {
}
impl TypeSubstitutes {
/// Create a new set of type substitutes with some default substitutions in place.
pub fn new(crate_path: &CratePath) -> Self {
// Some hardcoded default type substitutes, can be overridden by user
let defaults = [
@@ -88,7 +92,7 @@ impl TypeSubstitutes {
k,
Substitute {
path: v,
param_mapping: TypeParamMapping::None,
param_mapping: TypeParamMapping::PassThrough,
},
)
})
@@ -99,13 +103,24 @@ impl TypeSubstitutes {
}
}
/// Insert the given substitution, overwriting any other with the same path.
pub fn insert(
&mut self,
source: syn::Path,
target: AbsolutePath,
) -> Result<(), TypeSubstitutionError> {
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
self.substitutes.insert(key, val);
Ok(())
}
/// Only insert the given substitution if a substitution at that path doesn't
/// already exist.
pub fn insert_if_not_exists(
&mut self,
source: syn::Path,
target: AbsolutePath,
) -> Result<(), CodegenError> {
) -> Result<(), TypeSubstitutionError> {
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
self.substitutes.entry(key).or_insert(val);
Ok(())
@@ -115,7 +130,7 @@ impl TypeSubstitutes {
pub fn extend(
&mut self,
elems: impl IntoIterator<Item = (syn::Path, AbsolutePath)>,
) -> Result<(), CodegenError> {
) -> Result<(), TypeSubstitutionError> {
for (source, target) in elems.into_iter() {
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
self.substitutes.insert(key, val);
@@ -127,78 +142,142 @@ impl TypeSubstitutes {
/// source to target, and output the source => substitution mapping that we work out from this.
fn parse_path_substitution(
src_path: syn::Path,
mut target_path: syn::Path,
) -> Result<(PathSegments, Substitute), CodegenError> {
let Some(syn::PathSegment { arguments: src_path_args, ..}) = src_path.segments.last() else {
return Err(CodegenError::EmptySubstitutePath(src_path.span()))
};
let Some(syn::PathSegment { arguments: target_path_args, ..}) = target_path.segments.last_mut() else {
return Err(CodegenError::EmptySubstitutePath(target_path.span()))
};
let source_args: Vec<_> = type_args(src_path_args).collect();
let param_mapping = if source_args.is_empty() {
// If the type parameters on the source type are not specified, then this means that
// the type is either not generic or the user wants to pass through all the parameters
TypeParamMapping::None
} else {
// Describe the mapping in terms of "which source param idx is used for each target param".
// So, for each target param, find the matching source param index.
let mapping = type_args(target_path_args)
.filter_map(|arg| {
source_args
.iter()
.position(|&src| src == arg)
.map(|src_idx| {
u8::try_from(src_idx).expect("type arguments to be fewer than 256; qed")
})
})
.collect();
TypeParamMapping::Specified(mapping)
};
// Now that we've parsed the type params from our target path, remove said params from
// that path, since we're storing them separately.
*target_path_args = syn::PathArguments::None;
target_path: syn::Path,
) -> Result<(PathSegments, Substitute), TypeSubstitutionError> {
let param_mapping = Self::parse_path_param_mapping(&src_path, &target_path)?;
Ok((
PathSegments::from(&src_path),
Substitute {
// Note; at this point, target_path might have some generics still. These
// might be hardcoded types that we want to keep, so leave them here for now.
path: target_path,
param_mapping,
},
))
}
/// Given a source type path, return a substituted type path if a substitution is defined.
pub fn for_path(&self, path: impl Into<PathSegments>) -> Option<&syn::Path> {
self.substitutes.get(&path.into()).map(|s| &s.path)
/// Given a source and target path, parse the type params to work out the mapping from
/// source to target, and return it.
fn parse_path_param_mapping(
src_path: &syn::Path,
target_path: &syn::Path,
) -> Result<TypeParamMapping, TypeSubstitutionError> {
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()))
};
// Get hold of the generic args for the "from" type, erroring if they aren't valid.
let source_args = match src_path_args {
syn::PathArguments::None => {
// No generics defined on the source type:
Vec::new()
}
syn::PathArguments::AngleBracketed(args) => {
// We have generics like <A,B> defined on the source type (error for any non-ident type):
args.args
.iter()
.map(|arg| match get_valid_from_substitution_type(arg) {
Some(ident) => Ok(ident),
None => Err(TypeSubstitutionError::InvalidFromType(arg.span())),
})
.collect::<Result<Vec<_>, _>>()?
}
syn::PathArguments::Parenthesized(args) => {
// Generics like (A,B) -> defined; not allowed:
return Err(TypeSubstitutionError::ExpectedAngleBracketGenerics(
args.span(),
));
}
};
// Get hold of the generic args for the "to" type, erroring if they aren't valid.
let target_args = match target_path_args {
syn::PathArguments::None => {
// No generics on target.
Vec::new()
}
syn::PathArguments::AngleBracketed(args) => {
// We have generics like <A,B> defined on the target type.
args.args
.iter()
.map(|arg| match get_valid_to_substitution_type(arg) {
Some(arg) => Ok(arg),
None => Err(TypeSubstitutionError::InvalidToType(arg.span())),
})
.collect::<Result<Vec<_>, _>>()?
}
syn::PathArguments::Parenthesized(args) => {
// Generics like (A,B) -> defined; not allowed:
return Err(TypeSubstitutionError::ExpectedAngleBracketGenerics(
args.span(),
));
}
};
// If no generics defined on source or target, we just apply any concrete generics
// to the substitute type.
if source_args.is_empty() && target_args.is_empty() {
return Ok(TypeParamMapping::PassThrough);
}
// Make a note of the idents in the source args and their indexes.
let mapping = source_args
.into_iter()
.enumerate()
.map(|(idx, ident)| (ident.clone(), idx))
.collect();
Ok(TypeParamMapping::Specified(mapping))
}
/// Given a source type path, return whether a substitute exists for it.
pub fn contains(&self, path: impl Into<PathSegments>) -> bool {
self.substitutes.contains_key(&path.into())
}
/// Given a source type path and the resolved, supplied type parameters,
/// return a new path and optionally overwritten type parameters.
pub fn for_path_with_params<'a: 'b, 'b>(
&'a self,
pub fn for_path_with_params(
&self,
path: impl Into<PathSegments>,
params: &'b [TypePath],
) -> Option<(&'a syn::Path, Cow<'b, [TypePath]>)> {
// For now, we only support:
// 1. Reordering the generics
// 2. Omitting certain generics
fn reorder_params<'a>(
params: &'a [TypePath],
params: &[TypePath],
) -> Option<TypePathType> {
// If we find a substitute type, we'll take the substitute path, and
// swap any idents with their new concrete types.
fn replace_params(
mut substitute_path: syn::Path,
params: &[TypePath],
mapping: &TypeParamMapping,
) -> Cow<'a, [TypePath]> {
) -> TypePathType {
match mapping {
TypeParamMapping::Specified(mapping) => Cow::Owned(
mapping
// We need to map the input params to the output params somehow:
TypeParamMapping::Specified(mapping) => {
// A map from ident name to replacement path.
let replacement_map: Vec<(&syn::Ident, &TypePath)> = mapping
.iter()
.filter_map(|&idx| params.get(idx as usize))
.cloned()
.collect(),
),
_ => Cow::Borrowed(params),
.filter_map(|(ident, idx)| params.get(*idx).map(|param| (ident, param)))
.collect();
// Replace params in our substitute path with the incoming ones as needed.
// No need if no replacements given.
if !replacement_map.is_empty() {
replace_path_params_recursively(&mut substitute_path, &replacement_map);
}
TypePathType::Path {
path: substitute_path,
params: Vec::new(),
}
}
// No mapping; just hand back the substitute path and input params.
TypeParamMapping::PassThrough => TypePathType::Path {
path: substitute_path,
params: params.to_vec(),
},
}
}
@@ -206,7 +285,7 @@ impl TypeSubstitutes {
self.substitutes
.get(&path)
.map(|sub| (&sub.path, reorder_params(params, &sub.param_mapping)))
.map(|sub| replace_params(sub.path.clone(), params, &sub.param_mapping))
}
}
@@ -234,23 +313,87 @@ impl<T: scale_info::form::Form> From<&scale_info::Path<T>> for PathSegments {
}
}
/// Returns an iterator over generic type parameters for `syn::PathArguments`.
/// For example:
/// - `<'a, T>` should only return T
/// - `(A, B) -> String` shouldn't return anything
fn type_args(path_args: &syn::PathArguments) -> impl Iterator<Item = &syn::Path> {
let args_opt = match path_args {
syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
ref args,
..
}) => Some(args),
_ => None,
};
/// Dig through a `syn::TypePath` (this is provided by the user in a type substitution definition as the "to" type) and
/// swap out any type params which match the idents given in the "from" type with the corresponding concrete types.
///
/// eg if we have:
///
/// ```text
/// from = sp_runtime::MultiAddress<A, B>,
/// to = ::subxt::utils::Static<::sp_runtime::MultiAddress<A, B>>
/// ```
///
/// And we encounter a `sp_runtime::MultiAddress<Foo, bar>`, then we will pass the `::sp_runtime::MultiAddress<A, B>`
/// type param value into this call to turn it into `::sp_runtime::MultiAddress<Foo, Bar>`.
fn replace_path_params_recursively<I: Borrow<syn::Ident>, P: Borrow<TypePath>>(
path: &mut syn::Path,
params: &Vec<(I, P)>,
) {
for segment in &mut path.segments {
let syn::PathArguments::AngleBracketed(args) = &mut segment.arguments else {
continue
};
for arg in &mut args.args {
let syn::GenericArgument::Type(ty) = arg else {
continue
};
let syn::Type::Path(path) = ty else {
continue
};
if let Some(ident) = get_ident_from_type_path(path) {
if let Some((_, replacement)) = params.iter().find(|(i, _)| ident == i.borrow()) {
*ty = replacement.borrow().to_syn_type();
continue;
}
}
replace_path_params_recursively(&mut path.path, params);
}
}
}
args_opt.into_iter().flatten().filter_map(|arg| match arg {
syn::GenericArgument::Type(syn::Type::Path(type_path)) => Some(&type_path.path),
_ => None,
})
/// Given a "to" type in a type substitution, return the TypePath inside or None if
/// it's not a valid "to" type.
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
};
Some(type_path)
}
/// Given a "from" type in a type substitution, return the Ident inside or None if
/// it's not a valid "from" type.
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
};
get_ident_from_type_path(type_path)
}
/// Given a type path, return the single ident representing it if that's all it is.
fn get_ident_from_type_path(type_path: &syn::TypePath) -> Option<&syn::Ident> {
if type_path.qself.is_some() {
// No "<Foo as Bar>" type thing
return None;
}
if type_path.path.leading_colon.is_some() {
// No leading "::"
return None;
}
if type_path.path.segments.len() > 1 {
// The path should just be a single ident, not multiple
return None;
}
let Some(segment) = type_path.path.segments.last() else {
// Get the single ident (should be infallible)
return None
};
if !segment.arguments.is_empty() {
// The ident shouldn't have any of it's own generic args like A<B, C>
return None;
}
Some(&segment.ident)
}
/// Whether a path is absolute - starts with `::` or `crate`.
@@ -265,14 +408,88 @@ fn is_absolute(path: &syn::Path) -> bool {
pub struct AbsolutePath(pub syn::Path);
impl TryFrom<syn::Path> for AbsolutePath {
type Error = (syn::Path, String);
type Error = TypeSubstitutionError;
fn try_from(value: syn::Path) -> Result<Self, Self::Error> {
if is_absolute(&value) {
Ok(AbsolutePath(value))
} else {
Err(
(value, "The substitute path must be a global absolute path; try prefixing with `::` or `crate`".to_owned())
)
Err(TypeSubstitutionError::ExpectedAbsolutePath(value.span()))
}
}
}
#[cfg(test)]
mod test {
use super::*;
macro_rules! syn_path {
($path:path) => {{
let path: syn::Path = syn::parse_quote!($path);
path
}};
}
macro_rules! type_path {
($path:path) => {{
let path: syn::Path = syn::parse_quote!($path);
TypePath::from_syn_path(path)
}};
}
fn ident(name: &'static str) -> syn::Ident {
syn::Ident::new(name, proc_macro2::Span::call_site())
}
#[test]
#[rustfmt::skip]
fn replacing_nested_type_params_works() {
// Original path, replacement ident->paths, expected output path
let paths = [
// Works ok if nothing to replace
(
syn_path!(::some::path::Foo<::other::Path<A, B>>),
vec![],
syn_path!(::some::path::Foo<::other::Path<A, B>>),
),
// Simple top level replacing
(
syn_path!(::some::path::Foo<A>),
vec![(ident("A"), type_path!(::new::Value))],
syn_path!(::some::path::Foo<::new::Value>),
),
// More deeply nested replacing works too
(
syn_path!(::some::path::Foo<::other::Path<A, B>>),
vec![(ident("A"), type_path!(::new::Value))],
syn_path!(::some::path::Foo<::other::Path<::new::Value, B>>),
),
(
syn_path!(::some::path::Foo<::other::Path<A, B>>),
vec![
(ident("A"), type_path!(::new::A)),
(ident("B"), type_path!(::new::B)),
],
syn_path!(::some::path::Foo<::other::Path<::new::A, ::new::B>>),
),
(
syn_path!(::some::path::Foo<::other::Path<A, ::more::path::to<::something::Argh<B>>>, C>),
vec![
(ident("A"), type_path!(::new::A)),
(ident("B"), type_path!(::new::B)),
],
syn_path!(::some::path::Foo<::other::Path<::new::A, ::more::path::to<::something::Argh<::new::B>>>,C>),
),
// The same ident will be replaced as many times as needed:
(
syn_path!(::some::path::Foo<::other::Path<A, ::foo::Argh<A, B>, A>>),
vec![(ident("A"), type_path!(::new::Value))],
syn_path!(::some::path::Foo<::other::Path<::new::Value, ::foo::Argh<::new::Value, B>, ::new::Value>>),
),
];
for (mut path, replacements, expected) in paths {
replace_path_params_recursively(&mut path, &replacements);
assert_eq!(path, expected);
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
+2 -2
View File
@@ -1,8 +1,8 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::api::CodegenError;
use crate::error::CodegenError;
use super::{
CompositeDef, CompositeDefFields, CratePath, Derives, TypeDefParameters, TypeGenerator,
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
+40 -14
View File
@@ -1,4 +1,4 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
@@ -10,8 +10,14 @@ use scale_info::{form::PortableForm, Path, TypeDefPrimitive};
use std::collections::BTreeSet;
use syn::parse_quote;
/// An opaque struct representing a type path. The main usage of this is
/// to spit out as tokens in some `quote!{ ... }` macro; the inner structure
/// should be unimportant.
#[derive(Clone, Debug)]
pub enum TypePath {
pub struct TypePath(TypePathInner);
#[derive(Clone, Debug)]
pub enum TypePathInner {
Parameter(TypeParameter),
Type(TypePathType),
}
@@ -24,15 +30,35 @@ impl quote::ToTokens for TypePath {
}
impl TypePath {
/// Construct a [`TypePath`] from a [`TypeParameter`]
pub fn from_parameter(param: TypeParameter) -> TypePath {
TypePath(TypePathInner::Parameter(param))
}
/// Construct a [`TypePath`] from a [`TypeParameter`]
pub fn from_type(ty: TypePathType) -> TypePath {
TypePath(TypePathInner::Type(ty))
}
/// Construct a [`TypePath`] from a [`syn::TypePath`]
pub fn from_syn_path(path: syn::Path) -> TypePath {
// Note; this doesn't parse the parameters or anything, but since nothing external
// can inspect this structure, and the ToTokens impl works either way, it should be ok.
TypePath(TypePathInner::Type(TypePathType::Path {
path,
params: Vec::new(),
}))
}
pub(crate) fn to_syn_type(&self) -> syn::Type {
match self {
TypePath::Parameter(ty_param) => syn::Type::Path(parse_quote! { #ty_param }),
TypePath::Type(ty) => ty.to_syn_type(),
match &self.0 {
TypePathInner::Parameter(ty_param) => syn::Type::Path(parse_quote! { #ty_param }),
TypePathInner::Type(ty) => ty.to_syn_type(),
}
}
pub(crate) fn is_compact(&self) -> bool {
matches!(self, Self::Type(ty) if ty.is_compact())
matches!(&self.0, TypePathInner::Type(ty) if ty.is_compact())
}
/// Returns the type parameters in a path which are inherited from the containing type.
@@ -45,11 +71,11 @@ impl TypePath {
/// }
/// ```
pub fn parent_type_params(&self, acc: &mut BTreeSet<TypeParameter>) {
match self {
Self::Parameter(type_parameter) => {
match &self.0 {
TypePathInner::Parameter(type_parameter) => {
acc.insert(type_parameter.clone());
}
Self::Type(type_path) => type_path.parent_type_params(acc),
TypePathInner::Type(type_path) => type_path.parent_type_params(acc),
}
}
@@ -57,13 +83,13 @@ impl TypePath {
///
/// **Note:** Utilized for transforming `std::vec::Vec<T>` into slices `&[T]` for the storage API.
pub fn vec_type_param(&self) -> Option<&TypePath> {
let ty = match self {
TypePath::Type(ty) => ty,
let ty = match &self.0 {
TypePathInner::Type(ty) => ty,
_ => return None,
};
match ty {
TypePathType::Vec { ref of } => Some(of),
TypePathType::Vec { of } => Some(of),
_ => None,
}
}
@@ -72,7 +98,7 @@ impl TypePath {
#[derive(Clone, Debug)]
pub enum TypePathType {
Path {
path: syn::TypePath,
path: syn::Path,
params: Vec<TypePath>,
},
Vec {
@@ -108,7 +134,7 @@ impl TypePathType {
) -> Self {
let path_segments = path.segments();
let path: syn::TypePath = match path_segments {
let path: syn::Path = match path_segments {
[] => panic!("Type has no ident"),
[ident] => {
// paths to prelude types