1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum CaseMode {
6 Preserve,
8 Lower,
10 Upper,
12 Title,
17 Capitalize,
20}
21
22#[must_use]
24pub fn apply(input: &str, mode: CaseMode) -> String {
25 match mode {
26 CaseMode::Preserve => input.to_string(),
27 CaseMode::Lower => input.to_lowercase(),
28 CaseMode::Upper => input.to_uppercase(),
29 CaseMode::Title | CaseMode::Capitalize => title_case(input),
30 }
31}
32
33fn title_case(input: &str) -> String {
34 let mut out = String::with_capacity(input.len());
35 let mut at_word_start = true;
36 for c in input.chars() {
37 if !c.is_ascii_alphanumeric() {
38 out.push(c);
39 at_word_start = true;
40 continue;
41 }
42 if at_word_start {
43 for u in c.to_uppercase() {
44 out.push(u);
45 }
46 at_word_start = false;
47 } else {
48 for l in c.to_lowercase() {
49 out.push(l);
50 }
51 }
52 }
53 out
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn preserve_unchanged() {
62 assert_eq!(apply("Hello-World", CaseMode::Preserve), "Hello-World");
63 }
64
65 #[test]
66 fn lower_lowercases() {
67 assert_eq!(apply("Hello-World", CaseMode::Lower), "hello-world");
68 }
69
70 #[test]
71 fn upper_uppercases() {
72 assert_eq!(apply("Hello-World", CaseMode::Upper), "HELLO-WORLD");
73 }
74
75 #[test]
76 fn title_capitalizes_each_word() {
77 assert_eq!(apply("hello-world", CaseMode::Title), "Hello-World");
78 }
79
80 #[test]
81 fn capitalize_same_as_title() {
82 assert_eq!(
83 apply("hello-world", CaseMode::Capitalize),
84 apply("hello-world", CaseMode::Title)
85 );
86 }
87
88 #[test]
89 fn title_case_lowercases_non_first_chars() {
90 assert_eq!(apply("HELLO WORLD", CaseMode::Title), "Hello World");
91 }
92}