split_char_from_str/
lib.rs1#![no_std]
2#![doc = include_str!("README.md")]
3
4pub 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
17pub 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
35pub trait SplitCharFromStr<'a>: sealed::Sealed + Sized {
37 fn split_first_char(self) -> Option<(char, &'a str)>;
44
45 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}