use syn::{Type, PathArguments, GenericArgument};
pub fn map_type(ty: &Type) -> String {
match ty {
Type::Path(type_path) => {
let ident = type_path.path.segments.last().unwrap().ident.to_string();
match ident.as_str() {
"i8" | "i16" | "i32" | "i64" | "isize" |
"u8" | "u16" | "u32" | "u64" | "usize" => "int".to_string(),
"f32" | "f64" => "float".to_string(),
"bool" => "bool".to_string(),
"String" => "str".to_string(),
"PyString" => "str".to_string(),
"Py<PyString>" => "str".to_string(),
"PyAny" => "Any".to_string(),
"PyObject" => "Any".to_string(),
"PyResult" => {
extract_generic_type(type_path, 0).map_or("Any".to_string(), |inner| map_type(inner))
}
"Option" => {
extract_generic_type(type_path, 0).map_or("Any | None".to_string(), |inner| {
format!("{} | None", map_type(inner))
})
}
"Vec" => {
extract_generic_type(type_path, 0).map_or("list[Any]".to_string(), |inner| {
format!("list[{}]", map_type(inner))
})
}
"HashMap" => {
let key_type = extract_generic_type(type_path, 0);
let val_type = extract_generic_type(type_path, 1);
let key = key_type.map_or("Any".to_string(), |k| map_type(k));
let val = val_type.map_or("Any".to_string(), |v| map_type(v));
format!("dict[{}, {}]", key, val)
}
_ => ident,
}
}
Type::Reference(r) => map_type(&r.elem),
_ => "Any".to_string(),
}
}
fn extract_generic_type(type_path: &syn::TypePath, index: usize) -> Option<&Type> {
type_path.path.segments.last().and_then(|seg| {
if let PathArguments::AngleBracketed(ref generics) = seg.arguments {
generics.args.iter().filter_map(|arg| {
if let GenericArgument::Type(ty) = arg {
Some(ty)
} else {
None
}
}).nth(index)
} else {
None
}
})
}
#[cfg(test)]
mod tests{
use super::*;
#[test]
fn test_map_type(){
let ty = syn::parse_str("i32").unwrap();
let result = map_type(&ty);
assert_eq!(result, "int");
}
#[test]
fn test_map_type_with_generic(){
let ty = syn::parse_str("Vec<i32>").unwrap();
let result = map_type(&ty);
assert_eq!(result, "list[int]");
}
#[test]
fn test_map_type_with_option(){
let ty = syn::parse_str("Option<i32>").unwrap();
let result = map_type(&ty);
assert_eq!(result, "int | None");
}
#[test]
fn test_map_type_with_tuple(){
let ty = syn::parse_str("(i32, i32)").unwrap();
let result = map_type(&ty);
assert_eq!(result, "tuple[int, int]");
}
}