const_format/__str_methods/
str_split.rs1use super::{Pattern, PatternCtor, PatternNorm};
2
3use konst::slice::{bytes_find, bytes_find_skip};
4
5pub struct SplitInputConv<T>(pub &'static str, pub T);
6
7macro_rules! ctor {
8 ($ty:ty) => {
9 impl SplitInputConv<$ty> {
10 pub const fn conv(self) -> SplitInput {
11 SplitInput {
12 str: self.0,
13 pattern: PatternCtor(self.1).conv(),
14 length: usize::MAX,
15 }
16 .compute_length()
17 }
18 }
19 };
20}
21
22ctor! {u8}
23ctor! {&'static str}
24ctor! {char}
25
26#[derive(Copy, Clone)]
27pub struct SplitInput {
28 str: &'static str,
29 pattern: Pattern,
30 length: usize,
31}
32
33impl SplitInput {
34 const fn compute_length(mut self) -> Self {
35 self.length = count_splits(self);
36 self
37 }
38
39 pub const fn split_it<const LEN: usize>(self) -> [&'static str; LEN] {
40 split_it(self)
41 }
42
43 pub const fn length(&self) -> usize {
44 self.length
45 }
46}
47
48pub const fn count_splits(SplitInput { str, pattern, .. }: SplitInput) -> usize {
49 let mut count = 1;
50
51 match pattern.normalize() {
52 PatternNorm::AsciiByte(ascii_c) => {
53 let mut bytes = str.as_bytes();
54 let ascii_c = ascii_c.get();
55
56 while let [byte, rem @ ..] = bytes {
57 bytes = rem;
58
59 if *byte == ascii_c {
60 count += 1;
61 }
62 }
63 }
64 PatternNorm::Str(str_pat) => {
65 if str_pat.is_empty() {
66 let mut char_i = 0;
67 count += 1;
68 while let Some(next) = find_next_char_boundary(str, char_i) {
69 char_i = next;
70 count += 1;
71 }
72 } else {
73 let mut str = str.as_bytes();
74 while let Some(next) = bytes_find_skip(str, str_pat) {
75 str = next;
76 count += 1;
77 }
78 }
79 }
80 }
81
82 count
83}
84
85const fn find_u8(mut slice: &[u8], byte: u8) -> Option<usize> {
86 let mut i = 0;
87
88 while let [b, ref rem @ ..] = *slice {
89 if byte == b {
90 return Some(i);
91 }
92 slice = rem;
93 i += 1;
94 }
95 None
96}
97
98const fn find_next_char_boundary(str: &str, mut index: usize) -> Option<usize> {
99 if index == str.len() {
100 None
101 } else {
102 loop {
103 index += 1;
104 if index == str.len() || (str.as_bytes()[index] as i8) >= -0x40 {
105 break Some(index);
106 }
107 }
108 }
109}
110
111pub const fn split_it<const LEN: usize>(args: SplitInput) -> [&'static str; LEN] {
112 let SplitInput {
113 mut str,
114 pattern,
115 length: _,
116 } = args;
117
118 let mut out = [""; LEN];
119 let mut out_i = 0;
120
121 macro_rules! write_out {
122 ($string:expr) => {
123 out[out_i] = $string;
124 out_i += 1;
125 };
126 }
127
128 match pattern.normalize() {
129 PatternNorm::AsciiByte(ascii_c) => {
130 let ascii_c = ascii_c.get();
131
132 while let Some(found_at) = find_u8(str.as_bytes(), ascii_c) {
133 write_out! {konst::string::str_up_to(str, found_at)}
134 str = konst::string::str_from(str, found_at + 1);
135 }
136 }
137 PatternNorm::Str(str_pat) => {
138 if str_pat.is_empty() {
139 out_i += 1;
140 while let Some(next) = find_next_char_boundary(str, 0) {
141 write_out! {konst::string::str_up_to(str, next)}
142 str = konst::string::str_from(str, next);
143 }
144 } else {
145 while let Some(found_at) = bytes_find(str.as_bytes(), str_pat, 0) {
146 write_out! {konst::string::str_up_to(str, found_at)}
147 str = konst::string::str_from(str, found_at + str_pat.len());
148 }
149 }
150 }
151 }
152
153 write_out! {str}
154
155 assert!(out_i == LEN);
156 out
157}