use std::any::type_name;
pub(crate) fn short_type_name<T: ?Sized>() -> String {
let full_name = type_name::<T>();
let mut index: usize = 0;
let end_of_string = full_name.len();
let mut parsed_name = String::new();
while index < end_of_string {
let rest_of_string = full_name.get(index..end_of_string).unwrap_or_default();
if let Some(special_character_index) =
rest_of_string.find(|c: char| [' ', '<', '>', '(', ')', '[', ']', ',', ';'].contains(&c))
{
let segment_to_collapse = rest_of_string.get(0..special_character_index).unwrap_or_default();
parsed_name += collapse_type_name(segment_to_collapse);
let special_character = &rest_of_string[special_character_index..=special_character_index];
parsed_name.push_str(special_character);
match special_character {
">" | ")" | "]" if rest_of_string[special_character_index + 1..].starts_with("::") => {
parsed_name.push_str("::");
index += special_character_index + 3;
}
_ => index += special_character_index + 1,
}
} else {
parsed_name += collapse_type_name(rest_of_string);
index = end_of_string;
}
}
parsed_name
}
#[inline(always)]
fn collapse_type_name(string: &str) -> &str {
string.rsplit("::").next().unwrap()
}
#[cfg(test)]
mod tests {
use super::short_type_name;
use std::collections::HashMap;
#[test]
fn tests() {
assert_eq!(short_type_name::<String>(), "String");
assert_eq!(short_type_name::<Option<String>>(), "Option<String>");
assert_eq!(short_type_name::<(String, &str)>(), "(String, &str)");
assert_eq!(short_type_name::<[i32; 3]>(), "[i32; 3]");
assert_eq!(
short_type_name::<HashMap<String, Option<[i32; 3]>>>(),
"HashMap<String, Option<[i32; 3]>>"
);
assert_eq!(short_type_name::<dyn Fn(i32) -> i32>(), "dyn Fn(i32) -> i32");
}
}