pub mod borrowed;
pub mod buffered;
pub mod error;
pub mod mmap;
pub mod owned;
mod padding;
mod slice;
pub use borrowed::BorrowedBytes;
pub use buffered::BufferedInput;
pub use mmap::MmapInput;
pub use owned::OwnedBytes;
use self::error::InputError;
use crate::{result::InputRecorder, string_pattern::StringPattern};
use std::ops::Deref;
macro_rules! repr_align_block_size {
($it:item) => {
#[repr(C, align(128))]
$it
};
}
pub(crate) use repr_align_block_size;
pub const MAX_BLOCK_SIZE: usize = 128;
pub trait Input: Sized {
type BlockIterator<'i, 'r, R, const N: usize>: InputBlockIterator<
'i,
N,
Block = Self::Block<'i, N>,
Error = Self::Error,
>
where
Self: 'i,
R: InputRecorder<Self::Block<'i, N>> + 'r;
type Error: Into<InputError>;
type Block<'i, const N: usize>: InputBlock<'i, N>
where
Self: 'i;
#[inline(always)]
#[must_use]
fn len_hint(&self) -> Option<usize> {
None
}
#[must_use]
fn leading_padding_len(&self) -> usize;
#[must_use]
fn trailing_padding_len(&self) -> usize;
#[must_use]
fn iter_blocks<'i, 'r, R, const N: usize>(&'i self, recorder: &'r R) -> Self::BlockIterator<'i, 'r, R, N>
where
R: InputRecorder<Self::Block<'i, N>>;
#[must_use]
fn seek_backward(&self, from: usize, needle: u8) -> Option<usize>;
fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Result<Option<(usize, u8)>, Self::Error>;
fn seek_non_whitespace_forward(&self, from: usize) -> Result<Option<(usize, u8)>, Self::Error>;
#[must_use]
fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)>;
fn is_member_match(&self, from: usize, to: usize, member: &StringPattern) -> Result<bool, Self::Error>;
}
pub trait InputBlockIterator<'i, const N: usize> {
type Block: InputBlock<'i, N>;
type Error: Into<InputError>;
fn next(&mut self) -> Result<Option<Self::Block>, Self::Error>;
fn get_offset(&self) -> usize;
fn offset(&mut self, count: isize);
}
pub trait InputBlock<'i, const N: usize>: Deref<Target = [u8]> {
#[must_use]
fn halves(&self) -> (&[u8], &[u8]);
#[inline]
#[must_use]
fn quarters(&self) -> (&[u8], &[u8], &[u8], &[u8]) {
assert!(N.is_multiple_of(4), "block must be a power of two larger than 2");
let (half1, half2) = self.halves();
let (q1, q2) = (&half1[..N / 4], &half1[N / 4..]);
let (q3, q4) = (&half2[..N / 4], &half2[N / 4..]);
(q1, q2, q3, q4)
}
}
impl<'i, const N: usize> InputBlock<'i, N> for &'i [u8] {
#[inline(always)]
fn halves(&self) -> (&[u8], &[u8]) {
assert!(N.is_multiple_of(2), "block must be a power of two larger than 1");
(&self[..N / 2], &self[N / 2..])
}
}
pub(super) trait SliceSeekable {
fn is_member_match(&self, from: usize, to: usize, member: &StringPattern) -> bool;
fn seek_backward(&self, from: usize, needle: u8) -> Option<usize>;
fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)>;
fn seek_non_whitespace_forward(&self, from: usize) -> Option<(usize, u8)>;
fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)>;
}
fn align_to<const N: usize>(bytes: &[u8]) -> (&[u8], &[u8], &[u8]) {
let ptr = bytes.as_ptr();
let offset = ptr.align_offset(N);
if offset > bytes.len() {
(bytes, &[], &[])
} else {
let (left, rest) = bytes.split_at(offset);
let middle_len = (rest.len() / N) * N;
let (middle, right) = rest.split_at(middle_len);
(left, middle, right)
}
}
#[cfg(test)]
mod tests {
use super::align_to;
use crate::input::MAX_BLOCK_SIZE;
const N: usize = MAX_BLOCK_SIZE;
const SIZE: usize = 1024;
#[repr(align(128))]
struct Aligned {
bytes: [u8; SIZE],
}
#[test]
fn test_all_alignments() {
let aligned = Aligned { bytes: get_bytes() };
let slice = &aligned.bytes;
for i in 0..slice.len() {
let misalignment = i % N;
test_with_misalignment(misalignment, &slice[i..]);
}
}
fn get_bytes() -> [u8; SIZE] {
let mut bytes = [0; SIZE];
for (i, b) in bytes.iter_mut().enumerate() {
let x = i % (u8::MAX as usize);
*b = x as u8;
}
bytes
}
fn test_with_misalignment(misalignment: usize, slice: &[u8]) {
let expected_left_len = (N - misalignment) % N;
let expected_rem_len = slice.len() - expected_left_len;
let expected_middle_len = (expected_rem_len / N) * N;
let expected_right_len = expected_rem_len - expected_middle_len;
let (left, middle, right) = align_to::<N>(slice);
let glued_back: Vec<_> = [left, middle, right].into_iter().flatten().copied().collect();
assert_eq!(left.len(), expected_left_len, "misalignment = {misalignment}");
assert_eq!(middle.len(), expected_middle_len, "misalignment = {misalignment}");
assert_eq!(right.len(), expected_right_len, "misalignment = {misalignment}");
assert_eq!(glued_back, slice, "misalignment = {misalignment}");
}
}