This patch introduce self-owned skippable data iterators in Rust. This iterators will be used to access extended attributes later. Signed-off-by: Yiyang Wu <toolmanp@xxxxxxx> --- fs/erofs/rust/erofs_sys/data/raw_iters.rs | 121 ++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/fs/erofs/rust/erofs_sys/data/raw_iters.rs b/fs/erofs/rust/erofs_sys/data/raw_iters.rs index 8f3bd250d252..f1ff0a251596 100644 --- a/fs/erofs/rust/erofs_sys/data/raw_iters.rs +++ b/fs/erofs/rust/erofs_sys/data/raw_iters.rs @@ -4,3 +4,124 @@ pub(crate) mod ref_iter; mod traits; pub(crate) use traits::*; + +use super::*; +use alloc::boxed::Box; + +/// Represents a skippable continuous buffer iterator. This is used primarily for reading the +/// extended attributes. Since the key-value is flattened out in its original format. +pub(crate) struct SkippableContinuousIter<'a> { + iter: Box<dyn ContinuousBufferIter<'a> + 'a>, + data: RefBuffer<'a>, + cur: usize, +} + +fn cmp_with_cursor_move( + lhs: &[u8], + rhs: &[u8], + lhs_cur: &mut usize, + rhs_cur: &mut usize, + len: usize, +) -> bool { + let result = lhs[*lhs_cur..(*lhs_cur + len)] == rhs[*rhs_cur..(*rhs_cur + len)]; + *lhs_cur += len; + *rhs_cur += len; + result +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum SkipCmpError { + PosixError(Errno), + NotEqual(Off), +} + +impl From<Errno> for SkipCmpError { + fn from(e: Errno) -> Self { + SkipCmpError::PosixError(e) + } +} + +impl<'a> SkippableContinuousIter<'a> { + pub(crate) fn try_new( + mut iter: Box<dyn ContinuousBufferIter<'a> + 'a>, + ) -> PosixResult<Option<Self>> { + if iter.eof() { + return Ok(None); + } + let data = iter.next().unwrap()?; + Ok(Some(Self { iter, data, cur: 0 })) + } + pub(crate) fn skip(&mut self, offset: Off) -> PosixResult<()> { + let dlen = self.data.content().len() - self.cur; + if offset as usize <= dlen { + self.cur += offset as usize; + } else { + self.cur = 0; + self.iter.advance_off(dlen as Off); + self.data = self.iter.next().unwrap()?; + } + Ok(()) + } + + pub(crate) fn read(&mut self, buf: &mut [u8]) -> PosixResult<()> { + let mut dlen = self.data.content().len() - self.cur; + let mut bcur = 0_usize; + let blen = buf.len(); + if dlen != 0 && dlen >= blen { + buf.clone_from_slice(&self.data.content()[self.cur..(self.cur + blen)]); + self.cur += blen; + } else { + buf[bcur..(bcur + dlen)].copy_from_slice(&self.data.content()[self.cur..]); + bcur += dlen; + while bcur < blen { + self.cur = 0; + self.data = self.iter.next().unwrap()?; + dlen = self.data.content().len(); + if dlen >= blen - bcur { + buf[bcur..].copy_from_slice(&self.data.content()[..(blen - bcur)]); + self.cur = blen - bcur; + return Ok(()); + } else { + buf[bcur..(bcur + dlen)].copy_from_slice(self.data.content()); + bcur += dlen; + } + } + } + Ok(()) + } + + pub(crate) fn try_cmp(&mut self, buf: &[u8]) -> Result<(), SkipCmpError> { + let dlen = self.data.content().len() - self.cur; + let blen = buf.len(); + let mut bcur = 0_usize; + + if dlen != 0 && dlen >= blen { + if cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, blen) { + Ok(()) + } else { + Err(SkipCmpError::NotEqual(bcur as Off)) + } + } else { + if dlen != 0 { + let clen = dlen.min(blen); + if !cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, clen) { + return Err(SkipCmpError::NotEqual(bcur as Off)); + } + } + while bcur < blen { + self.cur = 0; + self.data = self.iter.next().unwrap()?; + let dlen = self.data.content().len(); + let clen = dlen.min(blen - bcur); + if !cmp_with_cursor_move(self.data.content(), buf, &mut self.cur, &mut bcur, clen) { + return Err(SkipCmpError::NotEqual(bcur as Off)); + } + } + + Ok(()) + } + } + pub(crate) fn eof(&self) -> bool { + self.data.content().len() - self.cur == 0 && self.iter.eof() + } +} -- 2.46.0