bevy_utils/
short_names.rs1pub fn get_short_name(full_name: &str) -> String {
8 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 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 let special_character =
37 &rest_of_string[special_character_index..=special_character_index];
38 parsed_name.push_str(special_character);
39
40 match special_character {
41 ">" | ")" | "]"
42 if rest_of_string[special_character_index + 1..].starts_with("::") =>
43 {
44 parsed_name.push_str("::");
45 index += special_character_index + 3;
47 }
48 _ => index += special_character_index + 1,
50 }
51 } else {
52 parsed_name += collapse_type_name(rest_of_string);
54 index = end_of_string;
55 }
56 }
57 parsed_name
58}
59
60#[inline(always)]
61fn collapse_type_name(string: &str) -> &str {
62 let mut segments = string.rsplit("::");
65 let (last, second_last): (&str, Option<&str>) = (segments.next().unwrap(), segments.next());
66 let Some(second_last) = second_last else {
67 return last;
68 };
69
70 if second_last.starts_with(char::is_uppercase) {
71 let index = string.len() - last.len() - second_last.len() - 2;
72 &string[index..]
73 } else {
74 last
75 }
76}
77
78#[cfg(test)]
79mod name_formatting_tests {
80 use super::get_short_name;
81
82 #[test]
83 fn trivial() {
84 assert_eq!(get_short_name("test_system"), "test_system");
85 }
86
87 #[test]
88 fn path_separated() {
89 assert_eq!(
90 get_short_name("bevy_prelude::make_fun_game"),
91 "make_fun_game".to_string()
92 );
93 }
94
95 #[test]
96 fn tuple_type() {
97 assert_eq!(
98 get_short_name("(String, String)"),
99 "(String, String)".to_string()
100 );
101 }
102
103 #[test]
104 fn array_type() {
105 assert_eq!(get_short_name("[i32; 3]"), "[i32; 3]".to_string());
106 }
107
108 #[test]
109 fn trivial_generics() {
110 assert_eq!(get_short_name("a<B>"), "a<B>".to_string());
111 }
112
113 #[test]
114 fn multiple_type_parameters() {
115 assert_eq!(get_short_name("a<B, C>"), "a<B, C>".to_string());
116 }
117
118 #[test]
119 fn enums() {
120 assert_eq!(get_short_name("Option::None"), "Option::None".to_string());
121 assert_eq!(
122 get_short_name("Option::Some(2)"),
123 "Option::Some(2)".to_string()
124 );
125 assert_eq!(
126 get_short_name("bevy_render::RenderSet::Prepare"),
127 "RenderSet::Prepare".to_string()
128 );
129 }
130
131 #[test]
132 fn generics() {
133 assert_eq!(
134 get_short_name("bevy_render::camera::camera::extract_cameras<bevy_render::camera::bundle::Camera3d>"),
135 "extract_cameras<Camera3d>".to_string()
136 );
137 }
138
139 #[test]
140 fn nested_generics() {
141 assert_eq!(
142 get_short_name("bevy::mad_science::do_mad_science<mad_science::Test<mad_science::Tube>, bavy::TypeSystemAbuse>"),
143 "do_mad_science<Test<Tube>, TypeSystemAbuse>".to_string()
144 );
145 }
146
147 #[test]
148 fn sub_path_after_closing_bracket() {
149 assert_eq!(
150 get_short_name("bevy_asset::assets::Assets<bevy_scene::dynamic_scene::DynamicScene>::asset_event_system"),
151 "Assets<DynamicScene>::asset_event_system".to_string()
152 );
153 assert_eq!(
154 get_short_name("(String, String)::default"),
155 "(String, String)::default".to_string()
156 );
157 assert_eq!(
158 get_short_name("[i32; 16]::default"),
159 "[i32; 16]::default".to_string()
160 );
161 }
162}