stdext/
str.rs

1//! Extension traits for `str` primitive type.
2
3/// Alternative for `std::str::pattern::Pattern` that does not require
4/// nightly Rust (as `Pattern` is unstable yet).
5#[doc(hidden)]
6pub enum AltPattern<'a> {
7    Str(&'a str),
8    Char(char),
9}
10
11impl<'a> From<&'a str> for AltPattern<'a> {
12    fn from(data: &'a str) -> Self {
13        Self::Str(data)
14    }
15}
16
17impl<'a> From<char> for AltPattern<'a> {
18    fn from(data: char) -> Self {
19        Self::Char(data)
20    }
21}
22
23/// Extension trait with useful methods for primitive type [`str`].
24///
25/// [`str`]: https://doc.rust-lang.org/std/primitive.str.html
26pub trait StrExt {
27    /// Version of [`str::splitn`] which expects the **exact**
28    /// amount of entries obtained after splitting. This method
29    /// returns `Vec`, as [`SplitN`] iterator depends on the unstable
30    /// type [`Pattern`] and cannot be returned on the stable Rust.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use stdext::prelude::*;
36    ///
37    /// let data = "Hello world";
38    /// let splitted = data.splitn_exact(2, " ").unwrap();
39    /// assert_eq!(&splitted, &["Hello", "world"]);
40    ///
41    /// let splitted = data.splitn_exact(5, '-');
42    /// assert!(splitted.is_none());
43    /// ```
44    ///
45    /// [`str::splitn`]: https://doc.rust-lang.org/std/primitive.str.html#method.splitn
46    /// [`SplitN`]: https://doc.rust-lang.org/std/str/struct.SplitN.html
47    /// [`Pattern`]: https://doc.rust-lang.org/std/str/pattern/trait.Pattern.html
48    fn splitn_exact<'a, P: Into<AltPattern<'a>>>(
49        &'a self,
50        n: usize,
51        pat: P,
52    ) -> Option<Vec<&'a str>>;
53}
54
55impl StrExt for &str {
56    fn splitn_exact<'a, P: Into<AltPattern<'a>>>(
57        &'a self,
58        n: usize,
59        pat: P,
60    ) -> Option<Vec<&'a str>> {
61        let pat = pat.into();
62        // Overcome for `&str` splitting API: it accepts generic arguments as separators,
63        // but the `Pattern` trait is unstable, thus it's impossible to just forward arguments
64        // inside on stable Rust.
65        let splitted: Vec<_> = match pat {
66            AltPattern::Str(sep) => self.splitn(n, sep).collect(),
67            AltPattern::Char(sep) => self.splitn(n, sep).collect(),
68        };
69
70        if splitted.len() == n {
71            Some(splitted)
72        } else {
73            None
74        }
75    }
76}