Skip to content

Commit 707ff23

Browse files
alice-i-cecileItsDoot
authored andcommitted
Move get_short_name utility method from bevy_reflect into bevy_utils (bevyengine#5174)
# Summary This method strips a long type name like `bevy::render::camera::PerspectiveCameraBundle` down into the bare type name (`PerspectiveCameraBundle`). This is generally useful utility method, needed by bevyengine#4299 and bevyengine#5121. As a result: - This method was moved to `bevy_utils` for easier reuse. - The legibility and robustness of this method has been significantly improved. - Harder test cases have been added. This change was split out of bevyengine#4299 to unblock it and make merging / reviewing the rest of those changes easier. ## Changelog - added `bevy_utils::get_short_name`, which strips the path from a type name for convenient display. - removed the `TypeRegistry::get_short_name` method. Use the function in `bevy_utils` instead.
1 parent f3f4a99 commit 707ff23

File tree

5 files changed

+120
-90
lines changed

5 files changed

+120
-90
lines changed

crates/bevy_reflect/src/type_registry.rs

Lines changed: 3 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl TypeRegistryArc {
231231
/// a [`TypeData`] which can be used to downcast [`Reflect`] trait objects of
232232
/// this type to trait objects of the relevant trait.
233233
///
234-
/// [short name]: TypeRegistration::get_short_name
234+
/// [short name]: bevy_utils::get_short_name
235235
/// [`TypeInfo`]: crate::TypeInfo
236236
/// [0]: crate::Reflect
237237
/// [1]: crate::Reflect
@@ -287,14 +287,14 @@ impl TypeRegistration {
287287
let type_name = std::any::type_name::<T>();
288288
Self {
289289
data: HashMap::default(),
290-
short_name: Self::get_short_name(type_name),
290+
short_name: bevy_utils::get_short_name(type_name),
291291
type_info: T::type_info(),
292292
}
293293
}
294294

295295
/// Returns the [short name] of the type.
296296
///
297-
/// [short name]: TypeRegistration::get_short_name
297+
/// [short name]: bevy_utils::get_short_name
298298
pub fn short_name(&self) -> &str {
299299
&self.short_name
300300
}
@@ -305,49 +305,6 @@ impl TypeRegistration {
305305
pub fn type_name(&self) -> &'static str {
306306
self.type_info.type_name()
307307
}
308-
309-
/// Calculates the short name of a type.
310-
///
311-
/// The short name of a type is its full name as returned by
312-
/// [`std::any::type_name`], but with the prefix of all paths removed. For
313-
/// example, the short name of `alloc::vec::Vec<core::option::Option<u32>>`
314-
/// would be `Vec<Option<u32>>`.
315-
pub fn get_short_name(full_name: &str) -> String {
316-
let mut short_name = String::new();
317-
318-
{
319-
// A typename may be a composition of several other type names (e.g. generic parameters)
320-
// separated by the characters that we try to find below.
321-
// Then, each individual typename is shortened to its last path component.
322-
//
323-
// Note: Instead of `find`, `split_inclusive` would be nice but it's still unstable...
324-
let mut remainder = full_name;
325-
while let Some(index) = remainder.find(&['<', '>', '(', ')', '[', ']', ',', ';'][..]) {
326-
let (path, new_remainder) = remainder.split_at(index);
327-
// Push the shortened path in front of the found character
328-
short_name.push_str(path.rsplit(':').next().unwrap());
329-
// Push the character that was found
330-
let character = new_remainder.chars().next().unwrap();
331-
short_name.push(character);
332-
// Advance the remainder
333-
if character == ',' || character == ';' {
334-
// A comma or semicolon is always followed by a space
335-
short_name.push(' ');
336-
remainder = &new_remainder[2..];
337-
} else {
338-
remainder = &new_remainder[1..];
339-
}
340-
}
341-
342-
// The remainder will only be non-empty if there were no matches at all
343-
if !remainder.is_empty() {
344-
// Then, the full typename is a path that has to be shortened
345-
short_name.push_str(remainder.rsplit(':').next().unwrap());
346-
}
347-
}
348-
349-
short_name
350-
}
351308
}
352309

353310
impl Clone for TypeRegistration {
@@ -459,42 +416,6 @@ mod test {
459416
use crate::TypeRegistration;
460417
use bevy_utils::HashMap;
461418

462-
#[test]
463-
fn test_get_short_name() {
464-
assert_eq!(
465-
TypeRegistration::get_short_name(std::any::type_name::<f64>()),
466-
"f64"
467-
);
468-
assert_eq!(
469-
TypeRegistration::get_short_name(std::any::type_name::<String>()),
470-
"String"
471-
);
472-
assert_eq!(
473-
TypeRegistration::get_short_name(std::any::type_name::<(u32, f64)>()),
474-
"(u32, f64)"
475-
);
476-
assert_eq!(
477-
TypeRegistration::get_short_name(std::any::type_name::<(String, String)>()),
478-
"(String, String)"
479-
);
480-
assert_eq!(
481-
TypeRegistration::get_short_name(std::any::type_name::<[f64]>()),
482-
"[f64]"
483-
);
484-
assert_eq!(
485-
TypeRegistration::get_short_name(std::any::type_name::<[String]>()),
486-
"[String]"
487-
);
488-
assert_eq!(
489-
TypeRegistration::get_short_name(std::any::type_name::<[f64; 16]>()),
490-
"[f64; 16]"
491-
);
492-
assert_eq!(
493-
TypeRegistration::get_short_name(std::any::type_name::<[String; 16]>()),
494-
"[String; 16]"
495-
);
496-
}
497-
498419
#[test]
499420
fn test_property_type_registration() {
500421
assert_eq!(

crates/bevy_utils/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub mod prelude {
44

55
pub mod futures;
66
pub mod label;
7+
mod short_names;
8+
pub use short_names::get_short_name;
79

810
mod default;
911
mod float_ord;

crates/bevy_utils/src/short_names.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/// Shortens a type name to remove all module paths.
2+
///
3+
/// The short name of a type is its full name as returned by
4+
/// [`std::any::type_name`], but with the prefix of all paths removed. For
5+
/// example, the short name of `alloc::vec::Vec<core::option::Option<u32>>`
6+
/// would be `Vec<Option<u32>>`.
7+
pub fn get_short_name(full_name: &str) -> String {
8+
// Generics result in nested paths within <..> blocks.
9+
// Consider "bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>".
10+
// To tackle this, we parse the string from left to right, collapsing as we go.
11+
let mut index: usize = 0;
12+
let end_of_string = full_name.len();
13+
let mut parsed_name = String::new();
14+
15+
while index < end_of_string {
16+
let rest_of_string = full_name.get(index..end_of_string).unwrap_or_default();
17+
18+
// Collapse everything up to the next special character,
19+
// then skip over it
20+
if let Some(special_character_index) = rest_of_string.find(|c: char| {
21+
(c == ' ')
22+
|| (c == '<')
23+
|| (c == '>')
24+
|| (c == '(')
25+
|| (c == ')')
26+
|| (c == '[')
27+
|| (c == ']')
28+
|| (c == ',')
29+
|| (c == ';')
30+
}) {
31+
let segment_to_collapse = rest_of_string
32+
.get(0..special_character_index)
33+
.unwrap_or_default();
34+
parsed_name += collapse_type_name(segment_to_collapse);
35+
// Insert the special character
36+
let special_character =
37+
&rest_of_string[special_character_index..=special_character_index];
38+
parsed_name.push_str(special_character);
39+
// Move the index just past the special character
40+
index += special_character_index + 1;
41+
} else {
42+
// If there are no special characters left, we're done!
43+
parsed_name += collapse_type_name(rest_of_string);
44+
index = end_of_string;
45+
}
46+
}
47+
parsed_name
48+
}
49+
50+
#[inline(always)]
51+
fn collapse_type_name(string: &str) -> &str {
52+
string.split("::").last().unwrap()
53+
}
54+
55+
#[cfg(test)]
56+
mod name_formatting_tests {
57+
use super::get_short_name;
58+
59+
#[test]
60+
fn trivial() {
61+
assert_eq!(get_short_name("test_system"), "test_system");
62+
}
63+
64+
#[test]
65+
fn path_seperated() {
66+
assert_eq!(
67+
get_short_name("bevy_prelude::make_fun_game"),
68+
"make_fun_game".to_string()
69+
);
70+
}
71+
72+
#[test]
73+
fn tuple_type() {
74+
assert_eq!(
75+
get_short_name("(String, String)"),
76+
"(String, String)".to_string()
77+
);
78+
}
79+
80+
#[test]
81+
fn array_type() {
82+
assert_eq!(get_short_name("[i32; 3]"), "[i32; 3]".to_string());
83+
}
84+
85+
#[test]
86+
fn trivial_generics() {
87+
assert_eq!(get_short_name("a<B>"), "a<B>".to_string());
88+
}
89+
90+
#[test]
91+
fn multiple_type_parameters() {
92+
assert_eq!(get_short_name("a<B, C>"), "a<B, C>".to_string());
93+
}
94+
95+
#[test]
96+
fn generics() {
97+
assert_eq!(
98+
get_short_name("bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>"),
99+
"extract_cameras<Camera3d>".to_string()
100+
);
101+
}
102+
103+
#[test]
104+
fn nested_generics() {
105+
assert_eq!(
106+
get_short_name("bevy::mad_science::do_mad_science<mad_science::Test<mad_science::Tube>, bavy::TypeSystemAbuse>"),
107+
"do_mad_science<Test<Tube>, TypeSystemAbuse>".to_string()
108+
);
109+
}
110+
}

tools/spancmp/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ serde = { version = "1.0", features = ["derive"] }
1212
clap = { version = "3.2", features = ["derive"] }
1313
regex = "1.5"
1414
termcolor = "1.1"
15-
bevy_reflect = { path = "../../crates/bevy_reflect", version = "0.8.0-dev" }
15+
bevy_utils = { path = "../../crates/bevy_utils", version = "0.8.0-dev" }
1616
lazy_static = "1.4"

tools/spancmp/src/pretty.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_reflect::TypeRegistration;
1+
use bevy_utils::get_short_name;
22
use lazy_static::lazy_static;
33
use regex::Regex;
44
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
@@ -206,21 +206,18 @@ lazy_static! {
206206

207207
pub fn simplify_name(name: &str) -> String {
208208
if let Some(captures) = SYSTEM_NAME.captures(name) {
209-
return format!(
210-
r#"system: name="{}""#,
211-
TypeRegistration::get_short_name(&captures[1])
212-
);
209+
return format!(r#"system: name="{}""#, get_short_name(&captures[1]));
213210
}
214211
if let Some(captures) = SYSTEM_OVERHEAD.captures(name) {
215212
return format!(
216213
r#"system overhead: name="{}""#,
217-
TypeRegistration::get_short_name(&captures[1])
214+
get_short_name(&captures[1])
218215
);
219216
}
220217
if let Some(captures) = SYSTEM_COMMANDS.captures(name) {
221218
return format!(
222219
r#"system_commands: name="{}""#,
223-
TypeRegistration::get_short_name(&captures[1])
220+
get_short_name(&captures[1])
224221
);
225222
}
226223
name.to_string()

0 commit comments

Comments
 (0)