scale_typegen/typegen/
type_params.rs

1// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use super::TypeParameter;
6use quote::{format_ident, quote};
7use scale_info::form::PortableForm;
8use std::collections::BTreeSet;
9
10/// Represents the set of generic type parameters for generating a type definition e.g. the `T` in
11/// `Foo<T>`.
12///
13/// Additionally this allows generating a `PhantomData` type for any type params which are unused
14/// in the type definition itself.
15#[derive(Clone, Debug, Default)]
16pub struct TypeParameters {
17    params: Vec<TypeParameter>,
18    unused: BTreeSet<TypeParameter>,
19}
20
21impl TypeParameters {
22    /// Create a new [`TypeParameters`] instance.
23    pub fn from_scale_info(params: &[scale_info::TypeParameter<PortableForm>]) -> Self {
24        let params = params
25            .iter()
26            .enumerate()
27            .filter_map(|(i, tp)| {
28                tp.ty.as_ref().map(|ty| {
29                    let tp_name = format_ident!("_{}", i);
30                    TypeParameter {
31                        concrete_type_id: ty.id,
32                        original_name: tp.name.clone(),
33                        name: tp_name,
34                    }
35                })
36            })
37            .collect::<Vec<_>>();
38
39        let unused = params.iter().cloned().collect();
40        Self { params, unused }
41    }
42
43    /// Construct a [`core::marker::PhantomData`] for the type unused type params.
44    pub fn unused_params_phantom_data(&self) -> Option<syn::TypePath> {
45        if self.unused.is_empty() {
46            return None;
47        }
48        let params = if self.unused.len() == 1 {
49            let param = self
50                .unused
51                .iter()
52                .next()
53                .expect("Checked for exactly one unused param");
54            quote! { #param }
55        } else {
56            let params = self.unused.iter();
57            quote! { ( #( #params ), * ) }
58        };
59        Some(syn::parse_quote! {::core::marker::PhantomData<#params> })
60    }
61
62    /// Returns the set of type parameters.
63    pub fn params(&self) -> &[TypeParameter] {
64        &self.params
65    }
66
67    /// Returns true if there are any unused type params
68    pub fn has_unused_type_params(&self) -> bool {
69        !self.unused.is_empty()
70    }
71    pub(super) fn mark_used(&mut self, param: &TypeParameter) {
72        self.unused.remove(param);
73    }
74}
75
76impl quote::ToTokens for TypeParameters {
77    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
78        if !self.params.is_empty() {
79            let params = &self.params;
80            tokens.extend(quote! { < #( #params ),* > })
81        }
82    }
83}