1use std::borrow::Cow;
2
3pub(crate) fn cut(mut source: &str, n: usize) -> impl Iterator<Item = &str> {
6 std::iter::from_fn(move || {
7 if source.is_empty() {
8 None
9 } else {
10 let end_idx = source
11 .char_indices()
12 .nth(n - 1)
13 .map_or_else(|| source.len(), |(idx, c)| idx + c.len_utf8());
14
15 let (sub_str, rest) = source.split_at(end_idx);
16 source = rest;
17
18 Some(sub_str)
19 }
20 })
21}
22
23pub(crate) fn to_uppercase(s: &str) -> Cow<'_, str> {
27 match s.as_bytes().iter().position(u8::is_ascii_lowercase) {
28 Some(pos) => {
29 let mut output = s.to_owned();
30
31 unsafe { output.get_unchecked_mut(pos..) }.make_ascii_uppercase();
33
34 Cow::Owned(output)
35 }
36 None => Cow::Borrowed(s),
37 }
38}
39
40pub(crate) fn split_prefix<const N: usize>(s: &str) -> (&str, &str) {
42 let end_idx = s
43 .char_indices()
44 .nth(N - 1)
45 .map_or_else(|| s.len(), |(idx, c)| idx + c.len_utf8());
46
47 s.split_at(end_idx)
48}
49
50#[cfg(test)]
51mod tests {
52 #[test]
53 fn cut() {
54 let mut iter = super::cut("hDHrdTv2n", 2);
55
56 assert_eq!(iter.next(), Some("hD"));
57 assert_eq!(iter.next(), Some("Hr"));
58 assert_eq!(iter.next(), Some("dT"));
59 assert_eq!(iter.next(), Some("v2"));
60 assert_eq!(iter.next(), Some("n"));
61 assert_eq!(iter.next(), None);
62 }
63
64 #[test]
65 fn to_uppercase() {
66 let upper = super::to_uppercase("MANAmE JeF");
67 assert_eq!(upper.as_ref(), "MANAME JEF");
68
69 let upper = super::to_uppercase("mAn4me jäf");
70 assert_eq!(upper.as_ref(), "MAN4ME JäF");
71 }
72
73 #[test]
74 fn split_prefix() {
75 assert_eq!(super::split_prefix::<1>("abc"), ("a", "bc"));
76 assert_eq!(super::split_prefix::<4>("abc"), ("abc", ""));
77 }
78}