1use crate::intern;
2
3#[inline]
4pub fn intern_kv_pair(name: &'static str, value: &'static str) -> &'static str {
5 crate::intern_str_cache!(name, value)
6}
7
8#[inline]
9pub fn short_type_name<T: ?Sized>() -> String {
10 let full = std::any::type_name::<T>();
15 let mut out = String::with_capacity(full.len());
16 let mut segment_start = 0usize;
17 for (i, c) in full.char_indices() {
18 if matches!(c, '<' | '>' | ',' | ' ') {
19 out.push_str(strip_path(&full[segment_start..i]));
20 out.push(c);
21 segment_start = i + c.len_utf8();
22 }
23 }
24
25 if segment_start < full.len() {
26 out.push_str(strip_path(&full[segment_start..]));
27 }
28
29 out
30}
31
32fn strip_path(segment: &str) -> &str {
33 match segment.rfind("::") {
34 Some(idx) => &segment[idx + 2..],
35 None => segment,
36 }
37}
38
39pub trait ToSnakeCase<O> {
40 fn to_snake_case(&self) -> O;
41}
42
43impl ToSnakeCase<String> for &'_ str {
44 fn to_snake_case(&self) -> String {
45 if self
46 .chars()
47 .all(|c| c.is_uppercase() || c.is_ascii_digit() || c == '_')
48 {
49 return self.to_string();
50 }
51
52 let mut snake_case = String::new();
53
54 for (i, c) in self.chars().enumerate() {
55 if c.is_uppercase() {
56 if i != 0 {
57 snake_case.push('_');
58 }
59 for lower_c in c.to_lowercase() {
60 snake_case.push(lower_c);
61 }
62 } else {
63 snake_case.push(c);
64 }
65 }
66 snake_case
67 }
68}
69
70impl ToSnakeCase<String> for String {
71 fn to_snake_case(&self) -> String {
72 if self
73 .chars()
74 .all(|c| c.is_uppercase() || c.is_ascii_digit() || c == '_')
75 {
76 return self.to_string();
77 }
78
79 let mut snake_case = String::new();
80
81 for (i, c) in self.chars().enumerate() {
82 if c.is_uppercase() {
83 if i != 0 {
84 snake_case.push('_');
85 }
86 for lower_c in c.to_lowercase() {
87 snake_case.push(lower_c);
88 }
89 } else {
90 snake_case.push(c);
91 }
92 }
93 snake_case
94 }
95}