mut_str/
traits.rs

1use core::ops::RangeBounds;
2
3use crate::{
4    char_slice, char_slice_mut, char_split_at, char_split_at_mut, copy_to,
5    errors::{LenNotEqual, ReplaceWithPadCharError, ReplaceWithPadError, ReplacementTooLong},
6    iter::{CharMutRefs, CharRefs},
7    replace, replace_with_pad, replace_with_pad_char, replace_with_pad_left,
8    replace_with_pad_left_char, replace_with_pad_left_space, replace_with_pad_space, Char,
9};
10
11/// The `StrExt` trait adds some methods to string types, many of which operate on character indexes and with character references.
12///
13/// To use its methods, import it with a use statement.
14/// ```
15/// use mut_str::StrExt;
16/// ```
17pub trait StrExt {
18    /// The output string type for string operations.
19    type Output: ?Sized;
20    /// The iterator type for iterating over [`Char`] references.
21    type Iter<'a>: Iterator<Item = &'a Char>
22    where
23        Self: 'a;
24    /// The iterator type for iterating over mutable [`Char`] references.
25    type IterMut<'a>: Iterator<Item = &'a mut Char>
26    where
27        Self: 'a;
28
29    #[must_use]
30    /// Get a character reference from the string and an index.
31    ///
32    /// ```
33    /// use mut_str::StrExt;
34    ///
35    /// let s = "Hello, World!";
36    /// let c = s.get_char(1).unwrap();
37    ///
38    /// assert_eq!(c, 'e');
39    /// ```
40    fn get_char(&self, i: usize) -> Option<&Char>;
41    #[must_use]
42    /// Get a mutable character reference from the mutable string and an index.
43    ///
44    /// ```
45    /// use mut_str::StrExt;
46    ///
47    /// let mut owned_s = Box::<str>::from("Hello, World!");
48    /// let c = owned_s.get_char_mut(1).unwrap();
49    ///
50    /// assert_eq!(c, 'e');
51    /// ```
52    fn get_char_mut(&mut self, i: usize) -> Option<&mut Char>;
53
54    #[must_use]
55    /// Slice the string in units of UTF-8 characters.
56    /// If `range` is out of bounds, `None` will be returned.
57    ///
58    /// ```
59    /// use mut_str::StrExt;
60    ///
61    /// let s = "Hello, World!";
62    ///
63    /// let hello = s.char_slice(..5).unwrap();
64    /// assert_eq!(hello, "Hello");
65    ///
66    /// let world = s.char_slice(7..12).unwrap();
67    /// assert_eq!(world, "World");
68    /// ```
69    fn char_slice<R: RangeBounds<usize>>(&self, range: R) -> Option<&Self::Output>;
70    #[must_use]
71    /// Slice the mutable string in units of UTF-8 characters.
72    /// If `range` is out of bounds, `None` will be returned.
73    ///
74    /// ```
75    /// use mut_str::StrExt;
76    ///
77    /// let mut owned_s = Box::<str>::from("Hello, World!");
78    ///
79    /// let hello = owned_s.char_slice_mut(..5).unwrap();
80    /// assert_eq!(hello, "Hello");
81    ///
82    /// let world = owned_s.char_slice_mut(7..12).unwrap();
83    /// assert_eq!(world, "World");
84    /// ```
85    fn char_slice_mut<R: RangeBounds<usize>>(&mut self, range: R) -> Option<&mut Self::Output>;
86
87    #[must_use]
88    /// Divide the string into two at an index in units of UTF-8 characters.
89    /// If `mid` is out of bounds, `None` will be returned.
90    ///
91    /// ```
92    /// use mut_str::StrExt;
93    ///
94    /// let s = "Hello, World!";
95    ///
96    /// let (l, r) = s.char_split_at(6).unwrap();
97    /// assert_eq!(l, "Hello,");
98    /// assert_eq!(r, " World!");
99    /// ```
100    fn char_split_at(&self, mid: usize) -> Option<(&Self::Output, &Self::Output)>;
101    #[must_use]
102    /// Divide the mutable string into two at an index in units of UTF-8 characters.
103    /// If `mid` is out of bounds, `None` will be returned.
104    ///
105    /// ```
106    /// use mut_str::StrExt;
107    ///
108    /// let mut owned_s = Box::<str>::from("Hello, World!");
109    ///
110    /// let (l, r) = owned_s.char_split_at_mut(6).unwrap();
111    /// assert_eq!(l, "Hello,");
112    /// assert_eq!(r, " World!");
113    /// ```
114    fn char_split_at_mut(&mut self, mid: usize) -> Option<(&mut Self::Output, &mut Self::Output)>;
115
116    #[must_use]
117    /// Get an iterator over character references in the string.
118    ///
119    /// ```
120    /// use mut_str::StrExt;
121    ///
122    /// let s = "Hello, World!";
123    ///
124    /// s.ref_iter()
125    ///     .zip(s.chars())
126    ///     .for_each(|(x, y)| assert_eq!(x, y));
127    /// ```
128    fn ref_iter(&self) -> Self::Iter<'_>;
129    #[must_use]
130    /// Get an iterator over mutable character references in the string.
131    ///
132    /// ```
133    /// use mut_str::StrExt;
134    ///
135    /// let s = "Hello, World!";
136    /// let mut owned_s = Box::<str>::from(s);
137    ///
138    /// owned_s.mut_iter()
139    ///     .zip(s.chars())
140    ///     .for_each(|(x, y)| assert_eq!(x, y));
141    /// ```
142    fn mut_iter(&mut self) -> Self::IterMut<'_>;
143
144    /// Copy the string to a byte buffer and get the new string containing the inserted character.
145    /// Returns `None` if `buffer` is shorter than the string.
146    ///
147    /// ```
148    /// use mut_str::StrExt;
149    ///
150    /// let s = "Hello, World!";
151    /// let mut buffer = [0; 50];
152    /// let new_s = s.copy_to(&mut buffer).unwrap();
153    ///
154    /// assert_eq!(new_s, s);
155    /// ```
156    fn copy_to<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a mut Self::Output>;
157
158    /// Replace the mutable string with another of the same length.
159    ///
160    /// ```
161    /// use mut_str::StrExt;
162    ///
163    /// let mut owned_s = Box::<str>::from("World!");
164    ///
165    /// owned_s.replace_with("🌍!!").unwrap();
166    /// assert_eq!(&*owned_s, "🌍!!");
167    ///
168    /// owned_s.replace_with("aaaaaa").unwrap();
169    /// assert_eq!(&*owned_s, "aaaaaa");
170    /// ```
171    ///
172    /// # Errors
173    /// - If `s` and `r`, when utf8 encoded, do not have the same length, [`LenNotEqual`] will be returned.
174    fn replace_with<'a>(&'a mut self, r: &str) -> Result<&'a mut str, LenNotEqual>;
175    /// Replace the mutable string with another of the same length or shorter.
176    /// The remaining bytes will be filled with spaces.
177    ///
178    /// ```
179    /// use mut_str::StrExt;
180    ///
181    /// let mut owned_s = Box::<str>::from("World!");
182    ///
183    /// owned_s.replace_with_pad_space("🌍").unwrap();
184    /// assert_eq!(&*owned_s, "🌍  ");
185    ///
186    /// owned_s.replace_with_pad_space("aaaa").unwrap();
187    /// assert_eq!(&*owned_s, "aaaa  ");
188    /// ```
189    ///
190    /// # Errors
191    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplacementTooLong`] will be returned.
192    fn replace_with_pad_space<'a>(&'a mut self, r: &str)
193        -> Result<&'a mut str, ReplacementTooLong>;
194    /// Replace the mutable string with another of the same length or shorter.
195    /// The remaining bytes will be filled with `pad`.
196    ///
197    /// ```
198    /// use mut_str::StrExt;
199    ///
200    /// let mut owned_s = Box::<str>::from("World!");
201    ///
202    /// owned_s.replace_with_pad("🌍", b'!').unwrap();
203    /// assert_eq!(&*owned_s, "🌍!!");
204    ///
205    /// owned_s.replace_with_pad("aaaa", b'b').unwrap();
206    /// assert_eq!(&*owned_s, "aaaabb");
207    /// ```
208    ///
209    /// # Errors
210    /// - If `pad` is not valid utf8, [`ReplaceWithPadError::InvalidPad`] will be returned.
211    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplaceWithPadError::ReplacementLen`] will be returned.
212    fn replace_with_pad<'a>(
213        &'a mut self,
214        r: &str,
215        pad: u8,
216    ) -> Result<&'a mut str, ReplaceWithPadError>;
217    /// Replace the mutable string with another of the same length or shorter.
218    /// The remaining bytes will be filled with `pad`, which must be one byte long.
219    ///
220    /// ```
221    /// use mut_str::StrExt;
222    ///
223    /// let mut owned_s = Box::<str>::from("World!");
224    ///
225    /// owned_s.replace_with_pad_char("🌍", '!').unwrap();
226    /// assert_eq!(&*owned_s, "🌍!!");
227    ///
228    /// owned_s.replace_with_pad_char("aaaa", 'b').unwrap();
229    /// assert_eq!(&*owned_s, "aaaabb");
230    /// ```
231    ///
232    /// # Errors
233    /// - If `pad_char`, when utf8 encoded, is longer than `Self`, [`ReplaceWithPadCharError::PadCharTooLong`] will be returned.
234    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplaceWithPadCharError::ReplacementLen`] will be returned.
235    fn replace_with_pad_char<'a, C>(
236        &'a mut self,
237        r: &str,
238        pad_char: C,
239    ) -> Result<&'a mut str, ReplaceWithPadCharError>
240    where
241        C: Into<char>;
242    /// Replace the mutable string with another of the same length or shorter, right aligned.
243    /// The remaining bytes before the string will be filled with spaces.
244    ///
245    /// ```
246    /// use mut_str::StrExt;
247    ///
248    /// let mut owned_s = Box::<str>::from("World!");
249    ///
250    /// owned_s.replace_with_pad_left_space("🌍").unwrap();
251    /// assert_eq!(&*owned_s, "  🌍");
252    ///
253    /// owned_s.replace_with_pad_left_space("aaaa").unwrap();
254    /// assert_eq!(&*owned_s, "  aaaa");
255    /// ```
256    ///
257    /// # Errors
258    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplacementTooLong`] will be returned.
259    fn replace_with_pad_left_space<'a>(
260        &'a mut self,
261        r: &str,
262    ) -> Result<&'a mut Self::Output, ReplacementTooLong>;
263    /// Replace the mutable string with another of the same length or shorter, right aligned.
264    /// The remaining bytes before the string will be filled with `pad`.
265    ///
266    /// ```
267    /// use mut_str::StrExt;
268    ///
269    /// let mut owned_s = Box::<str>::from("World!");
270    ///
271    /// owned_s.replace_with_pad_left("🌍", b'!').unwrap();
272    /// assert_eq!(&*owned_s, "!!🌍");
273    ///
274    /// owned_s.replace_with_pad_left("aaaa", b'b').unwrap();
275    /// assert_eq!(&*owned_s, "bbaaaa");
276    /// ```
277    ///
278    /// # Errors
279    /// - If `pad` is not valid utf8, [`ReplaceWithPadError::InvalidPad`] will be returned.
280    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplaceWithPadError::ReplacementLen`] will be returned.
281    fn replace_with_pad_left<'a>(
282        &'a mut self,
283        r: &str,
284        pad: u8,
285    ) -> Result<&'a mut Self::Output, ReplaceWithPadError>;
286    /// Replace the mutable string with another of the same length or shorter, right aligned.
287    /// The remaining bytes before the string will be filled with `char`, which must be one byte long.
288    ///
289    /// ```
290    /// use mut_str::StrExt;
291    ///
292    /// let mut owned_s = Box::<str>::from("World!");
293    ///
294    /// owned_s.replace_with_pad_left_char("🌍", '!').unwrap();
295    /// assert_eq!(&*owned_s, "!!🌍");
296    ///
297    /// owned_s.replace_with_pad_left_char("aaaa", 'b').unwrap();
298    /// assert_eq!(&*owned_s, "bbaaaa");
299    /// ```
300    ///
301    /// # Errors
302    /// - If `pad_char`, when utf8 encoded, is longer than `Self`, [`ReplaceWithPadCharError::PadCharTooLong`] will be returned.
303    /// - If `r`, when utf8 encoded, is longer than `s`, when utf8 encoded, [`ReplaceWithPadCharError::ReplacementLen`] will be returned.
304    fn replace_with_pad_left_char<'a, C>(
305        &'a mut self,
306        r: &str,
307        pad_char: C,
308    ) -> Result<&'a mut Self::Output, ReplaceWithPadCharError>
309    where
310        C: Into<char>;
311}
312
313impl StrExt for str {
314    type Output = Self;
315    type Iter<'a> = CharRefs<'a>;
316    type IterMut<'a> = CharMutRefs<'a>;
317
318    #[inline]
319    fn get_char(&self, i: usize) -> Option<&Char> {
320        Char::get(self, i)
321    }
322
323    #[inline]
324    fn get_char_mut(&mut self, i: usize) -> Option<&mut Char> {
325        Char::get_mut(self, i)
326    }
327
328    #[inline]
329    fn char_slice<R: RangeBounds<usize>>(&self, range: R) -> Option<&Self::Output> {
330        char_slice(self, range)
331    }
332
333    #[inline]
334    fn char_slice_mut<R: RangeBounds<usize>>(&mut self, range: R) -> Option<&mut Self::Output> {
335        char_slice_mut(self, range)
336    }
337
338    #[inline]
339    fn char_split_at(&self, mid: usize) -> Option<(&Self::Output, &Self::Output)> {
340        char_split_at(self, mid)
341    }
342
343    #[inline]
344    fn char_split_at_mut(&mut self, mid: usize) -> Option<(&mut Self::Output, &mut Self::Output)> {
345        char_split_at_mut(self, mid)
346    }
347
348    #[inline]
349    fn ref_iter(&self) -> Self::Iter<'_> {
350        CharRefs::from(self)
351    }
352
353    #[inline]
354    fn mut_iter(&mut self) -> Self::IterMut<'_> {
355        CharMutRefs::from(self)
356    }
357
358    #[inline]
359    fn copy_to<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a mut Self::Output> {
360        copy_to(self, buffer)
361    }
362
363    #[inline]
364    fn replace_with<'a>(&'a mut self, r: &str) -> Result<&'a mut str, LenNotEqual> {
365        replace(self, r)
366    }
367
368    #[inline]
369    fn replace_with_pad_space<'a>(
370        &'a mut self,
371        r: &str,
372    ) -> Result<&'a mut str, ReplacementTooLong> {
373        replace_with_pad_space(self, r)
374    }
375
376    #[inline]
377    fn replace_with_pad<'a>(
378        &'a mut self,
379        r: &str,
380        pad: u8,
381    ) -> Result<&'a mut str, ReplaceWithPadError> {
382        replace_with_pad(self, r, pad)
383    }
384
385    #[inline]
386    fn replace_with_pad_char<'a, C>(
387        &'a mut self,
388        r: &str,
389        pad_char: C,
390    ) -> Result<&'a mut str, ReplaceWithPadCharError>
391    where
392        C: Into<char>,
393    {
394        replace_with_pad_char(self, r, pad_char)
395    }
396
397    #[inline]
398    fn replace_with_pad_left_space(
399        &mut self,
400        r: &str,
401    ) -> Result<&mut Self::Output, ReplacementTooLong> {
402        replace_with_pad_left_space(self, r)
403    }
404
405    #[inline]
406    fn replace_with_pad_left(
407        &mut self,
408        r: &str,
409        pad: u8,
410    ) -> Result<&mut Self::Output, ReplaceWithPadError> {
411        replace_with_pad_left(self, r, pad)
412    }
413
414    #[inline]
415    fn replace_with_pad_left_char<C>(
416        &mut self,
417        r: &str,
418        pad_char: C,
419    ) -> Result<&mut Self::Output, ReplaceWithPadCharError>
420    where
421        C: Into<char>,
422    {
423        replace_with_pad_left_char(self, r, pad_char)
424    }
425}