1use super::{bytes_find, Pattern, PatternCtor, PatternNorm};
2
3pub struct ReplaceInputConv<T>(pub &'static str, pub T, pub &'static str);
4
5macro_rules! ctor {
6 ($ty:ty) => {
7 impl ReplaceInputConv<$ty> {
8 pub const fn conv(self) -> ReplaceInput {
9 ReplaceInput {
10 str: self.0,
11 pattern: PatternCtor(self.1).conv(),
12 replaced_with: self.2,
13 }
14 }
15 }
16 };
17}
18
19ctor! {u8}
20ctor! {&'static str}
21ctor! {char}
22
23pub struct ReplaceInput {
24 str: &'static str,
25 pattern: Pattern,
26 replaced_with: &'static str,
27}
28
29impl ReplaceInput {
30 pub const fn replace_length(&self) -> usize {
31 str_replace_length(self.str, self.pattern, self.replaced_with)
32 }
33 pub const fn replace<const L: usize>(&self) -> [u8; L] {
34 str_replace(self.str, self.pattern, self.replaced_with)
35 }
36}
37
38const fn str_replace_length(inp: &str, r: Pattern, replaced_with: &str) -> usize {
39 let inp = inp.as_bytes();
40
41 let replaced_len = replaced_with.len();
42 let mut out_len = 0;
43
44 match r.normalize() {
45 PatternNorm::AsciiByte(byte) => {
46 let byte = byte.get();
47 iter_copy_slice! {b in inp =>
48 out_len += if b == byte { replaced_len } else { 1 };
49 }
50 }
51 PatternNorm::Str(str) => {
52 if str.is_empty() {
53 return inp.len();
54 }
55 let str_len = str.len();
56 let mut i = 0;
57 while let Some(next_match) = bytes_find(inp, str, i) {
58 out_len += (next_match - i) + replaced_len;
59 i = next_match + str_len;
60 }
61 out_len += inp.len() - i;
62 }
63 }
64
65 out_len
66}
67
68const fn str_replace<const L: usize>(inp: &str, r: Pattern, replaced_with: &str) -> [u8; L] {
69 let inp = inp.as_bytes();
70
71 let replaced_with_bytes = replaced_with.as_bytes();
72 let mut out = [0u8; L];
73 let mut out_i = 0;
74
75 macro_rules! write_replaced {
76 () => {
77 iter_copy_slice! {b in replaced_with_bytes =>
78 out[out_i] = b;
79 out_i += 1;
80 }
81 };
82 }
83 macro_rules! write_byte {
84 ($byte:expr) => {
85 out[out_i] = $byte;
86 out_i += 1;
87 };
88 }
89
90 match r.normalize() {
91 PatternNorm::AsciiByte(byte) => {
92 let byte = byte.get();
93 iter_copy_slice! {b in inp =>
94 if b == byte {
95 write_replaced!{}
96 } else {
97 write_byte!{b}
98 }
99 }
100 }
101 PatternNorm::Str(str) => {
102 if str.is_empty() {
103 iter_copy_slice! {b in inp =>
104 write_byte!(b);
105 }
106 return out;
107 }
108 let str_len = str.len();
109 let mut i = 0;
110 while let Some(next_match) = bytes_find(inp, str, i) {
111 __for_range! {j in i..next_match =>
112 write_byte!(inp[j]);
113 }
114 write_replaced! {}
115
116 i = next_match + str_len;
117 }
118 __for_range! {j in i..inp.len() =>
119 write_byte!(inp[j]);
120 }
121 }
122 }
123 out
124}
125