const_format/__str_methods/
str_replace.rs

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}