Skip to main content

cheetah_string/cheetah_string/
traits.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::borrow::Borrow;
4use core::cmp::Ordering;
5use core::fmt::{self, Display};
6use core::hash::{Hash, Hasher};
7use core::ops::Add;
8use core::str;
9
10use super::repr::INLINE_CAPACITY;
11use super::CheetahString;
12
13#[inline]
14fn concatenate(left: &str, right: &str) -> CheetahString {
15    let len = left
16        .len()
17        .checked_add(right.len())
18        .expect("concatenated string length overflow");
19
20    if len <= INLINE_CAPACITY {
21        let mut bytes = [0; INLINE_CAPACITY];
22        bytes[..left.len()].copy_from_slice(left.as_bytes());
23        bytes[left.len()..len].copy_from_slice(right.as_bytes());
24        let value =
25            str::from_utf8(&bytes[..len]).expect("concatenating valid strings must preserve UTF-8");
26        return CheetahString::from_slice(value);
27    }
28
29    let mut value = String::with_capacity(len);
30    value.push_str(left);
31    value.push_str(right);
32    CheetahString::from_string(value)
33}
34
35impl PartialEq for CheetahString {
36    #[inline]
37    fn eq(&self, other: &Self) -> bool {
38        #[cfg(all(feature = "experimental-simd", target_arch = "x86_64"))]
39        {
40            crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
41        }
42        #[cfg(not(all(feature = "experimental-simd", target_arch = "x86_64")))]
43        {
44            self.as_str() == other.as_str()
45        }
46    }
47}
48
49impl PartialEq<str> for CheetahString {
50    #[inline]
51    fn eq(&self, other: &str) -> bool {
52        #[cfg(all(feature = "experimental-simd", target_arch = "x86_64"))]
53        {
54            crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
55        }
56        #[cfg(not(all(feature = "experimental-simd", target_arch = "x86_64")))]
57        {
58            self.as_str() == other
59        }
60    }
61}
62
63impl PartialEq<String> for CheetahString {
64    #[inline]
65    fn eq(&self, other: &String) -> bool {
66        #[cfg(all(feature = "experimental-simd", target_arch = "x86_64"))]
67        {
68            crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
69        }
70        #[cfg(not(all(feature = "experimental-simd", target_arch = "x86_64")))]
71        {
72            self.as_str() == other.as_str()
73        }
74    }
75}
76
77impl PartialEq<Vec<u8>> for CheetahString {
78    #[inline]
79    fn eq(&self, other: &Vec<u8>) -> bool {
80        self.as_bytes() == other.as_slice()
81    }
82}
83
84impl<'a> PartialEq<&'a str> for CheetahString {
85    #[inline]
86    fn eq(&self, other: &&'a str) -> bool {
87        self.as_str() == *other
88    }
89}
90
91impl PartialEq<CheetahString> for str {
92    #[inline]
93    fn eq(&self, other: &CheetahString) -> bool {
94        self == other.as_str()
95    }
96}
97
98impl PartialEq<CheetahString> for String {
99    #[inline]
100    fn eq(&self, other: &CheetahString) -> bool {
101        self.as_str() == other.as_str()
102    }
103}
104
105impl PartialEq<CheetahString> for &str {
106    #[inline]
107    fn eq(&self, other: &CheetahString) -> bool {
108        *self == other.as_str()
109    }
110}
111
112impl Eq for CheetahString {}
113
114impl PartialOrd for CheetahString {
115    #[inline]
116    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
117        Some(self.cmp(other))
118    }
119}
120
121impl Ord for CheetahString {
122    #[inline]
123    fn cmp(&self, other: &Self) -> Ordering {
124        self.as_str().cmp(other.as_str())
125    }
126}
127
128impl Hash for CheetahString {
129    #[inline]
130    fn hash<H: Hasher>(&self, state: &mut H) {
131        self.as_str().hash(state);
132    }
133}
134
135impl Display for CheetahString {
136    #[inline]
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        self.as_str().fmt(f)
139    }
140}
141
142impl fmt::Debug for CheetahString {
143    #[inline]
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        fmt::Debug::fmt(self.as_str(), f)
146    }
147}
148
149impl Borrow<str> for CheetahString {
150    #[inline]
151    fn borrow(&self) -> &str {
152        self.as_str()
153    }
154}
155
156// Add trait implementations for string concatenation
157
158impl Add<&str> for CheetahString {
159    type Output = CheetahString;
160
161    /// Concatenates a `CheetahString` with a string slice.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use cheetah_string::CheetahString;
167    ///
168    /// let s = CheetahString::from("Hello");
169    /// let result = s + " World";
170    /// assert_eq!(result, "Hello World");
171    /// ```
172    #[inline]
173    fn add(self, rhs: &str) -> Self::Output {
174        if rhs.is_empty() {
175            return self;
176        }
177
178        concatenate(self.as_str(), rhs)
179    }
180}
181
182impl Add<&CheetahString> for CheetahString {
183    type Output = CheetahString;
184
185    /// Concatenates two `CheetahString` values.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use cheetah_string::CheetahString;
191    ///
192    /// let s1 = CheetahString::from("Hello");
193    /// let s2 = CheetahString::from(" World");
194    /// let result = s1 + &s2;
195    /// assert_eq!(result, "Hello World");
196    /// ```
197    #[inline]
198    fn add(self, rhs: &CheetahString) -> Self::Output {
199        self + rhs.as_str()
200    }
201}
202
203impl Add<String> for CheetahString {
204    type Output = CheetahString;
205
206    /// Concatenates a `CheetahString` with a `String`.
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// use cheetah_string::CheetahString;
212    ///
213    /// let s = CheetahString::from("Hello");
214    /// let result = s + String::from(" World");
215    /// assert_eq!(result, "Hello World");
216    /// ```
217    #[inline]
218    fn add(self, rhs: String) -> Self::Output {
219        if rhs.is_empty() {
220            return self;
221        }
222
223        if self.is_empty() {
224            return CheetahString::from_string(rhs);
225        }
226
227        concatenate(self.as_str(), &rhs)
228    }
229}