From 2efc637ab95d8b52f758dd8b7f4eb3324263ed51 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Thu, 25 May 2023 10:23:52 +0100 Subject: [PATCH] Move util into mod and add `short_type_name` function --- src/userdata_impl.rs | 9 ++-- src/{util.rs => util/mod.rs} | 4 ++ src/util/short_names.rs | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) rename src/{util.rs => util/mod.rs} (99%) create mode 100644 src/util/short_names.rs diff --git a/src/userdata_impl.rs b/src/userdata_impl.rs index d143631..7f140ac 100644 --- a/src/userdata_impl.rs +++ b/src/userdata_impl.rs @@ -1,4 +1,4 @@ -use std::any::{self, TypeId}; +use std::any::TypeId; use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; use std::string::String as StdString; @@ -10,7 +10,7 @@ use crate::types::{Callback, MaybeSend}; use crate::userdata::{ AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods, }; -use crate::util::{check_stack, get_userdata, StackGuard}; +use crate::util::{check_stack, get_userdata, short_type_name, StackGuard}; use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Value}; #[cfg(not(feature = "send"))] @@ -363,9 +363,8 @@ impl<'lua, T: 'static> UserDataRegistrar<'lua, T> { } // Returns function name for the type `T`, without the module path -fn get_function_name(name: &str) -> StdString { - let type_name = any::type_name::().rsplit("::").next().unwrap(); - format!("{type_name}.{name}",) +fn get_function_name(name: &str) -> StdString { + format!("{}.{name}", short_type_name::()) } impl<'lua, T: 'static> UserDataFields<'lua, T> for UserDataRegistrar<'lua, T> { diff --git a/src/util.rs b/src/util/mod.rs similarity index 99% rename from src/util.rs rename to src/util/mod.rs index 690a9e1..394ce34 100644 --- a/src/util.rs +++ b/src/util/mod.rs @@ -13,6 +13,8 @@ use rustc_hash::FxHashMap; use crate::error::{Error, Result}; use crate::memory::MemoryState; +pub(crate) use short_names::short_type_name; + static METATABLE_CACHE: Lazy> = Lazy::new(|| { let mut map = FxHashMap::with_capacity_and_hasher(32, Default::default()); crate::lua::init_metatable_cache(&mut map); @@ -1066,3 +1068,5 @@ static DESTRUCTED_USERDATA_METATABLE: u8 = 0; static ERROR_PRINT_BUFFER_KEY: u8 = 0; static USERDATA_METATABLE_INDEX: u8 = 0; static USERDATA_METATABLE_NEWINDEX: u8 = 0; + +mod short_names; diff --git a/src/util/short_names.rs b/src/util/short_names.rs new file mode 100644 index 0000000..a50c2bf --- /dev/null +++ b/src/util/short_names.rs @@ -0,0 +1,84 @@ +//! Mostly copied from bevy_utils +//! https://github.com/bevyengine/bevy/blob/main/crates/bevy_utils/src/short_names.rs + +use std::any::type_name; + +/// Returns a short version of a type name `T` without all module paths. +/// +/// The short name of a type is its full name as returned by +/// [`std::any::type_name`], but with the prefix of all paths removed. For +/// example, the short name of `alloc::vec::Vec>` +/// would be `Vec>`. +pub(crate) fn short_type_name() -> String { + let full_name = type_name::(); + + // Generics result in nested paths within <..> blocks. + // Consider "core::option::Option". + // To tackle this, we parse the string from left to right, collapsing as we go. + 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(); + + // Collapse everything up to the next special character, + // then skip over it + 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); + // Insert the special character + 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("::"); + // Move the index past the "::" + index += special_character_index + 3; + } + // Move the index just past the special character + _ => index += special_character_index + 1, + } + } else { + // If there are no special characters left, we're done! + 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"); + assert_eq!(short_type_name::>(), "Option"); + assert_eq!(short_type_name::<(String, &str)>(), "(String, &str)"); + assert_eq!(short_type_name::<[i32; 3]>(), "[i32; 3]"); + assert_eq!( + short_type_name::>>(), + "HashMap>" + ); + assert_eq!( + short_type_name:: i32>(), + "dyn Fn(i32) -> i32" + ); + } +}