macro_tools/typ.rs
1//!
2//! Advanced syntax elements.
3//!
4
5/// Define a private namespace for all its items.
6mod private
7{
8
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, clippy ::needless_pass_by_value ) ]
62 pub fn type_parameters(ty: &syn ::Type, range: impl NonIterableInterval) -> Vec< &syn ::Type >
63 {
64 if let syn ::Type ::Path(syn ::TypePath
65 {
66 path: syn ::Path { ref segments, .. },
67 ..
68 }) = ty
69 {
70 let last = &segments.last();
71 if last.is_none()
72 {
73 return vec![ty];
74 }
75 let args = &last.unwrap().arguments;
76 if let syn ::PathArguments ::AngleBracketed(ref args2) = args
77 {
78 let args3 = &args2.args;
79 let left = range.left().into_left_closed();
80 let mut right = range.right().into_right_closed();
81 let len = args3.len();
82 if right == isize ::MAX
83 {
84 right = len as isize;
85 }
86 // dbg!( left );
87 // dbg!( right );
88 // dbg!( len );
89 let selected: Vec< &syn ::Type > = args3
90 .iter()
91 .skip_while(|e| !matches!(e, syn ::GenericArgument ::Type(_)))
92 .skip(usize ::try_from(left.max(0)).unwrap())
93 .take(usize ::try_from((right - left + 1).min(len as isize - left).max(0)).unwrap())
94 .map(|e| {
95 if let syn ::GenericArgument ::Type(ty) = e
96 {
97 ty
98 } else {
99 unreachable!("Expects Type")
100 }
101 })
102 .collect();
103 return selected;
104 }
105 }
106 vec![ty]
107 }
108
109 /// Checks if a given [`syn ::Type`] is an `Option` type.
110 ///
111 /// This function examines a type to determine if it represents an `Option`.
112 /// It is useful for scenarios where type-specific behavior needs to be conditional
113 /// on whether the type is optional or not.
114 ///
115 /// # Example
116 ///
117 /// ```rust
118 /// let type_string = "Option< i32 >";
119 /// let parsed_type: syn ::Type = syn ::parse_str( type_string ).expect( "Type should parse correctly" );
120 /// assert!( macro_tools ::typ ::is_optional( &parsed_type ) );
121 /// ```
122 ///
123 #[ must_use ]
124 pub fn is_optional(ty: &syn ::Type) -> bool
125 {
126 typ ::type_rightmost(ty) == Some("Option".to_string())
127 }
128
129 /// Extracts the first generic parameter from a given `syn ::Type` if any exists.
130 ///
131 /// This function is designed to analyze a type and retrieve its first generic parameter.
132 /// It is particularly useful when working with complex types in macro expansions and needs
133 /// to extract specific type information for further processing.
134 ///
135 ///
136 /// # Example
137 /// ```rust
138 /// let type_string = "Result< Option< i32 >, Error >";
139 /// let parsed_type: syn ::Type = syn ::parse_str( type_string ).expect( "Type should parse correctly" );
140 /// let first_param = macro_tools ::typ ::parameter_first( &parsed_type ).expect( "Should have at least one parameter" );
141 /// // Option< i32 >
142 /// ```
143 /// # Errors
144 /// qqq: docs
145 pub fn parameter_first(ty: &syn ::Type) -> Result< &syn ::Type >
146 {
147 typ ::type_parameters(ty, 0..=0)
148 .first()
149 .copied()
150 .ok_or_else(|| syn_err!(ty, "Expects at least one parameter here: \n {}", qt! { #ty }))
151 }
152}
153
154#[ doc( inline ) ]
155#[ allow( unused_imports ) ]
156pub use own :: *;
157
158/// Own namespace of the module.
159#[ allow( unused_imports ) ]
160pub mod own
161{
162
163 use super :: *;
164 #[ doc( inline ) ]
165 pub use orphan :: *;
166 #[ doc( inline ) ]
167 pub use private :: { type_rightmost, type_parameters, is_optional, parameter_first };
168}
169
170/// Orphan namespace of the module.
171#[ allow( unused_imports ) ]
172pub mod orphan
173{
174
175 use super :: *;
176 #[ doc( inline ) ]
177 pub use exposed :: *;
178}
179
180/// Exposed namespace of the module.
181#[ allow( unused_imports ) ]
182pub mod exposed
183{
184
185 use super :: *;
186
187 pub use super ::super ::typ;
188
189 // pub use super ::own as typ;
190
191 #[ doc( inline ) ]
192 pub use prelude :: *;
193}
194
195/// Prelude to use essentials: `use my_module ::prelude :: *`.
196#[ allow( unused_imports ) ]
197pub mod prelude
198{
199 use super :: *;
200}