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}