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