strtools/split/
mod.rs

1//! This module contains functions with the primary purpose of splitting [str]s.
2
3use crate::util::Sorted;
4
5mod char_boundary;
6pub use char_boundary::*;
7
8mod non_escaped;
9pub use non_escaped::*;
10
11/// Splits a string into `N + 1` pieces.
12///
13/// # Panics
14/// Panics if an index is out of bounds, `index <= input.len()`.
15///
16/// # Examples
17/// ```
18/// # use strtools::split;
19/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
20/// let ([a, b], c) = split::n_times("abcdefghijkl", &[4, 8].try_into()?);
21///
22/// assert_eq!((a, b, c), ("abcd", "efgh", "ijkl"));
23/// # Ok(())
24/// # }
25/// ```
26pub fn n_times<'s, const N: usize>(
27    input: &'s str,
28    indices: &Sorted<usize, N>,
29) -> ([&'s str; N], &'s str) {
30    match indices.last() {
31        // N is not 0, since it must be sorted, if the last index is in bounds, then so are all
32        // others
33        Some(&last) => assert!(last <= input.len(), "index out of bounds"),
34        None => return ([""; N], input),
35    }
36
37    let mut res = [""; N];
38    let mut prev = 0;
39
40    for (idx, &index) in indices.iter().enumerate() {
41        // SAFETY: indices checked above
42        res[idx] = unsafe { input.get_unchecked(prev..index) };
43        prev = index;
44    }
45
46    // SAFETY: see above
47    (res, unsafe { input.get_unchecked(prev..) })
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    pub fn n_times_non_overlapping() {
56        assert_eq!(
57            n_times("abcdefghijkl", &[4, 8].try_into().unwrap()),
58            (["abcd", "efgh"], "ijkl")
59        );
60    }
61
62    #[test]
63    pub fn n_times_non_boundary() {
64        assert_eq!(
65            n_times("abcdefgh", &[].try_into().unwrap()),
66            ([], "abcdefgh")
67        );
68        assert_eq!(
69            n_times("abcdefgh", &[0].try_into().unwrap()),
70            ([""], "abcdefgh")
71        );
72        assert_eq!(
73            n_times("abcdefgh", &[8].try_into().unwrap()),
74            (["abcdefgh"], "")
75        );
76    }
77
78    #[test]
79    pub fn n_times_non_repeating() {
80        assert_eq!(
81            n_times("abcdefghijkl", &[4, 4, 4, 8].try_into().unwrap()),
82            (["abcd", "", "", "efgh"], "ijkl")
83        );
84    }
85}