split_exact 1.1.0

splitting strings into arrays of slices
Documentation
#![no_std]

pub trait SplitExact {
    fn split_exact<const N: usize>(&self, predicate: impl FnMut(char) -> bool)
        -> [Option<&str>; N];

    fn split_exact_with_rest<const N: usize>(
        &self,
        predicate: impl FnMut(char) -> bool,
    ) -> ([Option<&str>; N], &str);
}

impl SplitExact for str {
    /// Returns an array the size of `N` containing the substrings
    /// of `self` when separated by a given predicate.
    ///
    /// If `N` is greater than the number of splits,
    /// the elements for which no item was found will be None.
    ///
    /// If `N` is smaller than the number of splits,
    /// the items for which no element was provided will be truncated.
    ///
    /// # Usage
    ///
    /// Number of splits = number of elements:
    ///
    /// ```
    /// # use split_exact::SplitExact;
    ///
    /// let header = "GET / HTTP/1.1";
    /// assert_eq!([Some("GET"), Some("/"), Some("HTTP/1.1")], header.split_exact(char::is_whitespace));
    /// ```
    ///
    /// Number of splits < number of elements:
    ///
    /// ```
    /// # use split_exact::SplitExact;
    ///
    /// let header = "!run command";
    /// assert_eq!([Some("!run"), Some("command"), None], header.split_exact(char::is_whitespace));
    /// ```
    ///
    /// Number of splits > number of elements:
    ///
    /// ```
    /// # use split_exact::SplitExact;
    ///
    /// let header = "cargo make target release";
    /// assert_eq!([Some("cargo"), Some("make"), Some("target")], header.split_exact(char::is_whitespace));
    /// ```
    fn split_exact<const N: usize>(
        &self,
        predicate: impl FnMut(char) -> bool,
    ) -> [Option<&str>; N] {
        let mut elements = [None; N];
        let mut splits = self.split(predicate);

        for element in &mut elements {
            *element = splits.next();
        }

        elements
    }

    /// Like [str::split_exact], but also returns
    /// the string slice that did not fit into the array.
    ///
    /// ```
    /// # use split_exact::SplitExact;
    ///
    /// let no_remainder = "test case scenario";
    /// assert_eq!(([Some("test"), Some("case"), Some("scenario")], ""), no_remainder.split_exact_with_rest(char::is_whitespace));
    ///
    /// let with_remainder = "test case scenario with remainder";
    /// assert_eq!(([Some("test"), Some("case"), Some("scenario")], "with remainder"), with_remainder.split_exact_with_rest(char::is_whitespace));
    /// ```
    fn split_exact_with_rest<const N: usize>(
        &self,
        mut predicate: impl FnMut(char) -> bool,
    ) -> ([Option<&str>; N], &str) {
        let elements = self.split_exact(&mut predicate);

        let offset = self
            .match_indices(predicate)
            .nth(N.saturating_sub(1))
            .map(|(index, _)| index.saturating_add(1))
            .unwrap_or(self.len());

        (elements, &self[offset..])
    }
}