tor-bytes: Add cursor functionality to Reader

We'll use this to implement signature and MAC checking for
EstablishIntro cells.
This commit is contained in:
Nick Mathewson 2023-02-27 14:33:45 -05:00
parent 09d601d050
commit 0bf1ae70ba
2 changed files with 62 additions and 0 deletions

View File

@ -0,0 +1 @@
ADDED: Cursor functionality in Reader.

View File

@ -317,6 +317,43 @@ impl<'a> Reader<'a> {
{
read_nested_generic::<u32, _, _>(self, f)
}
/// Return a cursor object describing the current position of this Reader within
/// its underlying byte stream.
///
/// The resulting [`Cursor`] can be used with `range`, but nothing else.
pub fn cursor(&self) -> Cursor<'a> {
Cursor {
pos: self.off,
_phantom: std::marker::PhantomData,
}
}
/// Return the slice of bytes between the start cursor (inclusive) and end
/// cursor (exclusive).
///
/// If the cursors are not in order, return an empty slice.
///
/// This function is guaranteed not to panic if the inputs were generated
/// from a different Reader, but the byte slice that it returns will
/// not be well-defined.
pub fn range(&self, start: Cursor<'a>, end: Cursor<'a>) -> &'a [u8] {
if start.pos <= end.pos && end.pos <= self.b.len() {
&self.b[start.pos..end.pos]
} else {
&self.b[..0]
}
}
}
/// A reference to a position within a [`Reader`].
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Cursor<'a> {
/// The underlying position within the reader.
pos: usize,
/// Used so that we can restrict the cursor to the lifetime of the
/// underlying byte slice.
_phantom: std::marker::PhantomData<&'a [u8]>,
}
/// Implementation of `read_nested_*` -- generic
@ -573,4 +610,28 @@ mod tests {
assert_eq!(les.unwrap_err(), Error::Truncated);
assert_eq!(r.remaining(), 28);
}
#[test]
fn cursor() -> Result<()> {
let alphabet = b"abcdefghijklmnopqrstuvwxyz";
let mut r = Reader::from_slice(&alphabet[..]);
let c1 = r.cursor();
let _ = r.take_u16()?;
let c2 = r.cursor();
let c2b = r.cursor();
r.advance(7)?;
let c3 = r.cursor();
assert_eq!(r.range(c1, c2), &b"ab"[..]);
assert_eq!(r.range(c2, c3), &b"cdefghi"[..]);
assert_eq!(r.range(c1, c3), &b"abcdefghi"[..]);
assert_eq!(r.range(c1, c1), &b""[..]);
assert_eq!(r.range(c3, c1), &b""[..]);
assert_eq!(c2, c2b);
assert!(c1 < c2);
assert!(c2 < c3);
Ok(())
}
}