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}