capitalize/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(feature = "nightly", feature(iter_intersperse))]
4#![cfg_attr(feature = "nightly", feature(doc_cfg))]
5
6// NOTE: Why mainly use iterator methods? In the end we will copy each char,
7// doing it in that way we avoid use indexing (a[b]). To avoid compiler check
8// bounds and possible panic. It must be compared with benchmarks to ensure
9// that speed is not affected or optimize that.
10
11mod iter;
12use iter::CapitalizeIterator;
13
14/// It's implemented for all types that implement [`AsRef<str>`].
15pub trait Capitalize: AsRef<str> {
16    /// First character to title case and the rest to lower case.
17    /// This means that characters like digraphs will only have
18    /// their first letter capitalized, instead of the full character.
19    ///
20    /// Behavior is like [Python's `str.capitalize`]. Also, it uses
21    /// [`char::to_uppercase`] under the hood, then read its doc.
22    /// That relies on Unicode to change to upper case.
23    ///
24    /// # Examples
25    ///
26    /// ```rust
27    /// # use capitalize::Capitalize;
28    /// assert_eq!("✨ Hello World".capitalize(), "✨ hello world");
29    /// assert_eq!("ñandu".capitalize(), "Ñandu");
30    /// assert_eq!("こんにちは世界".capitalize(), "こんにちは世界");
31    /// ```
32    ///
33    /// [Python's `str.capitalize`]: https://docs.python.org/3/library/stdtypes.html#str.capitalize
34    fn capitalize(&self) -> String;
35
36    /// Split by space into words, then for each word change the first
37    /// character to title case and the rest to lower case.
38    /// This means that characters like digraphs will only have
39    /// their first letter capitalized, instead of the full character.
40    ///
41    /// It uses [`char.to_uppercase()`] under the hood, then read its doc.
42    /// That relies on Unicode to change to upper case.
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// # use capitalize::Capitalize;
48    /// assert_eq!("✨ hello world".capitalize_words(), "✨ Hello World");
49    /// assert_eq!("ñandu".capitalize_words(), "Ñandu");
50    /// assert_eq!("こんにちは世界".capitalize_words(), "こんにちは世界");
51    /// ```
52    #[cfg(feature = "nightly")]
53    #[doc(cfg(feature = "nightly"))]
54    fn capitalize_words(&self) -> String;
55
56    /// First character to upper case and the rest will remain the same.
57    ///
58    /// It uses [`char.to_uppercase()`] under the hood, then read its doc.
59    /// That relies on Unicode to change to upper case.
60    ///
61    /// # Examples
62    ///
63    /// ```rust
64    /// # use capitalize::Capitalize;
65    /// assert_eq!("hello World".capitalize_first_only(), "Hello World");
66    /// assert_eq!("✨ hello World".capitalize_first_only(), "✨ hello World");
67    /// ```
68    fn capitalize_first_only(&self) -> String;
69
70    /// The last character to upper case and the rest will remain the same.
71    ///
72    /// It uses [`char.to_uppercase()`] under the hood, then read its doc.
73    /// That relies on Unicode to change to upper case.
74    ///
75    /// # Examples
76    ///
77    /// ```rust
78    /// # use capitalize::Capitalize;
79    /// assert_eq!("✨ Hello World".capitalize_last_only(), "✨ Hello WorlD");
80    /// assert_eq!("Hello World ✨".capitalize_last_only(), "Hello World ✨");
81    /// assert_eq!("hello world".capitalize_last_only(), "hello worlD");
82    /// ```
83    fn capitalize_last_only(&self) -> String;
84}
85
86impl<T: AsRef<str>> Capitalize for T {
87    fn capitalize(&self) -> String {
88        let string = self.as_ref();
89
90        let mut buf = String::with_capacity(string.len());
91        buf.extend(string.chars().capitalize());
92
93        return buf;
94    }
95
96    #[cfg(feature = "nightly")]
97    fn capitalize_words(&self) -> String {
98        if self.as_ref().is_empty() {
99            return String::with_capacity(0);
100        }
101        self.as_ref()
102            .split(" ")
103            .intersperse(" ")
104            .map(|item| item.chars().capitalize())
105            .flatten()
106            .collect()
107    }
108
109    fn capitalize_first_only(&self) -> String {
110        let mut chars = self.as_ref().chars();
111        let Some(first) = chars.next() else {
112            return String::with_capacity(0);
113        };
114        first.to_uppercase().chain(chars).collect()
115    }
116
117    fn capitalize_last_only(&self) -> String {
118        let mut chars = self.as_ref().chars().rev();
119        let Some(last) = chars.next() else {
120            return String::with_capacity(0);
121        };
122        last.to_uppercase().chain(chars).rev().collect()
123    }
124}
125
126#[cfg(test)]
127mod test {
128    use super::Capitalize;
129
130    #[test]
131    fn string_reference() {
132        let text = String::from("hello ✨ World");
133        let text_ref = &text;
134        assert_eq!(text_ref.capitalize(), "Hello ✨ world");
135    }
136
137    #[test]
138    fn capitalize_first_only_reference() {
139        let text = String::from("heLLo ✨ World");
140        let text_ref = &text;
141        assert_eq!(text_ref.capitalize_first_only(), "HeLLo ✨ World");
142    }
143
144    #[test]
145    fn capitalize_final_only_reference() {
146        let text = String::from("heLLo ✨ World");
147        let text_ref = &text;
148        assert_eq!(text_ref.capitalize_last_only(), "heLLo ✨ WorlD");
149    }
150}