[go: up one dir, main page]

re_case/
lib.rs

1//! Case conversions, the way Rerun likes them.
2
3/// Converts a snake or pascal case input into a snake case output.
4///
5/// If the input contains multiple parts separated by dots, only the last part is converted.
6pub fn to_snake_case(s: &str) -> String {
7    use convert_case::{Boundary, Converter, Pattern};
8
9    let rerun_snake = Converter::new()
10        .set_boundaries(&[
11            Boundary::Hyphen,
12            Boundary::Space,
13            Boundary::Underscore,
14            Boundary::Acronym,
15            Boundary::LowerUpper,
16        ])
17        .set_pattern(Pattern::Lowercase)
18        .set_delim("_");
19
20    let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect();
21    if let Some(last) = parts.last_mut() {
22        *last = last
23            .replace("UVec", "uvec")
24            .replace("DVec", "dvec")
25            .replace("UInt", "uint");
26        *last = rerun_snake.convert(last.as_str());
27    }
28    parts.join(".")
29}
30
31#[test]
32fn test_to_snake_case() {
33    assert_eq!(
34        to_snake_case("rerun.components.Position2D"),
35        "rerun.components.position2d"
36    );
37    assert_eq!(
38        to_snake_case("rerun.components.position2d"),
39        "rerun.components.position2d"
40    );
41
42    assert_eq!(
43        to_snake_case("rerun.datatypes.Utf8"),
44        "rerun.datatypes.utf8"
45    );
46    assert_eq!(
47        to_snake_case("rerun.datatypes.utf8"),
48        "rerun.datatypes.utf8"
49    );
50
51    assert_eq!(
52        to_snake_case("rerun.datatypes.UVec2D"),
53        "rerun.datatypes.uvec2d"
54    );
55    assert_eq!(
56        to_snake_case("rerun.datatypes.uvec2d"),
57        "rerun.datatypes.uvec2d"
58    );
59
60    assert_eq!(
61        to_snake_case("rerun.datatypes.UInt32"),
62        "rerun.datatypes.uint32"
63    );
64    assert_eq!(
65        to_snake_case("rerun.datatypes.uint32"),
66        "rerun.datatypes.uint32"
67    );
68
69    assert_eq!(
70        to_snake_case("rerun.archetypes.Points2DIndicator"),
71        "rerun.archetypes.points2d_indicator"
72    );
73    assert_eq!(
74        to_snake_case("rerun.archetypes.points2d_indicator"),
75        "rerun.archetypes.points2d_indicator"
76    );
77
78    assert_eq!(
79        to_snake_case("rerun.components.TranslationAndMat3x3"),
80        "rerun.components.translation_and_mat3x3"
81    );
82    assert_eq!(
83        to_snake_case("rerun.components.translation_and_mat3x3"),
84        "rerun.components.translation_and_mat3x3"
85    );
86
87    assert_eq!(
88        to_snake_case("rerun.components.AnnotationContext"),
89        "rerun.components.annotation_context"
90    );
91}
92
93/// Converts a snake or pascal case input into a pascal case output.
94///
95/// If the input contains multiple parts separated by dots, only the last part is converted.
96pub fn to_pascal_case(s: &str) -> String {
97    use convert_case::{Boundary, Converter, Pattern};
98
99    let rerun_pascal = Converter::new()
100        .set_boundaries(&[
101            Boundary::Hyphen,
102            Boundary::Space,
103            Boundary::Underscore,
104            Boundary::DigitUpper,
105            Boundary::Acronym,
106            Boundary::LowerUpper,
107        ])
108        .set_pattern(Pattern::Capital);
109
110    let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect();
111    if let Some(last) = parts.last_mut() {
112        *last = last
113            .replace("uvec", "UVec")
114            .replace("dvec", "DVec")
115            .replace("uint", "UInt")
116            .replace("2d", "2D") // NOLINT
117            .replace("3d", "3D") // NOLINT
118            .replace("4d", "4D");
119        *last = rerun_pascal.convert(last.as_str());
120    }
121    parts.join(".")
122}
123
124#[test]
125fn test_to_pascal_case() {
126    assert_eq!(
127        to_pascal_case("rerun.components.position2d"),
128        "rerun.components.Position2D"
129    );
130    assert_eq!(
131        to_pascal_case("rerun.components.Position2D"),
132        "rerun.components.Position2D"
133    );
134
135    assert_eq!(
136        to_pascal_case("rerun.datatypes.uvec2d"),
137        "rerun.datatypes.UVec2D"
138    );
139    assert_eq!(
140        to_pascal_case("rerun.datatypes.UVec2D"),
141        "rerun.datatypes.UVec2D"
142    );
143
144    assert_eq!(
145        to_pascal_case("rerun.datatypes.uint32"),
146        "rerun.datatypes.UInt32"
147    );
148    assert_eq!(
149        to_pascal_case("rerun.datatypes.UInt32"),
150        "rerun.datatypes.UInt32"
151    );
152
153    assert_eq!(
154        to_pascal_case("rerun.archetypes.points2d_indicator"),
155        "rerun.archetypes.Points2DIndicator"
156    );
157    assert_eq!(
158        to_pascal_case("rerun.archetypes.Points2DIndicator"),
159        "rerun.archetypes.Points2DIndicator"
160    );
161
162    assert_eq!(
163        to_pascal_case("rerun.components.translation_and_mat3x3"),
164        "rerun.components.TranslationAndMat3x3"
165    );
166    assert_eq!(
167        to_pascal_case("rerun.components.TranslationAndMat3x3"),
168        "rerun.components.TranslationAndMat3x3"
169    );
170}
171
172/// Converts a snake or pascal case input into "human case" output, i.e. start with upper case and continue with lower case.
173///
174/// If the input contains multiple parts separated by dots, only the last part is converted.
175pub fn to_human_case(s: &str) -> String {
176    use convert_case::{Boundary, Converter, Pattern};
177
178    let rerun_human = Converter::new()
179        .set_boundaries(&[
180            Boundary::Hyphen,
181            Boundary::Space,
182            Boundary::Underscore,
183            Boundary::LowerDigit,
184            Boundary::Acronym,
185            Boundary::LowerUpper,
186        ])
187        .set_pattern(Pattern::Sentence)
188        .set_delim(" ");
189
190    let mut parts: Vec<_> = s.split('.').map(ToOwned::to_owned).collect();
191    if let Some(last) = parts.last_mut() {
192        *last = rerun_human.convert(last.as_str());
193        *last = last
194            .replace("Uvec", "UVec")
195            .replace("Uint", "UInt")
196            .replace("U vec", "UVec")
197            .replace("U int", "UInt")
198            .replace("Int 32", "Int32")
199            .replace("mat 3x 3", "mat3x3")
200            .replace("mat 4x 4", "mat4x4")
201            .replace("2d", "2D") // NOLINT
202            .replace("3d", "3D") // NOLINT
203            .replace("4d", "4D");
204    }
205    parts.join(".")
206}
207
208#[test]
209fn test_to_human_case() {
210    assert_eq!(
211        to_human_case("rerun.components.position2d"),
212        "rerun.components.Position 2D"
213    );
214    assert_eq!(
215        to_human_case("rerun.components.Position2D"),
216        "rerun.components.Position 2D"
217    );
218
219    assert_eq!(
220        to_human_case("rerun.datatypes.uvec2d"),
221        "rerun.datatypes.UVec 2D"
222    );
223    assert_eq!(
224        to_human_case("rerun.datatypes.UVec2D"),
225        "rerun.datatypes.UVec 2D"
226    );
227
228    assert_eq!(
229        to_human_case("rerun.datatypes.uint32"),
230        "rerun.datatypes.UInt32"
231    );
232    assert_eq!(
233        to_human_case("rerun.datatypes.UInt32"),
234        "rerun.datatypes.UInt32"
235    );
236
237    assert_eq!(
238        to_human_case("rerun.archetypes.points2d_indicator"),
239        "rerun.archetypes.Points 2D indicator"
240    );
241    assert_eq!(
242        to_human_case("rerun.archetypes.Points2DIndicator"),
243        "rerun.archetypes.Points 2D indicator"
244    );
245
246    assert_eq!(
247        to_human_case("rerun.components.translation_and_mat3x3"),
248        "rerun.components.Translation and mat3x3"
249    );
250    assert_eq!(
251        to_human_case("rerun.components.TranslationAndMat3x3"),
252        "rerun.components.Translation and mat3x3"
253    );
254}