libdelimit: initial commit

This commit is contained in:
Emma Tebibyte 2025-10-27 23:37:11 -06:00
parent be6bd5386d
commit 31b424d205
Signed by: emma
GPG Key ID: 427287A2F16F44FA

92
src/libdelimit.rs Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2025 Emma Tebibyte <emma@tebibyte.media>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
* for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
use std::{
io::{ Read, Result, stdin },
mem::self,
process::ExitCode,
};
const BUFFER_SIZE: usize = 4096;
struct Delimited {
stream: Box<dyn Read>,
delimiter: Vec<u8>,
buffer: Vec<u8>
}
impl Delimited {
fn new(stream: Box<dyn Read>, delimiter: &[u8]) -> Self {
Delimited {
stream,
delimiter: delimiter.to_vec(),
buffer: Vec::with_capacity(BUFFER_SIZE),
}
}
}
impl Iterator for Delimited {
type Item = Result<Vec<u8>>;
fn next(&mut self) -> Option<Self::Item> {
let mut buf = [0; BUFFER_SIZE];
loop {
if let Some(p) = find_subslice(&self.buffer, &self.delimiter) {
let chunk = self.buffer.drain(..p).collect::<Vec<_>>();
let _ = self.buffer.drain(..self.delimiter.len());
return Some(Ok(chunk));
}
match self.stream.read(&mut buf) {
Ok(0) => {
if self.buffer.is_empty() {
return None;
}
return Some(Ok(mem::take(&mut self.buffer)));
},
Ok(n) => {
let content = &buf[..n];
self.buffer.extend_from_slice(&content);
},
Err(e) => {
return Some(Err(e));
},
}
}
}
}
fn find_subslice(stack: &[u8], key: &[u8]) -> Option<usize> {
if key.len() == 1 {
return stack.iter().position(|&b| b == key[0]);
}
if key.len() > stack.len() {
return None;
}
for i in 0..=stack.len() - key.len() {
if &stack[i..i + key.len()] == key {
return Some(i);
}
}
None
}