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 "Duration" => parse_quote!(::core::time::Duration),
220 ident => panic!("Unknown prelude type '{ident}'"),
221 }
222 }
223 _ => {
224 let mut ty_path = path_segments
226 .iter()
227 .map(|s| syn::PathSegment::from(format_ident!("{}", s)))
228 .collect::<syn::punctuated::Punctuated<syn::PathSegment, syn::Token![::]>>();
229 ty_path.insert(0, syn::PathSegment::from(root_mod_ident));
230 parse_quote!( #ty_path )
231 }
232 };
233 Self::Path { path, params }
234 }
235
236 fn parent_type_params(&self, acc: &mut BTreeSet<TypeParameter>) {
246 match self {
247 TypePathType::Path { params, .. } => {
248 for p in params {
249 p.parent_type_params_recurse(acc)
250 }
251 }
252 TypePathType::Vec { of } => of.parent_type_params_recurse(acc),
253 TypePathType::Array { of, .. } => of.parent_type_params_recurse(acc),
254 TypePathType::Tuple { elements } => {
255 for e in elements {
256 e.parent_type_params_recurse(acc)
257 }
258 }
259 TypePathType::Primitive { .. } => (),
260 TypePathType::Compact { inner, .. } => inner.parent_type_params_recurse(acc),
261 TypePathType::BitVec {
262 bit_order_type,
263 bit_store_type,
264 ..
265 } => {
266 bit_order_type.parent_type_params_recurse(acc);
267 bit_store_type.parent_type_params_recurse(acc);
268 }
269 }
270 }
271
272 pub fn is_compact(&self) -> bool {
274 matches!(self, TypePathType::Compact { .. })
275 }
276
277 pub fn is_string(&self) -> bool {
279 matches!(
280 self,
281 TypePathType::Primitive {
282 def: TypeDefPrimitive::Str
283 }
284 )
285 }
286
287 fn to_syn_type(&self, alloc_crate_path: &AllocCratePath) -> syn::Type {
288 match &self {
289 TypePathType::Path { path, params } => {
290 let path = if params.is_empty() {
291 parse_quote! { #path }
292 } else {
293 let params = params.iter().map(|e| e.to_syn_type(alloc_crate_path));
294 parse_quote! { #path< #( #params ),* > }
295 };
296 syn::Type::Path(path)
297 }
298 TypePathType::Vec { of } => {
299 let of = of.to_syn_type(alloc_crate_path);
300 let type_path = parse_quote! { #alloc_crate_path::vec::Vec<#of> };
301 syn::Type::Path(type_path)
302 }
303 TypePathType::Array { len, of } => {
304 let of = of.to_syn_type(alloc_crate_path);
305 let array = parse_quote! { [#of; #len] };
306 syn::Type::Array(array)
307 }
308 TypePathType::Tuple { elements } => {
309 let elements = elements.iter().map(|e| e.to_syn_type(alloc_crate_path));
310 let tuple = parse_quote! { (#( # elements, )* ) };
311 syn::Type::Tuple(tuple)
312 }
313 TypePathType::Primitive { def } => syn::Type::Path(match def {
314 TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool),
315 TypeDefPrimitive::Char => parse_quote!(::core::primitive::char),
316 TypeDefPrimitive::Str => parse_quote!(#alloc_crate_path::string::String),
317 TypeDefPrimitive::U8 => parse_quote!(::core::primitive::u8),
318 TypeDefPrimitive::U16 => parse_quote!(::core::primitive::u16),
319 TypeDefPrimitive::U32 => parse_quote!(::core::primitive::u32),
320 TypeDefPrimitive::U64 => parse_quote!(::core::primitive::u64),
321 TypeDefPrimitive::U128 => parse_quote!(::core::primitive::u128),
322 TypeDefPrimitive::U256 => unimplemented!("not a rust primitive"),
323 TypeDefPrimitive::I8 => parse_quote!(::core::primitive::i8),
324 TypeDefPrimitive::I16 => parse_quote!(::core::primitive::i16),
325 TypeDefPrimitive::I32 => parse_quote!(::core::primitive::i32),
326 TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64),
327 TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128),
328 TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"),
329 }),
330 TypePathType::Compact {
331 inner,
332 is_field,
333 compact_type_path,
334 } => {
335 let inner = inner.to_syn_type(alloc_crate_path);
336 let path = if *is_field {
337 parse_quote! ( #inner )
340 } else {
341 parse_quote! ( #compact_type_path<#inner> )
342 };
343 syn::Type::Path(path)
344 }
345 TypePathType::BitVec {
346 bit_order_type,
347 bit_store_type,
348 decoded_bits_type_path,
349 } => {
350 let bit_order_type = bit_order_type.to_syn_type(alloc_crate_path);
351 let bit_store_type = bit_store_type.to_syn_type(alloc_crate_path);
352 let type_path =
353 parse_quote! { #decoded_bits_type_path<#bit_store_type, #bit_order_type> };
354 syn::Type::Path(type_path)
355 }
356 }
357 }
358}
359
360#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
362pub struct TypeParameter {
363 pub(super) concrete_type_id: u32,
364 pub(super) original_name: String,
365 pub(super) name: Ident,
366}
367
368impl quote::ToTokens for TypeParameter {
369 fn to_tokens(&self, tokens: &mut TokenStream) {
370 self.name.to_tokens(tokens)
371 }
372}