code_generator/
as_case.rs

1use core::{fmt::Display, str::Chars};
2/// Performance improvement based on [https://internals.rust-lang.org/t/add-as-lowercase-et-al/15797]
3
4use crate::CaseType;
5
6pub const CASE_SEPARATOR: char = '`';
7
8pub struct Cased<'a, T: ?Sized> {
9    case_type: CaseType,
10    source: &'a T,
11}
12
13pub trait AsCase<'a> {
14    fn as_case(&'a self, case_type: CaseType) -> impl Display + 'a;
15}
16
17impl<'a> AsCase<'a> for str {
18    fn as_case(&'a self, case_type: CaseType) -> impl Display + 'a {
19        Cased {
20            case_type,
21            source: self
22        }
23    }
24}
25
26impl<'a> AsCase<'a> for String {
27    fn as_case(&self, case_type: CaseType) -> impl Display {
28        Cased {
29            case_type,
30            source: self
31        }
32    }
33}
34
35impl<'a, T: ?Sized> Cased<'a, T> {
36    fn write_first_char(case_type: CaseType, char: char, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        match case_type {
38            CaseType::FlatCase => { write!(f, "{}", char.to_lowercase()) }
39            CaseType::ScreamingCase => { write!(f, "{}", char.to_uppercase()) }
40            CaseType::CamelCase => { write!(f, "{}", char.to_lowercase()) }
41            CaseType::PascalCase => { write!(f, "{}", char.to_uppercase()) }
42            CaseType::SnakeCase => { write!(f, "{}", char.to_lowercase()) }
43            CaseType::ScreamingSnakeCase => { write!(f, "{}", char.to_uppercase()) }
44        }
45    }
46    fn write_first_char_in_chunk(case_type: CaseType, char: char, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47        match case_type {
48            CaseType::FlatCase => { write!(f, "{}", char.to_lowercase()) }
49            CaseType::ScreamingCase => { write!(f, "{}", char.to_uppercase()) }
50            CaseType::CamelCase => { write!(f, "{}", char.to_uppercase()) }
51            CaseType::PascalCase => { write!(f, "{}", char.to_uppercase()) }
52            CaseType::SnakeCase => { write!(f, "{}", char.to_lowercase()) }
53            CaseType::ScreamingSnakeCase => { write!(f, "{}", char.to_uppercase()) }
54        }
55    }
56    fn write_default_char(case_type: CaseType, char: char, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57        match case_type {
58            CaseType::FlatCase => { write!(f, "{}", char.to_lowercase()) }
59            CaseType::ScreamingCase => { write!(f, "{}", char.to_uppercase()) }
60            CaseType::CamelCase => { write!(f, "{}", char.to_lowercase()) }
61            CaseType::PascalCase => { write!(f, "{}", char.to_lowercase()) }
62            CaseType::SnakeCase => { write!(f, "{}", char.to_lowercase()) }
63            CaseType::ScreamingSnakeCase => { write!(f, "{}", char.to_uppercase()) }
64        }
65    }
66    fn write_chunk_separator(case_type: CaseType, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67        match case_type {
68            CaseType::FlatCase => { core::fmt::Result::Ok(()) }
69            CaseType::ScreamingCase => { core::fmt::Result::Ok(()) }
70            CaseType::CamelCase => { core::fmt::Result::Ok(()) }
71            CaseType::PascalCase => { core::fmt::Result::Ok(()) }
72            CaseType::SnakeCase => { write!(f, "{}", '_') }
73            CaseType::ScreamingSnakeCase => { write!(f, "{}", '_') }
74        }
75    }
76    fn casify(chars: Chars<'_>, case_type: CaseType, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77        let mut result = core::fmt::Result::Ok(());
78
79        let mut is_first_in_chunk = false;
80        let mut is_first = true;
81
82        for char in chars {
83            if char == CASE_SEPARATOR {
84                is_first_in_chunk = true;
85                continue;
86            }
87
88            if char.is_uppercase() {
89                is_first_in_chunk = true;
90            }
91
92            match (is_first, is_first_in_chunk) {
93                (true, _) => {result = result.and(Self::write_first_char(case_type, char, f));}
94                (_, true) => {
95                    result = result.and(Self::write_chunk_separator(case_type, f));
96                    result = result.and(Self::write_first_char_in_chunk(case_type, char, f));
97                }
98                (_, false) => {result = result.and(Self::write_default_char(case_type, char, f));}
99            }
100
101            is_first_in_chunk = false;
102            is_first = false;
103        }
104
105        result
106    }
107}
108
109impl<'a> Display for Cased<'a, str> {
110    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111        Self::casify(self.source.chars(), self.case_type, f)
112    }
113}
114
115impl<'a> Display for Cased<'a, String> {
116    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117        Self::casify(self.source.chars(), self.case_type, f)
118    }
119}