rumtk_core/buffers/
helpers.rs1use crate::base::{RUMResult, RUMVec};
22use crate::buffers::constants::DEFAULT_BYTE_WINDOW_SIZE;
23use crate::buffers::RUMBuffer;
24use crate::cpu::*;
25use crate::strings::{rumtk_format, RUMArrayConversions, RUMString};
26use clap::builder::TypedValueParser;
27use rand::{distr::Alphanumeric, RngExt};
28use tokio::io::AsyncReadExt;
29
30#[inline(always)]
46pub fn slice_to_buffer(buffer: &[u8]) -> RUMBuffer {
47 RUMBuffer::from(buffer)
48}
49
50#[inline(always)]
67pub fn new_random_buffer<const N: usize>() -> [u8; N] {
68 let mut buffer = [0u8; N];
69 rand::fill(&mut buffer);
70 buffer
71}
72
73#[inline(always)]
90pub fn new_random_rumbuffer<const N: usize>() -> RUMBuffer {
91 slice_to_buffer(&new_random_buffer::<N>())
92}
93
94pub fn new_random_string_buffer<const N: usize>() -> RUMString {
111 rand::rng()
112 .sample_iter(&Alphanumeric)
113 .take(N) .map(char::from)
115 .collect()
116}
117
118pub fn new_random_string_set<const N: usize>(item_count: usize) -> RUMVec<RUMString> {
137 let mut set = RUMVec::<RUMString>::with_capacity(item_count);
138
139 for _ in 0..item_count {
140 set.push(new_random_string_buffer::<N>())
141 }
142
143 set
144}
145
146#[inline(always)]
162pub fn buffer_to_string(buffer: &[u8]) -> RUMResult<RUMString> {
163 match buffer.to_string() {
164 Ok(string) => Ok(string),
165 Err(e) => Err(rumtk_format!("Failure to parse incoming UTF-8 string: {}", e)),
166 }
167}
168
169#[inline(always)]
170pub fn buffer_to_str(buffer: &[u8]) -> RUMResult<&str> {
171 match std::str::from_utf8(buffer) {
172 Ok(string) => Ok(string),
173 Err(e) => Err(rumtk_format!("Failure to parse incoming UTF-8 string: {}", e)),
174 }
175}
176
177#[inline(always)]
178pub fn buffer_count(buffer: &[u8], pattern: u8) -> usize {
179 bytecount::count(buffer, pattern)
180}
181
182#[inline(always)]
183pub fn buffer_contains(buffer: &[u8], pattern: u8) -> bool {
184 buffer_find_byte(buffer, pattern).unwrap_or(buffer.len()) < buffer.len()
185}
186
187#[inline(always)]
188pub fn buffer_slice_to_array(chunk: &[u8]) -> &[u8; DEFAULT_BYTE_WINDOW_SIZE] {
189 chunk.try_into().expect("length mismatch")
190}
191
192#[inline(always)]
193pub fn buffer_chunk_find_fallback(chunk: &[u8], byte: u8) -> Option<usize> {
194 chunk.iter().position(|c| *c==byte)
195}
196
197#[inline(always)]
198pub fn buffer_chunk_find(chunk: &[u8], byte: u8) -> usize {
199 let length = chunk.len();
200
201 if length == DEFAULT_BYTE_WINDOW_SIZE {
202 let chunk_window = buffer_slice_to_array(chunk);
203 cpu_find_simd(chunk_window, byte).unwrap_or(length)
204 } else {
205 buffer_chunk_find_fallback(chunk, byte).unwrap_or(length)
206 }
207}
208
209#[inline(always)]
210pub fn buffer_find_byte(buffer: &[u8], byte: u8) -> Option<usize> {
211 cpu_find_simd(buffer, byte)
212}
213
214#[inline(always)]
215pub fn buffer_find(buffer: &[u8], pattern: &[u8]) -> usize {
216 if buffer.is_empty() {
217 return buffer.len();
218 }
219
220 let start_pattern_byte = pattern[0];
221 let pattern_length = pattern.len();
222 let mut working_buffer = buffer;
223 let mut cumulative = 0;
224 let mut end = 0;
225
226 while (end + pattern_length) < working_buffer.len() {
227 working_buffer = &working_buffer[end..];
228
229 if working_buffer[..pattern_length] == *pattern {
230 return cumulative;
231 } else {
232 working_buffer = &working_buffer[pattern_length..];
233 cumulative += pattern_length;
234 }
235
236 end = buffer_find_byte(&working_buffer, start_pattern_byte).unwrap_or(working_buffer.len());
237 cumulative += end;
238 }
239
240 buffer.len()
241}
242
243#[inline(always)]
244pub fn buffer_find_instances<'a>(buffer: &'a [u8], pattern: &[u8]) -> RUMVec<(usize, &'a [u8])> {
245 if buffer.is_empty() {
246 return RUMVec::new();
247 }
248
249 let pattern_length = pattern.len();
250 let buffer_length = buffer.len() - pattern_length;
251 let mut instances = RUMVec::<(usize, &[u8])>::with_capacity(100);
252
253 let mut cursor = buffer_find(buffer, pattern);
254 let mut cumulative = cursor;
255 let mut remainder = &buffer[..];
256
257 while cumulative < buffer_length {
258 instances.push((cumulative, &remainder[..cursor]));
259 let next = cursor + pattern_length;
260 if next <= remainder.len() {
261 remainder = &remainder[cursor + pattern_length..];
262 cursor = buffer_find(remainder, pattern);
263 cumulative += cursor;
264 } else {
265 cumulative += remainder.len();
266 }
267 }
268
269 instances
270}
271
272#[inline(always)]
273pub fn buffer_replace_in_place<'a>(buffer: &'a mut [u8], pattern: &[u8], replacement: &[u8]) {
274 if buffer.is_empty() || pattern.is_empty() || replacement.is_empty() {
276 return;
277 }
278
279 if pattern.len() == 1 {
281 cpu_replace_simd(buffer, pattern[0], replacement[0]);
282 return;
283 }
284
285 let replacement_length = replacement.len();
286 let mut cursor = buffer_find(&buffer, pattern);
287 let mut remainder = buffer;
288
289 while cursor < remainder.len() {
290 for i in 0..replacement_length {
291 remainder[cursor + i] = replacement[i];
292 }
293
294 remainder = &mut remainder[cursor + pattern.len()..];
295 cursor = buffer_find(remainder, pattern);
296 }
297}
298
299#[inline(always)]
300pub fn buffer_replace(buffer: &[u8], pattern: &[u8], replacement: &[u8]) -> RUMBuffer {
301 match buffer.is_empty() {
302 true => RUMBuffer::from(buffer),
303 false => {
304 let pattern_length = pattern.len();
305 let replacement_length = replacement.len();
306 let instances = buffer_find_instances(&buffer, pattern);
307 let mut new_buffer = RUMVec::with_capacity(buffer.len() + (instances.len() * (replacement_length)));
308 let mut last = 0;
309
310 for (indx, chunk) in instances {
311 new_buffer.extend_from_slice(chunk);
312 new_buffer.extend_from_slice(replacement);
313 last = indx + pattern_length;
314 }
315
316 new_buffer.extend_from_slice(&buffer[last..]);
317 RUMBuffer::from(new_buffer)
318 }
319 }
320}
321
322#[inline]
323pub fn buffer_trim(buffer: &RUMBuffer) -> RUMBuffer {
324 let trimmed = buffer_slice_trim(&buffer[..]);
325 RUMBuffer::from(trimmed)
326}
327
328#[inline(always)]
329pub fn buffer_slice_trim(buffer: &[u8]) -> &[u8] {
330 buffer.trim_ascii()
331}
332
333pub fn buffer_has_pattern(buffer: &[u8], pattern: &[u8]) -> bool {
334 buffer_find(buffer, pattern) != buffer.len()
335}
336
337pub fn is_unique_bytes(data: &[u8]) -> bool {
338 let mut items = ahash::AHashSet::with_capacity(data.len());
339 for i in 0..data.len() {
340 if !items.insert(data[i]) {
341 return false;
342 }
343 }
344 true
345}