split_first_char/
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.
5pub fn split_first_char(text: &str) -> Option<(char, &'_ str)> {
6    let mut iter = text.chars();
7    let first = iter.next()?;
8    let rest = iter.as_str();
9    Some((first, rest))
10}
11
12mod sealed {
13    pub trait Sealed {}
14    impl<'a> Sealed for &'a str {}
15}
16
17/// Convenient trait to call [`split_first_char`] as a method.
18pub trait SplitFirstChar<'a>: sealed::Sealed + Sized {
19    /// Split a string into a pair of first character and the rest.
20    fn split_first_char(self) -> Option<(char, &'a str)>;
21}
22
23impl<'a> SplitFirstChar<'a> for &'a str {
24    fn split_first_char(self) -> Option<(char, &'a str)> {
25        split_first_char(self)
26    }
27}
28
29#[cfg(test)]
30mod test {
31    use super::{split_first_char, SplitFirstChar};
32    use core::ops::Deref;
33
34    #[test]
35    fn function() {
36        assert_eq!(split_first_char("abc"), Some(('a', "bc")));
37        assert_eq!(split_first_char("x"), Some(('x', "")));
38        assert_eq!(split_first_char(""), None);
39    }
40
41    #[test]
42    fn method() {
43        assert_eq!("abc".split_first_char(), Some(('a', "bc")));
44        assert_eq!("x".split_first_char(), Some(('x', "")));
45        assert_eq!("".split_first_char(), None);
46    }
47
48    #[test]
49    fn lifetime() {
50        fn _use_function(text: &str) -> Option<&'_ str> {
51            let (_, rest) = split_first_char(text)?;
52            Some(rest)
53        }
54
55        fn _use_method(text: &str) -> Option<&'_ str> {
56            let (_, rest) = text.split_first_char()?;
57            Some(rest)
58        }
59    }
60
61    #[test]
62    fn deref() {
63        enum Input {
64            None,
65            One,
66            Many,
67        }
68
69        impl Deref for Input {
70            type Target = str;
71            fn deref(&self) -> &Self::Target {
72                match self {
73                    Input::None => "",
74                    Input::One => "x",
75                    Input::Many => "abc",
76                }
77            }
78        }
79
80        assert_eq!(Input::None.split_first_char(), None);
81        assert_eq!(Input::One.split_first_char(), Some(('x', "")));
82        assert_eq!(Input::Many.split_first_char(), Some(('a', "bc")));
83    }
84}