1use std::{ops, usize};
6
7pub trait CharSlice<R> {
11 fn char_slice(&self, r: R) -> &str;
15}
16
17impl CharSlice<ops::RangeFull> for str {
18 #[inline]
19 fn char_slice(&self, _: ops::RangeFull) -> &str {
20 self
21 }
22}
23
24impl CharSlice<ops::RangeTo<usize>> for str {
25 #[inline]
26 fn char_slice(&self, r: ops::RangeTo<usize>) -> &str {
27 self.char_slice(0..r.end)
28 }
29}
30
31impl CharSlice<ops::RangeFrom<usize>> for str {
32 #[inline]
33 fn char_slice(&self, r: ops::RangeFrom<usize>) -> &str {
34 self.char_slice(r.start..usize::MAX)
35 }
36}
37
38impl CharSlice<ops::Range<usize>> for str {
39 #[inline]
40 fn char_slice(&self, r: ops::Range<usize>) -> &str {
41 char_slice(self, r.start, r.end)
42 }
43}
44
45#[inline(always)]
46fn utf8_start_byte(b: u8) -> bool {
48 b < 128 || b >= 192
49}
50
51fn char_slice(s: &str, start: usize, end: usize) -> &str {
52 if end <= start { return "" }
53
54 let mut bidx = 0; let mut cidx = 0; let mut start_idx = 0;
58
59 for b in s.bytes() {
60 if utf8_start_byte(b) {
61 if cidx == start {
62 start_idx = bidx;
63 }
64
65 if cidx == end {
66 return &s[start_idx..bidx];
67 }
68
69 cidx += 1;
70 }
71
72 bidx += 1;
73 }
74
75 if start >= cidx {
77 return ""
78 }
79
80 &s[start_idx..]
82}
83
84#[test]
85fn substr_test() {
86 assert_eq!( "".char_slice(0 .. 0), "");
87 assert_eq!( "".char_slice(0 .. 1), "");
88 assert_eq!( "a".char_slice(1 .. 2), "");
89 assert_eq!( "a".char_slice(0 .. 1), "a");
90 assert_eq!( "a".char_slice(0 .. 2), "a");
91 assert_eq!( "a".char_slice(0 .. 0), "");
92 assert_eq!("ab".char_slice(0 .. 1), "a");
93 assert_eq!("ab".char_slice(1 .. 2), "b");
94 assert_eq!("ab".char_slice(0 .. 2), "ab");
95
96 assert_eq!("äöü".char_slice(0 .. 0), "");
97 assert_eq!("äöü".char_slice(4 .. 5), "");
98 assert_eq!("äöü".char_slice(0 .. 1), "ä");
99 assert_eq!("äöü".char_slice(1 .. 2), "ö");
100 assert_eq!("äöü".char_slice(2 .. 3), "ü");
101 assert_eq!("äöü".char_slice(0 .. 2), "äö");
102 assert_eq!("äöü".char_slice(1 .. 3), "öü");
103 assert_eq!("äöü".char_slice(0 .. 3), "äöü");
104 assert_eq!("äöü".char_slice(0 .. 4), "äöü");
105}