Skip to content

cleanup: remove Bytes8 abstraction #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 4 additions & 136 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use core::slice;
use core::convert::TryInto;
use core::convert::TryFrom;

pub struct Bytes<'a> {
slice: &'a [u8],
Expand Down Expand Up @@ -30,12 +32,8 @@ impl<'a> Bytes<'a> {
}

#[inline]
pub fn peek_4(&self) -> Option<&[u8]> {
if self.slice.len() >= self.pos + 4 {
Some(&self.slice[self.pos..=self.pos + 3])
} else {
None
}
pub fn peek_n<U: TryFrom<&'a[u8]>>(&self, n: usize) -> Option<U> {
self.slice.get(self.pos..self.pos + n)?.try_into().ok()
}

#[inline]
Expand Down Expand Up @@ -85,15 +83,6 @@ impl<'a> Bytes<'a> {
self.pos = 0;
self.slice = tail;
}

#[inline]
pub fn next_8<'b>(&'b mut self) -> Option<Bytes8<'b, 'a>> {
if self.slice.len() >= self.pos + 8 {
Some(Bytes8::new(self))
} else {
None
}
}
}

impl<'a> AsRef<[u8]> for Bytes<'a> {
Expand All @@ -117,124 +106,3 @@ impl<'a> Iterator for Bytes<'a> {
}
}
}

pub struct Bytes8<'a, 'b: 'a> {
bytes: &'a mut Bytes<'b>,
#[cfg(debug_assertions)]
pos: usize
}

macro_rules! bytes8_methods {
($f:ident, $pos:expr) => {
#[inline]
pub fn $f(&mut self) -> u8 {
self.assert_pos($pos);
let b = unsafe { *self.bytes.slice.get_unchecked(self.bytes.pos) };
self.bytes.pos += 1;
b
}
};
() => {
bytes8_methods!(_0, 0);
bytes8_methods!(_1, 1);
bytes8_methods!(_2, 2);
bytes8_methods!(_3, 3);
bytes8_methods!(_4, 4);
bytes8_methods!(_5, 5);
bytes8_methods!(_6, 6);
bytes8_methods!(_7, 7);
}
}

impl<'a, 'b: 'a> Bytes8<'a, 'b> {
bytes8_methods! {}

#[cfg(not(debug_assertions))]
#[inline]
fn new(bytes: &'a mut Bytes<'b>) -> Bytes8<'a, 'b> {
Bytes8 {
bytes: bytes,
}
}

#[cfg(debug_assertions)]
#[inline]
fn new(bytes: &'a mut Bytes<'b>) -> Bytes8<'a, 'b> {
Bytes8 {
bytes,
pos: 0,
}
}

#[cfg(not(debug_assertions))]
#[inline]
fn assert_pos(&mut self, _pos: usize) {
}

#[cfg(debug_assertions)]
#[inline]
fn assert_pos(&mut self, pos: usize) {
assert!(self.pos == pos);
self.pos += 1;
}
}

#[cfg(test)]
mod tests {
use super::Bytes;

#[test]
fn test_next_8_too_short() {
// Start with 10 bytes.
let slice = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8];
let mut bytes = Bytes::new(&slice);
// Skip 3 of them.
unsafe { bytes.advance(3); }
// There should be 7 left, not enough to call next_8.
assert!(bytes.next_8().is_none());
}

#[test]
fn test_next_8_just_right() {
// Start with 10 bytes.
let slice = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8];
let mut bytes = Bytes::new(&slice);
// Skip 2 of them.
unsafe { bytes.advance(2); }
// There should be 8 left, just enough to call next_8.
let ret = bytes.next_8();
assert!(ret.is_some());
let mut ret = ret.unwrap();
// They should be the bytes starting with 2.
assert_eq!(ret._0(), 2u8);
assert_eq!(ret._1(), 3u8);
assert_eq!(ret._2(), 4u8);
assert_eq!(ret._3(), 5u8);
assert_eq!(ret._4(), 6u8);
assert_eq!(ret._5(), 7u8);
assert_eq!(ret._6(), 8u8);
assert_eq!(ret._7(), 9u8);
}

#[test]
fn test_next_8_extra() {
// Start with 10 bytes.
let slice = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8];
let mut bytes = Bytes::new(&slice);
// Skip 1 of them.
unsafe { bytes.advance(1); }
// There should be 9 left, more than enough to call next_8.
let ret = bytes.next_8();
assert!(ret.is_some());
let mut ret = ret.unwrap();
// They should be the bytes starting with 1.
assert_eq!(ret._0(), 1u8);
assert_eq!(ret._1(), 2u8);
assert_eq!(ret._2(), 3u8);
assert_eq!(ret._3(), 4u8);
assert_eq!(ret._4(), 5u8);
assert_eq!(ret._5(), 6u8);
assert_eq!(ret._6(), 7u8);
assert_eq!(ret._7(), 8u8);
}
}
53 changes: 25 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,14 +478,16 @@ impl<'h, 'b> Request<'h, 'b> {
let orig_len = buf.len();
let mut bytes = Bytes::new(buf);
complete!(skip_empty_lines(&mut bytes));
let method = match bytes.peek_4() {
Some(b"GET ") => {
const GET: [u8; 4] = *b"GET ";
const POST: [u8; 4] = *b"POST";
let method = match bytes.peek_n::<[u8; 4]>(4) {
Some(GET) => {
unsafe {
bytes.advance_and_commit(4);
}
"GET"
}
Some(b"POST") if bytes.peek_ahead(4) == Some(b' ') => {
Some(POST) if bytes.peek_ahead(4) == Some(b' ') => {
unsafe {
bytes.advance_and_commit(5);
}
Expand Down Expand Up @@ -744,20 +746,13 @@ pub const EMPTY_HEADER: Header<'static> = Header { name: "", value: b"" };

#[inline]
fn parse_version(bytes: &mut Bytes) -> Result<u8> {
if let Some(mut eight) = bytes.next_8() {
expect!(eight._0() => b'H' |? Err(Error::Version));
expect!(eight._1() => b'T' |? Err(Error::Version));
expect!(eight._2() => b'T' |? Err(Error::Version));
expect!(eight._3() => b'P' |? Err(Error::Version));
expect!(eight._4() => b'/' |? Err(Error::Version));
expect!(eight._5() => b'1' |? Err(Error::Version));
expect!(eight._6() => b'.' |? Err(Error::Version));
let v = match eight._7() {
b'0' => 0,
b'1' => 1,
_ => return Err(Error::Version)
};
return Ok(Status::Complete(v))
if let Some(eight) = bytes.peek_n::<[u8; 8]>(8) {
unsafe { bytes.advance(8); }
return match &eight {
b"HTTP/1.0" => Ok(Status::Complete(0)),
b"HTTP/1.1" => Ok(Status::Complete(1)),
_ => Err(Error::Version),
}
}

// else (but not in `else` because of borrow checker)
Expand Down Expand Up @@ -1117,24 +1112,26 @@ fn parse_headers_iter_uninit<'a, 'b>(
simd::match_header_value_vectored(bytes);

'value_line: loop {
if let Some(mut bytes8) = bytes.next_8() {
if let Some(bytes8) = bytes.peek_n::<[u8; 8]>(8) {
macro_rules! check {
($bytes:ident, $i:ident) => ({
b = $bytes.$i();
($bytes:ident, $i:literal) => ({
b = $bytes[$i];
if !is_header_value_token(b) {
unsafe { bytes.advance($i + 1); }
break 'value_line;
}
});
}

check!(bytes8, _0);
check!(bytes8, _1);
check!(bytes8, _2);
check!(bytes8, _3);
check!(bytes8, _4);
check!(bytes8, _5);
check!(bytes8, _6);
check!(bytes8, _7);
check!(bytes8, 0);
check!(bytes8, 1);
check!(bytes8, 2);
check!(bytes8, 3);
check!(bytes8, 4);
check!(bytes8, 5);
check!(bytes8, 6);
check!(bytes8, 7);
unsafe { bytes.advance(8); }

continue 'value_line;
}
Expand Down