Skip to main content

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}