#![allow(dead_code)]
use syn::GenericArgument;
use syn::PathArguments;
use syn::Type;
pub fn is_option(ty: &Type) -> bool {
if let Type::Path(type_path) = ty
&& let Some(segment) = type_path.path.segments.last()
{
return segment.ident == "Option";
}
false
}
pub fn is_vec(ty: &Type) -> bool {
if let Type::Path(type_path) = ty
&& let Some(segment) = type_path.path.segments.last()
{
return segment.ident == "Vec";
}
false
}
pub fn extract_inner_type(ty: &Type) -> &Type {
if let Type::Path(type_path) = ty
&& let Some(segment) = type_path.path.segments.last()
&& let PathArguments::AngleBracketed(args) = &segment.arguments
&& args.args.len() == 1
&& let GenericArgument::Type(inner_ty) = &args.args[0]
{
return inner_ty;
}
ty
}
pub fn get_type_name(ty: &Type) -> Option<String> {
if let Type::Path(type_path) = ty
&& let Some(segment) = type_path.path.segments.last()
{
return Some(segment.ident.to_string());
}
None
}
pub fn is_primitive_type(ty: &Type) -> bool {
if let Some(name) = get_type_name(ty) {
matches!(
name.as_str(),
"bool"
| "i8"
| "i16"
| "i32"
| "i64"
| "i128"
| "isize"
| "u8"
| "u16"
| "u32"
| "u64"
| "u128"
| "usize"
| "f32"
| "f64"
| "String"
| "str"
)
} else {
false
}
}
pub fn is_type_path(ty: &Type, expected: &str) -> bool {
if let Type::Path(type_path) = ty {
let path_str = quote::quote!(#type_path).to_string();
path_str == expected || path_str.ends_with(&format!("::{expected}"))
} else {
false
}
}
pub fn get_generic_args(ty: &Type) -> Vec<&Type> {
if let Type::Path(type_path) = ty
&& let Some(segment) = type_path.path.segments.last()
&& let PathArguments::AngleBracketed(args) = &segment.arguments
{
return args
.args
.iter()
.filter_map(|arg| {
if let GenericArgument::Type(ty) = arg {
Some(ty)
} else {
None
}
})
.collect();
}
vec![]
}
pub fn is_map_type(ty: &Type) -> bool {
if let Some(name) = get_type_name(ty) {
matches!(name.as_str(), "HashMap" | "BTreeMap")
} else {
false
}
}
pub fn format_type_for_codegen(ty: &Type) -> String {
quote::quote!(#ty).to_string()
}
#[cfg(test)]
mod tests {
use super::*;
use syn::parse_quote;
#[test]
fn test_is_option() {
let opt_ty: Type = parse_quote!(Option<String>);
let non_opt_ty: Type = parse_quote!(String);
assert!(is_option(&opt_ty));
assert!(!is_option(&non_opt_ty));
}
#[test]
fn test_extract_inner_type() {
let opt_ty: Type = parse_quote!(Option<String>);
let inner = extract_inner_type(&opt_ty);
assert_eq!(quote::quote!(#inner).to_string(), "String");
let vec_ty: Type = parse_quote!(Vec<i32>);
let inner = extract_inner_type(&vec_ty);
assert_eq!(quote::quote!(#inner).to_string(), "i32");
}
#[test]
fn test_is_primitive_type() {
let string_ty: Type = parse_quote!(String);
let custom_ty: Type = parse_quote!(MyCustomType);
assert!(is_primitive_type(&string_ty));
assert!(!is_primitive_type(&custom_ty));
}
}