split_char_from_str/
lib.rs

1#![no_std]
2#![doc = include_str!("README.md")]
3
4/// Split a string into a pair of first character and the rest.
5///
6/// ```
7/// # use split_char_from_str::split_first_char;
8/// assert_eq!(split_first_char("abc"), Some(('a', "bc")))
9/// ```
10pub fn split_first_char(text: &str) -> Option<(char, &'_ str)> {
11    let mut iter = text.chars();
12    let first = iter.next()?;
13    let rest = iter.as_str();
14    Some((first, rest))
15}
16
17/// Split a string into a pair of initial part and the last character.
18///
19/// ```
20/// # use split_char_from_str::split_last_char;
21/// assert_eq!(split_last_char("abc"), Some(("ab", 'c')))
22/// ```
23pub fn split_last_char(text: &str) -> Option<(&'_ str, char)> {
24    let mut iter = text.chars();
25    let last = iter.next_back()?;
26    let rest = iter.as_str();
27    Some((rest, last))
28}
29
30mod sealed {
31    pub trait Sealed {}
32    impl<'a> Sealed for &'a str {}
33}
34
35/// Extension trait that provides methods to split character from a `&str`.
36pub trait SplitCharFromStr<'a>: sealed::Sealed + Sized {
37    /// Split a string into a pair of first character and the rest.
38    ///
39    /// ```
40    /// # use split_char_from_str::SplitCharFromStr;
41    /// assert_eq!("abc".split_first_char(), Some(('a', "bc")))
42    /// ```
43    fn split_first_char(self) -> Option<(char, &'a str)>;
44
45    /// Split a string into a pair of initial part and the last character.
46    /// ```
47    /// # use split_char_from_str::SplitCharFromStr;
48    /// assert_eq!("abc".split_last_char(), Some(("ab", 'c')))
49    /// ```
50    fn split_last_char(self) -> Option<(&'a str, char)>;
51}
52
53impl<'a> SplitCharFromStr<'a> for &'a str {
54    fn split_first_char(self) -> Option<(char, &'a str)> {
55        split_first_char(self)
56    }
57
58    fn split_last_char(self) -> Option<(&'a str, char)> {
59        split_last_char(self)
60    }
61}
62
63pub use split_first_char as first;
64pub use split_last_char as last;
65pub use SplitCharFromStr as Extension;
66
67#[cfg(test)]
68mod test {
69    use crate::{split_first_char, split_last_char, SplitCharFromStr};
70    use core::ops::Deref;
71
72    #[test]
73    fn function() {
74        assert_eq!(split_first_char("abc"), Some(('a', "bc")));
75        assert_eq!(split_first_char("x"), Some(('x', "")));
76        assert_eq!(split_first_char(""), None);
77        assert_eq!(split_last_char("abc"), Some(("ab", 'c')));
78        assert_eq!(split_last_char("x"), Some(("", 'x')));
79        assert_eq!(split_last_char(""), None);
80    }
81
82    #[test]
83    fn method() {
84        assert_eq!("abc".split_first_char(), Some(('a', "bc")));
85        assert_eq!("x".split_first_char(), Some(('x', "")));
86        assert_eq!("".split_first_char(), None);
87        assert_eq!("abc".split_last_char(), Some(("ab", 'c')));
88        assert_eq!("x".split_last_char(), Some(("", 'x')));
89        assert_eq!("".split_last_char(), None);
90    }
91
92    #[test]
93    fn lifetime() {
94        fn _use_function(text: &str) -> Option<(&'_ str, &'_ str)> {
95            let (_, tail) = split_first_char(text)?;
96            let (init, _) = split_last_char(text)?;
97            Some((tail, init))
98        }
99
100        fn _use_method(text: &str) -> Option<(&'_ str, &'_ str)> {
101            let (_, tail) = text.split_first_char()?;
102            let (init, _) = text.split_last_char()?;
103            Some((tail, init))
104        }
105    }
106
107    #[test]
108    fn deref() {
109        enum Input {
110            None,
111            One,
112            Many,
113        }
114
115        impl Deref for Input {
116            type Target = str;
117            fn deref(&self) -> &Self::Target {
118                match self {
119                    Input::None => "",
120                    Input::One => "x",
121                    Input::Many => "abc",
122                }
123            }
124        }
125
126        assert_eq!(Input::None.split_first_char(), None);
127        assert_eq!(Input::One.split_first_char(), Some(('x', "")));
128        assert_eq!(Input::Many.split_first_char(), Some(('a', "bc")));
129        assert_eq!(Input::None.split_last_char(), None);
130        assert_eq!(Input::One.split_last_char(), Some(("", 'x')));
131        assert_eq!(Input::Many.split_last_char(), Some(("ab", 'c')));
132    }
133}