1 | use super::{bytes_find, Pattern, PatternCtor, PatternNorm}; |
2 | |
3 | pub struct ReplaceInputConv<T>(pub &'static str, pub T, pub &'static str); |
4 | |
5 | macro_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 | |
19 | ctor! {u8} |
20 | ctor! {&'static str} |
21 | ctor! {char} |
22 | |
23 | pub struct ReplaceInput { |
24 | str: &'static str, |
25 | pattern: Pattern, |
26 | replaced_with: &'static str, |
27 | } |
28 | |
29 | impl 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 | |
38 | const 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 | |
68 | const 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 | |