smol_bytes/str_ext.rs
1use core::fmt;
2
3use crate::{Utf8Bytes, Utf8BytesMut};
4
5/// Converts a value to shared or compact UTF-8 bytes using its [`fmt::Display`] implementation.
6///
7/// [`ToUtf8Bytes::to_utf8bytes`] returns the default shared [`Utf8Bytes`],
8/// which retains heap storage after shrinking. [`ToUtf8Bytes::to_compact_utf8bytes`]
9/// returns [`crate::compact::Utf8Bytes`], which moves short contents back to
10/// inline storage.
11///
12/// # Examples
13///
14/// ```
15/// use smol_bytes::ToUtf8Bytes;
16///
17/// assert_eq!(42.to_utf8bytes().as_str(), "42");
18/// ```
19pub trait ToUtf8Bytes {
20 /// Converts this value to the default shared [`Utf8Bytes`] using [`fmt::Display`].
21 ///
22 /// Shared results retain heap storage when they are later shortened. Use
23 /// [`ToUtf8Bytes::to_compact_utf8bytes`] when short results should use inline storage.
24 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
25 fn to_utf8bytes(&self) -> Utf8Bytes;
26
27 /// Converts this value to compact [`crate::compact::Utf8Bytes`] using [`fmt::Display`].
28 ///
29 /// Compact results use inline storage when their contents fit. Use
30 /// [`ToUtf8Bytes::to_utf8bytes`] when retaining heap storage after shrinking is preferred.
31 ///
32 /// # Examples
33 ///
34 /// ```
35 /// use smol_bytes::{ToUtf8Bytes, compact};
36 ///
37 /// let value: compact::Utf8Bytes = 42.to_compact_utf8bytes();
38 /// assert_eq!(value.as_str(), "42");
39 /// ```
40 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
41 fn to_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes;
42}
43
44impl<T> ToUtf8Bytes for T
45where
46 T: fmt::Display + ?Sized,
47{
48 fn to_utf8bytes(&self) -> Utf8Bytes {
49 let mut value = Utf8BytesMut::new();
50 fmt::Write::write_fmt(&mut value, format_args!("{self}"))
51 .expect("a formatting trait implementation returned an error");
52 value.freeze_shared()
53 }
54
55 fn to_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes {
56 let mut value = Utf8BytesMut::new();
57 fmt::Write::write_fmt(&mut value, format_args!("{self}"))
58 .expect("a formatting trait implementation returned an error");
59 value.freeze_compact()
60 }
61}
62
63/// [`str`] methods that return default shared or compact UTF-8 bytes.
64///
65/// Methods ending in `_utf8bytes` return the default shared [`Utf8Bytes`],
66/// retaining heap storage after shrinking. Their `_compact_utf8bytes`
67/// counterparts return [`crate::compact::Utf8Bytes`], which use inline storage
68/// whenever their contents fit.
69///
70/// This trait is sealed and can only be implemented for [`str`] by this crate.
71pub trait StrExt: private::Sealed {
72 /// Returns the lowercase equivalent as the default shared [`Utf8Bytes`].
73 ///
74 /// Shared results retain heap storage when they are later shortened. Use
75 /// [`StrExt::to_lowercase_compact_utf8bytes`] when short results should use inline storage.
76 ///
77 /// See [`str::to_lowercase`].
78 ///
79 /// # Examples
80 ///
81 /// ```
82 /// use smol_bytes::StrExt;
83 ///
84 /// assert_eq!("RÜST".to_lowercase_utf8bytes().as_str(), "rüst");
85 /// ```
86 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
87 fn to_lowercase_utf8bytes(&self) -> Utf8Bytes;
88
89 /// Returns the lowercase equivalent as compact [`crate::compact::Utf8Bytes`].
90 ///
91 /// Compact results use inline storage when their contents fit. Use
92 /// [`StrExt::to_lowercase_utf8bytes`] when retaining heap storage after shrinking is preferred.
93 ///
94 /// See [`str::to_lowercase`].
95 ///
96 /// # Examples
97 ///
98 /// ```
99 /// use smol_bytes::StrExt;
100 ///
101 /// assert_eq!("RÜST".to_lowercase_compact_utf8bytes().as_str(), "rüst");
102 /// ```
103 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
104 fn to_lowercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes;
105
106 /// Returns the uppercase equivalent as the default shared [`Utf8Bytes`].
107 ///
108 /// Shared results retain heap storage when they are later shortened. Use
109 /// [`StrExt::to_uppercase_compact_utf8bytes`] when short results should use inline storage.
110 ///
111 /// See [`str::to_uppercase`].
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use smol_bytes::StrExt;
117 ///
118 /// assert_eq!("straße".to_uppercase_utf8bytes().as_str(), "STRASSE");
119 /// ```
120 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
121 fn to_uppercase_utf8bytes(&self) -> Utf8Bytes;
122
123 /// Returns the uppercase equivalent as compact [`crate::compact::Utf8Bytes`].
124 ///
125 /// Compact results use inline storage when their contents fit. Use
126 /// [`StrExt::to_uppercase_utf8bytes`] when retaining heap storage after shrinking is preferred.
127 ///
128 /// See [`str::to_uppercase`].
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use smol_bytes::StrExt;
134 ///
135 /// assert_eq!("straße".to_uppercase_compact_utf8bytes().as_str(), "STRASSE");
136 /// ```
137 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
138 fn to_uppercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes;
139
140 /// Returns the ASCII lowercase equivalent as the default shared [`Utf8Bytes`].
141 ///
142 /// Shared results retain heap storage when they are later shortened. Use
143 /// [`StrExt::to_ascii_lowercase_compact_utf8bytes`] when short results should use inline
144 /// storage.
145 ///
146 /// See [`str::to_ascii_lowercase`].
147 ///
148 /// # Examples
149 ///
150 /// ```
151 /// use smol_bytes::StrExt;
152 ///
153 /// assert_eq!("RuSt".to_ascii_lowercase_utf8bytes().as_str(), "rust");
154 /// ```
155 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
156 fn to_ascii_lowercase_utf8bytes(&self) -> Utf8Bytes;
157
158 /// Returns the ASCII lowercase equivalent as compact [`crate::compact::Utf8Bytes`].
159 ///
160 /// Compact results use inline storage when their contents fit. Use
161 /// [`StrExt::to_ascii_lowercase_utf8bytes`] when retaining heap storage after shrinking is
162 /// preferred.
163 ///
164 /// See [`str::to_ascii_lowercase`].
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// use smol_bytes::StrExt;
170 ///
171 /// assert_eq!("RuSt".to_ascii_lowercase_compact_utf8bytes().as_str(), "rust");
172 /// ```
173 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
174 fn to_ascii_lowercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes;
175
176 /// Returns the ASCII uppercase equivalent as the default shared [`Utf8Bytes`].
177 ///
178 /// Shared results retain heap storage when they are later shortened. Use
179 /// [`StrExt::to_ascii_uppercase_compact_utf8bytes`] when short results should use inline
180 /// storage.
181 ///
182 /// See [`str::to_ascii_uppercase`].
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use smol_bytes::StrExt;
188 ///
189 /// assert_eq!("RuSt".to_ascii_uppercase_utf8bytes().as_str(), "RUST");
190 /// ```
191 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
192 fn to_ascii_uppercase_utf8bytes(&self) -> Utf8Bytes;
193
194 /// Returns the ASCII uppercase equivalent as compact [`crate::compact::Utf8Bytes`].
195 ///
196 /// Compact results use inline storage when their contents fit. Use
197 /// [`StrExt::to_ascii_uppercase_utf8bytes`] when retaining heap storage after shrinking is
198 /// preferred.
199 ///
200 /// See [`str::to_ascii_uppercase`].
201 ///
202 /// # Examples
203 ///
204 /// ```
205 /// use smol_bytes::StrExt;
206 ///
207 /// assert_eq!("RuSt".to_ascii_uppercase_compact_utf8bytes().as_str(), "RUST");
208 /// ```
209 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
210 fn to_ascii_uppercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes;
211
212 /// Replaces every match of `from` with `to`, returning default shared [`Utf8Bytes`].
213 ///
214 /// Shared results retain heap storage when they are later shortened. Use
215 /// [`StrExt::replace_compact_utf8bytes`] when short results should use inline storage.
216 ///
217 /// See [`str::replace`].
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// use smol_bytes::StrExt;
223 ///
224 /// assert_eq!("one one".replace_utf8bytes("one", "two").as_str(), "two two");
225 /// ```
226 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
227 fn replace_utf8bytes(&self, from: &str, to: &str) -> Utf8Bytes;
228
229 /// Replaces every match of `from` with `to`, returning compact [`crate::compact::Utf8Bytes`].
230 ///
231 /// Compact results use inline storage when their contents fit. Use
232 /// [`StrExt::replace_utf8bytes`] when retaining heap storage after shrinking is preferred.
233 ///
234 /// See [`str::replace`].
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use smol_bytes::StrExt;
240 ///
241 /// assert_eq!(
242 /// "one one".replace_compact_utf8bytes("one", "two").as_str(),
243 /// "two two",
244 /// );
245 /// ```
246 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
247 fn replace_compact_utf8bytes(&self, from: &str, to: &str) -> crate::compact::Utf8Bytes;
248
249 /// Replaces at most `count` matches of `from` with `to`, returning default shared
250 /// [`Utf8Bytes`].
251 ///
252 /// Shared results retain heap storage when they are later shortened. Use
253 /// [`StrExt::replacen_compact_utf8bytes`] when short results should use inline storage.
254 ///
255 /// See [`str::replacen`].
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use smol_bytes::StrExt;
261 ///
262 /// assert_eq!(
263 /// "one one".replacen_utf8bytes("one", "two", 1).as_str(),
264 /// "two one",
265 /// );
266 /// ```
267 #[must_use = "this returns a new Utf8Bytes without modifying the original"]
268 fn replacen_utf8bytes(&self, from: &str, to: &str, count: usize) -> Utf8Bytes;
269
270 /// Replaces at most `count` matches of `from` with `to`, returning compact
271 /// [`crate::compact::Utf8Bytes`].
272 ///
273 /// Compact results use inline storage when their contents fit. Use
274 /// [`StrExt::replacen_utf8bytes`] when retaining heap storage after shrinking is preferred.
275 ///
276 /// See [`str::replacen`].
277 ///
278 /// # Examples
279 ///
280 /// ```
281 /// use smol_bytes::StrExt;
282 ///
283 /// assert_eq!(
284 /// "one one".replacen_compact_utf8bytes("one", "two", 1).as_str(),
285 /// "two one",
286 /// );
287 /// ```
288 #[must_use = "this returns a new compact Utf8Bytes without modifying the original"]
289 fn replacen_compact_utf8bytes(
290 &self,
291 from: &str,
292 to: &str,
293 count: usize,
294 ) -> crate::compact::Utf8Bytes;
295}
296
297impl StrExt for str {
298 #[inline]
299 fn to_lowercase_utf8bytes(&self) -> Utf8Bytes {
300 self.to_lowercase().into()
301 }
302
303 #[inline]
304 fn to_lowercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes {
305 self.to_lowercase().into()
306 }
307
308 #[inline]
309 fn to_uppercase_utf8bytes(&self) -> Utf8Bytes {
310 self.to_uppercase().into()
311 }
312
313 #[inline]
314 fn to_uppercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes {
315 self.to_uppercase().into()
316 }
317
318 #[inline]
319 fn to_ascii_lowercase_utf8bytes(&self) -> Utf8Bytes {
320 self.to_ascii_lowercase().into()
321 }
322
323 #[inline]
324 fn to_ascii_lowercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes {
325 self.to_ascii_lowercase().into()
326 }
327
328 #[inline]
329 fn to_ascii_uppercase_utf8bytes(&self) -> Utf8Bytes {
330 self.to_ascii_uppercase().into()
331 }
332
333 #[inline]
334 fn to_ascii_uppercase_compact_utf8bytes(&self) -> crate::compact::Utf8Bytes {
335 self.to_ascii_uppercase().into()
336 }
337
338 #[inline]
339 fn replace_utf8bytes(&self, from: &str, to: &str) -> Utf8Bytes {
340 self.replace(from, to).into()
341 }
342
343 #[inline]
344 fn replace_compact_utf8bytes(&self, from: &str, to: &str) -> crate::compact::Utf8Bytes {
345 self.replace(from, to).into()
346 }
347
348 #[inline]
349 fn replacen_utf8bytes(&self, from: &str, to: &str, count: usize) -> Utf8Bytes {
350 self.replacen(from, to, count).into()
351 }
352
353 #[inline]
354 fn replacen_compact_utf8bytes(
355 &self,
356 from: &str,
357 to: &str,
358 count: usize,
359 ) -> crate::compact::Utf8Bytes {
360 self.replacen(from, to, count).into()
361 }
362}
363
364mod private {
365 pub trait Sealed {}
366
367 impl Sealed for str {}
368}