Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Move get_short_name utility method from bevy_reflect into bevy_utils #5174

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 3 additions & 82 deletions crates/bevy_reflect/src/type_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ impl TypeRegistryArc {
/// a [`TypeData`] which can be used to downcast [`Reflect`] trait objects of
/// this type to trait objects of the relevant trait.
///
/// [short name]: TypeRegistration::get_short_name
/// [short name]: bevy_utils::get_short_name
/// [`TypeInfo`]: crate::TypeInfo
/// [0]: crate::Reflect
/// [1]: crate::Reflect
Expand Down Expand Up @@ -287,14 +287,14 @@ impl TypeRegistration {
let type_name = std::any::type_name::<T>();
Self {
data: HashMap::default(),
short_name: Self::get_short_name(type_name),
short_name: bevy_utils::get_short_name(type_name),
type_info: T::type_info(),
}
}

/// Returns the [short name] of the type.
///
/// [short name]: TypeRegistration::get_short_name
/// [short name]: bevy_utils::get_short_name
pub fn short_name(&self) -> &str {
&self.short_name
}
Expand All @@ -305,49 +305,6 @@ impl TypeRegistration {
pub fn type_name(&self) -> &'static str {
self.type_info.type_name()
}

/// Calculates the short name of a type.
///
/// 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<core::option::Option<u32>>`
/// would be `Vec<Option<u32>>`.
pub fn get_short_name(full_name: &str) -> String {
let mut short_name = String::new();

{
// A typename may be a composition of several other type names (e.g. generic parameters)
// separated by the characters that we try to find below.
// Then, each individual typename is shortened to its last path component.
//
// Note: Instead of `find`, `split_inclusive` would be nice but it's still unstable...
let mut remainder = full_name;
while let Some(index) = remainder.find(&['<', '>', '(', ')', '[', ']', ',', ';'][..]) {
let (path, new_remainder) = remainder.split_at(index);
// Push the shortened path in front of the found character
short_name.push_str(path.rsplit(':').next().unwrap());
// Push the character that was found
let character = new_remainder.chars().next().unwrap();
short_name.push(character);
// Advance the remainder
if character == ',' || character == ';' {
// A comma or semicolon is always followed by a space
short_name.push(' ');
remainder = &new_remainder[2..];
} else {
remainder = &new_remainder[1..];
}
}

// The remainder will only be non-empty if there were no matches at all
if !remainder.is_empty() {
// Then, the full typename is a path that has to be shortened
short_name.push_str(remainder.rsplit(':').next().unwrap());
}
}

short_name
}
}

impl Clone for TypeRegistration {
Expand Down Expand Up @@ -459,42 +416,6 @@ mod test {
use crate::TypeRegistration;
use bevy_utils::HashMap;

#[test]
fn test_get_short_name() {
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<f64>()),
"f64"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<String>()),
"String"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<(u32, f64)>()),
"(u32, f64)"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<(String, String)>()),
"(String, String)"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[f64]>()),
"[f64]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[String]>()),
"[String]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[f64; 16]>()),
"[f64; 16]"
);
assert_eq!(
TypeRegistration::get_short_name(std::any::type_name::<[String; 16]>()),
"[String; 16]"
);
}

#[test]
fn test_property_type_registration() {
assert_eq!(
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub mod prelude {

pub mod futures;
pub mod label;
mod short_names;
pub use short_names::get_short_name;

mod default;
mod float_ord;
Expand Down
110 changes: 110 additions & 0 deletions crates/bevy_utils/src/short_names.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/// Shortens a type name to remove 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<core::option::Option<u32>>`
/// would be `Vec<Option<u32>>`.
pub fn get_short_name(full_name: &str) -> String {
// Generics result in nested paths within <..> blocks.
// Consider "bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>".
// 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| {
(c == ' ')
|| (c == '<')
|| (c == '>')
|| (c == '(')
|| (c == ')')
|| (c == '[')
|| (c == ']')
|| (c == ',')
|| (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);
// 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.split("::").last().unwrap()
}

#[cfg(test)]
mod name_formatting_tests {
use super::get_short_name;

#[test]
fn trivial() {
assert_eq!(get_short_name("test_system"), "test_system");
}

#[test]
fn path_seperated() {
assert_eq!(
get_short_name("bevy_prelude::make_fun_game"),
"make_fun_game".to_string()
);
}

#[test]
fn tuple_type() {
assert_eq!(
get_short_name("(String, String)"),
"(String, String)".to_string()
);
}

#[test]
fn array_type() {
assert_eq!(get_short_name("[i32; 3]"), "[i32; 3]".to_string());
}

#[test]
fn trivial_generics() {
assert_eq!(get_short_name("a<B>"), "a<B>".to_string());
}

#[test]
fn multiple_type_parameters() {
assert_eq!(get_short_name("a<B, C>"), "a<B, C>".to_string());
}

#[test]
fn generics() {
assert_eq!(
get_short_name("bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>"),
"extract_cameras<Camera3d>".to_string()
);
}

#[test]
fn nested_generics() {
assert_eq!(
get_short_name("bevy::mad_science::do_mad_science<mad_science::Test<mad_science::Tube>, bavy::TypeSystemAbuse>"),
"do_mad_science<Test<Tube>, TypeSystemAbuse>".to_string()
);
}
}
2 changes: 1 addition & 1 deletion tools/spancmp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ serde = { version = "1.0", features = ["derive"] }
clap = { version = "3.2", features = ["derive"] }
regex = "1.5"
termcolor = "1.1"
bevy_reflect = { path = "../../crates/bevy_reflect", version = "0.8.0-dev" }
bevy_utils = { path = "../../crates/bevy_utils", version = "0.8.0-dev" }
lazy_static = "1.4"
11 changes: 4 additions & 7 deletions tools/spancmp/src/pretty.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy_reflect::TypeRegistration;
use bevy_utils::get_short_name;
use lazy_static::lazy_static;
use regex::Regex;
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
Expand Down Expand Up @@ -206,21 +206,18 @@ lazy_static! {

pub fn simplify_name(name: &str) -> String {
if let Some(captures) = SYSTEM_NAME.captures(name) {
return format!(
r#"system: name="{}""#,
TypeRegistration::get_short_name(&captures[1])
);
return format!(r#"system: name="{}""#, get_short_name(&captures[1]));
}
if let Some(captures) = SYSTEM_OVERHEAD.captures(name) {
return format!(
r#"system overhead: name="{}""#,
TypeRegistration::get_short_name(&captures[1])
get_short_name(&captures[1])
);
}
if let Some(captures) = SYSTEM_COMMANDS.captures(name) {
return format!(
r#"system_commands: name="{}""#,
TypeRegistration::get_short_name(&captures[1])
get_short_name(&captures[1])
);
}
name.to_string()
Expand Down