macro_tools/typ.rs
1//!
2//! Advanced syntax elements.
3//!
4
5/// Define a private namespace for all its items.
6mod private
7{
8 #[ allow( clippy::wildcard_imports ) ]
9 use crate::*;
10 use interval_adapter::BoundExt;
11
12 /// Check is the rightmost item of path refering a type is specified type.
13 ///
14 /// Good to verify `core::option::Option< i32 >` is optional.
15 /// Good to verify `alloc::vec::Vec< i32 >` is vector.
16 ///
17 /// ### Basic use-case.
18 /// ```rust
19 /// use macro_tools::exposed::*;
20 ///
21 /// let code = qt!( core::option::Option< i32 > );
22 /// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
23 /// let got = typ::type_rightmost( &tree_type );
24 /// assert_eq!( got, Some( "Option".to_string() ) );
25 /// ```
26 /// # Panics
27 /// qqq: doc
28 #[ must_use ]
29 pub fn type_rightmost( ty : &syn::Type ) -> Option< String >
30 {
31 if let syn::Type::Path( path ) = ty
32 {
33 let last = &path.path.segments.last();
34 if last.is_none()
35 {
36 return None;
37 }
38 return Some( last.unwrap().ident.to_string() );
39 }
40 None
41 }
42
43 /// Return the specified number of parameters of the type.
44 ///
45 /// Good to getting `i32` from `core::option::Option< i32 >` or `alloc::vec::Vec< i32 >`
46 ///
47 /// ### Basic use-case.
48 /// ```
49 /// use macro_tools::{ typ, qt };
50 ///
51 /// let code = qt!( core::option::Option< i8, i16, i32, i64 > );
52 /// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
53 /// let got = typ::type_parameters( &tree_type, 0..=2 );
54 /// got.iter().for_each( | e | println!( "{}", qt!( #e ) ) );
55 /// // < i8
56 /// // < i16
57 /// // < i32
58 /// ```
59 /// # Panics
60 /// qqq: doc
61 #[ allow( clippy::cast_possible_wrap ) ]
62 pub fn type_parameters< 'a >( ty : &'a syn::Type, range : &'a impl NonIterableInterval ) -> Vec< &'a syn::Type >
63 {
64 if let syn::Type::Path( syn::TypePath{ path : syn::Path { ref segments, .. }, .. } ) = ty
65 {
66 let last = &segments.last();
67 if last.is_none()
68 {
69 return vec![ ty ]
70 }
71 let args = &last.unwrap().arguments;
72 if let syn::PathArguments::AngleBracketed( ref args2 ) = args
73 {
74 let args3 = &args2.args;
75 let left = range.left().into_left_closed();
76 let mut right = range.right().into_right_closed();
77 let len = args3.len();
78 if right == isize::MAX
79 {
80 right = len as isize;
81 }
82 // dbg!( left );
83 // dbg!( right );
84 // dbg!( len );
85 let selected : Vec< &syn::Type > = args3
86 .iter()
87 .skip_while( | e | !matches!( e, syn::GenericArgument::Type( _ ) ) )
88 .skip( usize::try_from( left.max( 0 ) ).unwrap() )
89 .take( usize::try_from( ( right - left + 1 ).min( len as isize - left ).max( 0 ) ).unwrap() )
90 .map( | e | if let syn::GenericArgument::Type( ty ) = e { ty } else { unreachable!( "Expects Type" ) } )
91 .collect();
92 return selected;
93 }
94 }
95 vec![ ty ]
96 }
97
98 /// Checks if a given [`syn::Type`] is an `Option` type.
99 ///
100 /// This function examines a type to determine if it represents an `Option`.
101 /// It is useful for scenarios where type-specific behavior needs to be conditional
102 /// on whether the type is optional or not.
103 ///
104 /// # Example
105 ///
106 /// ```rust
107 /// let type_string = "Option< i32 >";
108 /// let parsed_type : syn::Type = syn::parse_str( type_string ).expect( "Type should parse correctly" );
109 /// assert!( macro_tools::typ::is_optional( &parsed_type ) );
110 /// ```
111 ///
112 #[ must_use ]
113 pub fn is_optional( ty : &syn::Type ) -> bool
114 {
115 typ::type_rightmost( ty ) == Some( "Option".to_string() )
116 }
117
118 /// Extracts the first generic parameter from a given `syn::Type` if any exists.
119 ///
120 /// This function is designed to analyze a type and retrieve its first generic parameter.
121 /// It is particularly useful when working with complex types in macro expansions and needs
122 /// to extract specific type information for further processing.
123 ///
124///
125 /// # Example
126 /// ```rust
127 /// let type_string = "Result< Option< i32 >, Error >";
128 /// let parsed_type : syn::Type = syn::parse_str( type_string ).expect( "Type should parse correctly" );
129 /// let first_param = macro_tools::typ::parameter_first( &parsed_type ).expect( "Should have at least one parameter" );
130 /// // Option< i32 >
131 /// ```
132 /// # Errors
133 /// qqq: docs
134 pub fn parameter_first( ty : &syn::Type ) -> Result< &syn::Type >
135 {
136 typ::type_parameters( ty, &( 0 ..= 0 ) )
137 .first()
138 .copied()
139 .ok_or_else( || syn_err!( ty, "Expects at least one parameter here:\n {}", qt!{ #ty } ) )
140 }
141
142}
143
144#[ doc( inline ) ]
145#[ allow( unused_imports ) ]
146pub use own::*;
147
148/// Own namespace of the module.
149#[ allow( unused_imports ) ]
150pub mod own
151{
152 #[ allow( clippy::wildcard_imports ) ]
153 use super::*;
154 #[ doc( inline ) ]
155 pub use orphan::*;
156 #[ doc( inline ) ]
157 pub use private::
158 {
159 type_rightmost,
160 type_parameters,
161 is_optional,
162 parameter_first,
163 };
164}
165
166/// Orphan namespace of the module.
167#[ allow( unused_imports ) ]
168pub mod orphan
169{
170 #[ allow( clippy::wildcard_imports ) ]
171 use super::*;
172 #[ doc( inline ) ]
173 pub use exposed::*;
174}
175
176/// Exposed namespace of the module.
177#[ allow( unused_imports ) ]
178pub mod exposed
179{
180 #[ allow( clippy::wildcard_imports ) ]
181 use super::*;
182
183 pub use super::super::typ;
184
185 // pub use super::own as typ;
186
187 #[ doc( inline ) ]
188 pub use prelude::*;
189}
190
191/// Prelude to use essentials: `use my_module::prelude::*`.
192#[ allow( unused_imports ) ]
193pub mod prelude
194{
195 use super::*;
196}
197