1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//!
//! Determine kind of a container.
//!
/// Internal namespace.
pub( crate ) mod private
{
use crate::*;
// use crate::type_rightmost;
///
/// Kind of container.
///
#[ derive( Debug, PartialEq, Eq, Copy, Clone ) ]
pub enum ContainerKind
{
/// Not a container.
No,
/// Vector-like.
Vector,
/// Hash map-like.
HashMap,
/// Hash set-like.
HashSet,
}
/// Return kind of container specified by type.
///
/// Good to verify `alloc::vec::Vec< i32 >` is vector.
/// Good to verify `std::collections::HashMap< i32, i32 >` is hash map.
///
/// ### Basic use-case.
/// ```
/// use macro_tools::exposed::*;
///
/// let code = qt!( std::collections::HashMap< i32, i32 > );
/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
/// let kind = container_kind::of_type( &tree_type );
/// assert_eq!( kind, container_kind::ContainerKind::HashMap );
/// ```
pub fn of_type( ty : &syn::Type ) -> ContainerKind
{
if let syn::Type::Path( path ) = ty
{
let last = &path.path.segments.last();
if last.is_none()
{
return ContainerKind::No
}
match last.unwrap().ident.to_string().as_ref()
{
"Vec" => { return ContainerKind::Vector }
"HashMap" => { return ContainerKind::HashMap }
"HashSet" => { return ContainerKind::HashSet }
_ => { return ContainerKind::No }
}
}
ContainerKind::No
}
/// Return kind of container specified by type. Unlike [of_type] it also understand optional types.
///
/// Good to verify `Option< alloc::vec::Vec< i32 > >` is optional vector.
///
/// ### Basic use-case.
/// ```
/// use macro_tools::exposed::*;
///
/// let code = qt!( Option< std::collections::HashMap< i32, i32 > > );
/// let tree_type = syn::parse2::< syn::Type >( code ).unwrap();
/// let ( kind, optional ) = container_kind::of_optional( &tree_type );
/// assert_eq!( kind, container_kind::ContainerKind::HashMap );
/// assert_eq!( optional, true );
/// ```
pub fn of_optional( ty : &syn::Type ) -> ( ContainerKind, bool )
{
if typ::type_rightmost( ty ) == Some( "Option".to_string() )
{
let ty2 = typ::type_parameters( ty, 0 ..= 0 ).first().copied();
// inspect_type::inspect_type_of!( ty2 );
if ty2.is_none()
{
return ( ContainerKind::No, false )
}
let ty2 = ty2.unwrap();
return ( of_type( ty2 ), true )
}
( of_type( ty ), false )
}
}
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use protected::*;
/// Protected namespace of the module.
pub mod protected
{
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use super::orphan::*;
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use super::private::
{
ContainerKind,
of_type,
of_optional,
};
}
/// Orphan namespace of the module.
pub mod orphan
{
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use super::exposed::*;
}
/// Exposed namespace of the module.
pub mod exposed
{
pub use super::protected as container_kind;
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use super::prelude::*;
}
/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
}