pub struct ForwardSearch { /* private fields */ }Expand description
Reusable scratch for a scanner’s forward search for its next signature
(a magic, a checksum-valid block). Reads start at Self::FIRST_CHUNK,
or at 2 * sig_len - 1 when that is larger, so the first read always
tests sig_len offsets, and double up to Self::MAX_CHUNK, into one
buffer kept across calls,
so a search whose answer is a few bytes away reads a few bytes: a scan
that resumes one byte past a refused candidate costs work proportional to
the distance it actually searched, never a fixed 64 KiB per call. That is
the property testing::check_scan_is_linear holds every scanner to.
O(1) memory however far the next signature is.
The bytes a search read past its answer are kept for the next call
(0.10.3 Task 4). A call whose from lies inside what the previous
call read tests those bytes again without reading them again, and reads
only past them. Without that, every call paid at least its first read
afresh, so candidates a few bytes apart — an accepted header every
eleven bytes, say — cost a first read EACH: 64 bytes, or 2 * sig_len - 1 for a long signature, per candidate. A scan whose from only moves
forward therefore reads each byte about once in its searches, however
dense its candidates are.
One ForwardSearch serves one source, whose bytes do not change
while it is in use — a scanner owns one per scan. Pass a different
source and the kept bytes are that other source’s. A call with a
smaller file_len than the last never tests a kept byte at or past it.
Implementations§
Source§impl ForwardSearch
impl ForwardSearch
Sourcepub const FIRST_CHUNK: usize = 64
pub const FIRST_CHUNK: usize = 64
Size of the first read of every search, unless the signature is long
enough that 2 * sig_len - 1 is larger — see Self::find.
Sourcepub fn find(
&mut self,
src: &mut dyn SeekRead,
from: u64,
file_len: u64,
sig_len: usize,
matches: impl FnMut(&[u8]) -> bool,
) -> Result<Option<u64>>
pub fn find( &mut self, src: &mut dyn SeekRead, from: u64, file_len: u64, sig_len: usize, matches: impl FnMut(&[u8]) -> bool, ) -> Result<Option<u64>>
The first offset >= from at which matches accepts the sig_len
bytes starting there, or None when none does before file_len.
matches sees exactly sig_len bytes. Every offset is tested once,
carrying sig_len - 1 bytes across a chunk boundary. Never reads at
or past file_len, and stops at EOF if the source is shorter.
The first read is max(FIRST_CHUNK, 2 * sig_len - 1) bytes, so it
tests at least sig_len offsets. A first read of only sig_len
bytes tests ONE offset: for tar’s 512-byte block, a header one block
on then cost 512 + 1,024 bytes, three times the distance searched.
Sourcepub fn find_to_eof(
&mut self,
src: &mut dyn SeekRead,
from: u64,
file_len: u64,
sig_len: usize,
min_len: usize,
matches: impl FnMut(&[u8]) -> bool,
) -> Result<Option<u64>>
pub fn find_to_eof( &mut self, src: &mut dyn SeekRead, from: u64, file_len: u64, sig_len: usize, min_len: usize, matches: impl FnMut(&[u8]) -> bool, ) -> Result<Option<u64>>
Self::find for a record whose length is not fixed: offsets with
at least sig_len bytes before file_len are offered exactly
sig_len bytes, and the last offsets — those with fewer, down to
min_len — are offered every byte left before file_len. A record
whose longest form is sig_len bytes can then be judged whole
inside the search, wherever it starts, without a second read near
EOF. min_len is at least 1 and at most sig_len.