1use proc_macro2::{Ident, TokenStream};
6use quote::{format_ident, ToTokens};
7use scale_info::{form::PortableForm, Path, TypeDefPrimitive};
8use std::collections::BTreeSet;
9use syn::parse_quote;
10
11use crate::TypeGeneratorSettings;
12
13use super::ir::ToTokensWithSettings;
14use super::settings::AllocCratePath;
15
16#[derive(Clone, Debug)]
20pub struct TypePath(TypePathInner);
21
22#[derive(Clone, Debug)]
24pub enum TypePathInner {
25 Parameter(TypeParameter),
27 Type(TypePathType),
29}
30
31impl ToTokensWithSettings for TypePath {
32 fn to_tokens(&self, tokens: &mut TokenStream, settings: &TypeGeneratorSettings) {
33 let syn_type = self.to_syn_type(&settings.alloc_crate_path);
34 syn_type.to_tokens(tokens)
35 }
36}
37
38impl TypePath {
39 pub fn from_parameter(param: TypeParameter) -> TypePath {
41 TypePath(TypePathInner::Parameter(param))
42 }
43
44 pub fn from_type(ty: TypePathType) -> TypePath {
46 TypePath(TypePathInner::Type(ty))
47 }
48
49 pub fn from_syn_path(path: syn::Path) -> TypePath {
51 TypePath(TypePathInner::Type(TypePathType::Path {
54 path,
55 params: Vec::new(),
56 }))
57 }
58
59 pub(crate) fn to_syn_type(&self, alloc_crate_path: &AllocCratePath) -> syn::Type {
60 match &self.0 {
61 TypePathInner::Parameter(ty_param) => syn::Type::Path(parse_quote! { #ty_param }),
62 TypePathInner::Type(ty) => ty.to_syn_type(alloc_crate_path),
63 }
64 }
65
66 pub fn is_compact(&self) -> bool {
68 matches!(&self.0, TypePathInner::Type(ty) if ty.is_compact())
69 }
70
71 pub fn is_string(&self) -> bool {
73 matches!(&self.0, TypePathInner::Type(ty) if ty.is_string())
74 }
75
76 pub fn is_uint_up_to_u128(&self) -> bool {
78 matches!(
79 &self.0,
80 TypePathInner::Type(TypePathType::Primitive {
81 def: TypeDefPrimitive::U8
82 | TypeDefPrimitive::U16
83 | TypeDefPrimitive::U32
84 | TypeDefPrimitive::U64
85 | TypeDefPrimitive::U128
86 })
87 )
88 }
89
90 pub fn parent_type_params(&self) -> BTreeSet<TypeParameter> {
100 let mut acc = BTreeSet::<TypeParameter>::new();
101 self.parent_type_params_recurse(&mut acc);
102 acc
103 }
104
105 fn parent_type_params_recurse(&self, acc: &mut BTreeSet<TypeParameter>) {
106 match &self.0 {
107 TypePathInner::Parameter(type_parameter) => {
108 acc.insert(type_parameter.clone());
109 }
110 TypePathInner::Type(type_path) => type_path.parent_type_params(acc),
111 }
112 }
113
114 pub fn vec_type_param(&self) -> Option<&TypePath> {
118 let ty = match &self.0 {
119 TypePathInner::Type(ty) => ty,
120 _ => return None,
121 };
122
123 match ty {
124 TypePathType::Vec { of } => Some(of),
125 _ => None,
126 }
127 }
128}
129
130#[derive(Clone, Debug)]
132pub enum TypePathType {
133 Path {
135 path: syn::Path,
137 params: Vec<TypePath>,
139 },
140 Vec {
142 of: Box<TypePath>,
144 },
145 Array {
147 len: usize,
149 of: Box<TypePath>,
151 },
152 Tuple {
154 elements: Vec<TypePath>,
156 },
157 Primitive {
159 def: TypeDefPrimitive,
161 },
162 Compact {
164 inner: Box<TypePath>,
166 is_field: bool,
168 compact_type_path: syn::Path,
170 },
171 BitVec {
173 bit_order_type: Box<TypePath>,
175 bit_store_type: Box<TypePath>,
177 decoded_bits_type_path: syn::Path,
179 },
180}
181
182impl TypePathType {
183 pub fn from_type_def_path(
185 path: &Path<PortableForm>,
186 root_mod_ident: Ident,
187 params: Vec<TypePath>,
188 alloc_crate_path: &AllocCratePath,
189 ) -> Self {
190 let path_segments = &*path.segments;
191
192 let path: syn::Path = match path_segments {
193 [] => panic!("Type has no ident"),
194 [ident] => {
195 match ident.as_str() {
197 "Option" => parse_quote!(::core::option::Option),
198 "Result" => parse_quote!(::core::result::Result),
199 "Cow" => parse_quote!(#alloc_crate_path::borrow::Cow),
200 "BTreeMap" => parse_quote!(#alloc_crate_path::collections::BTreeMap),
201 "BTreeSet" => parse_quote!(#alloc_crate_path::collections::BTreeSet),
202 "BinaryHeap" => parse_quote!(#alloc_crate_path::collections::BinaryHeap),
203 "VecDeque" => parse_quote!(#alloc_crate_path::collections::VecDeque),
204 "LinkedList" => parse_quote!(#alloc_crate_path::collections::LinkedList),
205 "Range" => parse_quote!(::core::ops::Range),
206 "RangeInclusive" => parse_quote!(::core::ops::RangeInclusive),
207 "NonZeroI8" => parse_quote!(::core::num::NonZeroI8),
208 "NonZeroU8" => parse_quote!(::core::num::NonZeroU8),
209 "NonZeroI16" => parse_quote!(::core::num::NonZeroI16),
210 "NonZeroU16" => parse_quote!(::core::num::NonZeroU16),
211 "NonZeroI32" => parse_quote!(::core::num::NonZeroI32),
212 "NonZeroU32" => parse_quote!(::core::num::NonZeroU32),
213 "NonZeroI64" => parse_quote!(::core::num::NonZeroI64),
214 "NonZeroU64" => parse_quote!(::core::num::NonZeroU64),
215 "NonZeroI128" => parse_quote!(::core::num::NonZeroI128),
216 "NonZeroU128" => parse_quote!(::core::num::NonZeroU128),
217 "NonZeroIsize" => parse_quote!(::core::num::NonZeroIsize),
218 "NonZeroUsize" => parse_quote!(::core::num::NonZeroUsize),
219 ident => panic!("Unknown prelude type '{ident}'"),
220 }
221 }
222 _ => {
223 let mut ty_path = path_segments
225 .iter()
226 .map(|s| syn::PathSegment::from(format_ident!("{}", s)))
227 .collect::<syn::punctuated::Punctuated<syn::PathSegment, syn::Token![::]>>();
228 ty_path.insert(0, syn::PathSegment::from(root_mod_ident));
229 parse_quote!( #ty_path )
230 }
231 };
232 Self::Path { path, params }
233 }
234
235 fn parent_type_params(&self, acc: &mut BTreeSet<TypeParameter>) {
245 match self {
246 TypePathType::Path { params, .. } => {
247 for p in params {
248 p.parent_type_params_recurse(acc)
249 }
250 }
251 TypePathType::Vec { of } => of.parent_type_params_recurse(acc),
252 TypePathType::Array { of, .. } => of.parent_type_params_recurse(acc),
253 TypePathType::Tuple { elements } => {
254 for e in elements {
255 e.parent_type_params_recurse(acc)
256 }
257 }
258 TypePathType::Primitive { .. } => (),
259 TypePathType::Compact { inner, .. } => inner.parent_type_params_recurse(acc),
260 TypePathType::BitVec {
261 bit_order_type,
262 bit_store_type,
263 ..
264 } => {
265 bit_order_type.parent_type_params_recurse(acc);
266 bit_store_type.parent_type_params_recurse(acc);
267 }
268 }
269 }
270
271 pub fn is_compact(&self) -> bool {
273 matches!(self, TypePathType::Compact { .. })
274 }
275
276 pub fn is_string(&self) -> bool {
278 matches!(
279 self,
280 TypePathType::Primitive {
281 def: TypeDefPrimitive::Str
282 }
283 )
284 }
285
286 fn to_syn_type(&self, alloc_crate_path: &AllocCratePath) -> syn::Type {
287 match &self {
288 TypePathType::Path { path, params } => {
289 let path = if params.is_empty() {
290 parse_quote! { #path }
291 } else {
292 let params = params.iter().map(|e| e.to_syn_type(alloc_crate_path));
293 parse_quote! { #path< #( #params ),* > }
294 };
295 syn::Type::Path(path)
296 }
297 TypePathType::Vec { of } => {
298 let of = of.to_syn_type(alloc_crate_path);
299 let type_path = parse_quote! { #alloc_crate_path::vec::Vec<#of> };
300 syn::Type::Path(type_path)
301 }
302 TypePathType::Array { len, of } => {
303 let of = of.to_syn_type(alloc_crate_path);
304 let array = parse_quote! { [#of; #len] };
305 syn::Type::Array(array)
306 }
307 TypePathType::Tuple { elements } => {
308 let elements = elements.iter().map(|e| e.to_syn_type(alloc_crate_path));
309 let tuple = parse_quote! { (#( # elements, )* ) };
310 syn::Type::Tuple(tuple)
311 }
312 TypePathType::Primitive { def } => syn::Type::Path(match def {
313 TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool),
314 TypeDefPrimitive::Char => parse_quote!(::core::primitive::char),
315 TypeDefPrimitive::Str => parse_quote!(#alloc_crate_path::string::String),
316 TypeDefPrimitive::U8 => parse_quote!(::core::primitive::u8),
317 TypeDefPrimitive::U16 => parse_quote!(::core::primitive::u16),
318 TypeDefPrimitive::U32 => parse_quote!(::core::primitive::u32),
319 TypeDefPrimitive::U64 => parse_quote!(::core::primitive::u64),
320 TypeDefPrimitive::U128 => parse_quote!(::core::primitive::u128),
321 TypeDefPrimitive::U256 => unimplemented!("not a rust primitive"),
322 TypeDefPrimitive::I8 => parse_quote!(::core::primitive::i8),
323 TypeDefPrimitive::I16 => parse_quote!(::core::primitive::i16),
324 TypeDefPrimitive::I32 => parse_quote!(::core::primitive::i32),
325 TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64),
326 TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128),
327 TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"),
328 }),
329 TypePathType::Compact {
330 inner,
331 is_field,
332 compact_type_path,
333 } => {
334 let inner = inner.to_syn_type(alloc_crate_path);
335 let path = if *is_field {
336 parse_quote! ( #inner )
339 } else {
340 parse_quote! ( #compact_type_path<#inner> )
341 };
342 syn::Type::Path(path)
343 }
344 TypePathType::BitVec {
345 bit_order_type,
346 bit_store_type,
347 decoded_bits_type_path,
348 } => {
349 let bit_order_type = bit_order_type.to_syn_type(alloc_crate_path);
350 let bit_store_type = bit_store_type.to_syn_type(alloc_crate_path);
351 let type_path =
352 parse_quote! { #decoded_bits_type_path<#bit_store_type, #bit_order_type> };
353 syn::Type::Path(type_path)
354 }
355 }
356 }
357}
358
359#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
361pub struct TypeParameter {
362 pub(super) concrete_type_id: u32,
363 pub(super) original_name: String,
364 pub(super) name: Ident,
365}
366
367impl quote::ToTokens for TypeParameter {
368 fn to_tokens(&self, tokens: &mut TokenStream) {
369 self.name.to_tokens(tokens)
370 }
371}