mut_str/split.rs
1use core::{slice, str};
2
3#[must_use]
4/// Split a [`prim@str`] in units of UTF-8 characters.
5///
6/// ```
7/// use mut_str::char_split_at;
8///
9/// let s = "Hello, World!";
10///
11/// let (l, r) = char_split_at(s, 6).unwrap();
12/// assert_eq!(l, "Hello,");
13/// assert_eq!(r, " World!");
14/// ```
15pub fn char_split_at(s: &str, mid: usize) -> Option<(&str, &str)> {
16 let mut iter = s.char_indices();
17 let mut last_char = (0, '\x00');
18
19 for _ in 0..mid {
20 last_char = iter.next()?;
21 }
22
23 let mid_index = last_char.0 + last_char.1.len_utf8();
24
25 // SAFETY:
26 // `mid` is guaranteed to be on a char boundary and a maximum of one byte
27 // over the end of the slice.
28 Some(unsafe { (s.get_unchecked(..mid_index), s.get_unchecked(mid_index..)) })
29}
30
31#[must_use]
32/// Split a mutable [`prim@str`] in units of UTF-8 characters.
33///
34/// ```
35/// use mut_str::char_split_at_mut;
36///
37/// let mut owned_s = Box::<str>::from("Hello, World!");
38///
39/// let (l, r) = char_split_at_mut(&mut *owned_s, 6).unwrap();
40/// assert_eq!(l, "Hello,");
41/// assert_eq!(r, " World!");
42/// ```
43pub fn char_split_at_mut(s: &mut str, mid: usize) -> Option<(&mut str, &mut str)> {
44 let mut iter = s.char_indices();
45 let mut last_char = (0, '\x00');
46
47 for _ in 0..mid {
48 last_char = iter.next()?;
49 }
50
51 let mid_index = last_char.0 + last_char.1.len_utf8();
52
53 // SAFETY:
54 // `mid` is guaranteed to be on a char boundary and a maximum of one byte
55 // over the end of the slice.
56 Some(unsafe {
57 (
58 str::from_utf8_unchecked_mut(slice::from_raw_parts_mut(s.as_mut_ptr(), mid_index)),
59 s.get_unchecked_mut(mid_index..),
60 )
61 })
62}