1#![no_std]
2#![doc = include_str!("README.md")]
3
4pub 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
17pub trait SplitFirstChar<'a>: sealed::Sealed + Sized {
19 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}