Skip to content
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

Trait based contexts #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
96 changes: 83 additions & 13 deletions benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use test::black_box;

#[bench]
fn bench_byteorder(b: &mut test::Bencher) {
b.iter(|| black_box(LittleEndian::read_u16(&black_box([1, 2]))));
b.iter(|| black_box(byteorder::LittleEndian::read_u16(&black_box([1, 2]))));
b.bytes = 2;
}

Expand All @@ -24,13 +24,7 @@ fn bench_read_num(b: &mut test::Bencher) {
#[bench]
fn bench_str(b: &mut test::Bencher) {
let bytes = b"abcdefghijkl";
b.iter(|| {
black_box(
black_box(bytes)
.read_with::<&str>(&mut 0, Str::Len(5))
.unwrap(),
)
});
b.iter(|| black_box(black_box(bytes).read_with::<&str>(&mut 0, Len(5)).unwrap()));
b.bytes = 5;
}

Expand Down Expand Up @@ -112,25 +106,44 @@ fn example_write_hardcode(bytes: &mut [u8], header: Header) -> Option<()> {
Some(())
}

#[bench]
fn bench_example_read_write_numbers(b: &mut test::Bencher) {
let numbers = Numbers {
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
six: 6,
seven: 7,
eight: 8,
};
let buf = &mut [0u8; 30];
b.iter(|| {
black_box(numbers.try_write(buf, LE).unwrap());
black_box(Numbers::try_read(buf, LE).unwrap())
});
}

struct Header<'a> {
name: &'a str,
enabled: bool,
}

impl<'a> TryRead<'a, Endian> for Header<'a> {
fn try_read(bytes: &'a [u8], endian: Endian) -> Result<(Self, usize)> {
impl<'a, Ctx: Endianess> TryRead<'a, Ctx> for Header<'a> {
fn try_read(bytes: &'a [u8], endian: Ctx) -> Result<(Self, usize)> {
let offset = &mut 0;

let name_len = black_box(bytes.read_with::<u16>(offset, endian)? as usize);
let name = bytes.read_with::<&str>(offset, Str::Len(name_len))?;
let name = bytes.read_with::<&str>(offset, Len(name_len))?;
let enabled = bytes.read(offset)?;

Ok((Header { name, enabled }, *offset))
}
}

impl<'a> TryWrite<Endian> for Header<'a> {
fn try_write(self, bytes: &mut [u8], endian: Endian) -> Result<usize> {
impl<'a, Ctx: Endianess> TryWrite<Ctx> for Header<'a> {
fn try_write(self, bytes: &mut [u8], endian: Ctx) -> Result<usize> {
let offset = &mut 0;

bytes.write_with(offset, self.name.len() as u16, endian)?;
Expand All @@ -140,3 +153,60 @@ impl<'a> TryWrite<Endian> for Header<'a> {
Ok(*offset)
}
}

struct Numbers {
one: u8,
two: u16,
three: u32,
four: u64,
five: i8,
six: i16,
seven: i32,
eight: i64,
}

impl<'a, Ctx: Endianess> TryRead<'a, Ctx> for Numbers {
fn try_read(bytes: &'a [u8], endian: Ctx) -> Result<(Self, usize)> {
let offset = &mut 0;

let one = bytes.read_with(offset, endian)?;
let two = bytes.read_with(offset, endian)?;
let three = bytes.read_with(offset, endian)?;
let four = bytes.read_with(offset, endian)?;
let five = bytes.read_with(offset, endian)?;
let six = bytes.read_with(offset, endian)?;
let seven = bytes.read_with(offset, endian)?;
let eight = bytes.read_with(offset, endian)?;

Ok((
Numbers {
one,
two,
three,
four,
five,
six,
seven,
eight,
},
*offset,
))
}
}

impl<'a, Ctx: Endianess> TryWrite<Ctx> for &Numbers {
fn try_write(self, bytes: &mut [u8], endian: Ctx) -> Result<usize> {
let offset = &mut 0;

bytes.write_with(offset, self.one, endian)?;
bytes.write_with(offset, self.two, endian)?;
bytes.write_with(offset, self.three, endian)?;
bytes.write_with(offset, self.four, endian)?;
bytes.write_with(offset, self.five, endian)?;
bytes.write_with(offset, self.six, endian)?;
bytes.write_with(offset, self.seven, endian)?;
bytes.write_with(offset, self.eight, endian)?;

Ok(*offset)
}
}
93 changes: 93 additions & 0 deletions src/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//! Context for primitives

mod bool;
mod bytes;
mod num;
mod str;

pub use self::num::*;
pub use self::str::*;

/// Context that provides a fixed length for a slice.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff];
///
/// let sub: &[u8] = bytes.read_with(&mut 0, Len(2)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad]);
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Len(pub usize);

/// Context that provides a pattern that determines where the slice ends.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff];
///
/// static PATTERN: &'static [u8; 2] = &[0x00, 0xff];
///
/// let sub: &[u8] = bytes.read_with(&mut 0, Pattern(PATTERN)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff]);
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Pattern(pub &'static [u8]);

/// Context that provides a pattern that determines where the slice ends and a maximum length.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff];
///
/// static PATTERN: &'static [u8; 2] = &[0x00, 0xff];
///
/// let sub: &[u8] = bytes.read_with(&mut 0, PatternUntil(PATTERN, 4)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad, 0xbe, 0xef]);
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct PatternUntil(pub &'static [u8], pub usize);

/// Context that provides a delimiter that determines where the slice ends.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = b"hello, world!\0";

/// let str: &str = bytes.read_with(&mut 0, Delimiter(b"!"[0])).unwrap();
/// assert_eq!(str, "hello, world");
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Delimiter(pub u8);

/// Context that provides a delimiter that determines where the slice ends and a maximum length.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = b"hello, world!\0";

/// let str: &str = bytes.read_with(&mut 0, DelimiterUntil(NULL, 5)).unwrap();
/// assert_eq!(str, "hello");
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct DelimiterUntil(pub u8, pub usize);
117 changes: 48 additions & 69 deletions src/ctx/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,56 @@
use crate::{check_len, Error, Result, TryRead, TryWrite};

/// Context for &[u8] to determine where the slice ends.
///
/// Pattern will be included in the result
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff];
///
/// let sub: &[u8] = bytes.read_with(&mut 0, Bytes::Len(2)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad]);
///
/// static PATTERN: &'static [u8; 2] = &[0x00, 0xff];
///
/// let sub: &[u8] = bytes.read_with(&mut 0, Bytes::Pattern(PATTERN)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad, 0xbe, 0xef, 0x00, 0xff]);
///
/// let sub: &[u8] = bytes.read_with(&mut 0, Bytes::PatternUntil(PATTERN, 4)).unwrap();
/// assert_eq!(sub, &[0xde, 0xad, 0xbe, 0xef]);
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Bytes {
/// Take fix-length bytes
Len(usize),
/// Take bytes until reaching a byte pattern
Pattern(&'static [u8]),
/// Take bytes until either byte pattern or length reached
PatternUntil(&'static [u8], usize),
use super::{Len, Pattern, PatternUntil};

impl<'a> TryRead<'a, Len> for &'a [u8] {
#[inline]
fn try_read(bytes: &'a [u8], Len(len): Len) -> Result<(Self, usize)> {
check_len(bytes, len)?;
Ok((&bytes[..len], len))
}
}

impl<'a> TryRead<'a, Bytes> for &'a [u8] {
impl<'a> TryRead<'a, Pattern> for &'a [u8] {
#[inline]
fn try_read(bytes: &'a [u8], ctx: Bytes) -> Result<(Self, usize)> {
let len = match ctx {
Bytes::Len(len) => check_len(bytes, len)?,
Bytes::Pattern(pattern) => {
if pattern.is_empty() {
return Err(Error::BadInput {
err: "Pattern is empty",
});
}
check_len(bytes, pattern.len())?;
(0..bytes.len() - pattern.len() + 1)
.map(|n| bytes[n..].starts_with(pattern))
.position(|p| p)
.map(|len| len + pattern.len())
.ok_or(Error::Incomplete)?
}
Bytes::PatternUntil(pattern, len) => {
if pattern.is_empty() {
return Err(Error::BadInput {
err: "Pattern is empty",
});
}
if pattern.len() > len {
return Err(Error::BadInput {
err: "Pattern is longer than restricted length",
});
}
check_len(bytes, pattern.len())?;
(0..bytes.len() - pattern.len() + 1)
.map(|n| bytes[n..].starts_with(pattern))
.take(len - pattern.len())
.position(|p| p)
.map(|position| position + pattern.len())
.unwrap_or(check_len(bytes, len)?)
}
};
fn try_read(bytes: &'a [u8], Pattern(pattern): Pattern) -> Result<(Self, usize)> {
if pattern.is_empty() {
return Err(Error::BadInput {
err: "Pattern is empty",
});
}
check_len(bytes, pattern.len())?;
let len = (0..bytes.len() - pattern.len() + 1)
.map(|n| bytes[n..].starts_with(pattern))
.position(|p| p)
.map(|len| len + pattern.len())
.ok_or(Error::Incomplete)?;
Ok((&bytes[..len], len))
}
}

impl<'a> TryRead<'a, PatternUntil> for &'a [u8] {
#[inline]
fn try_read(
bytes: &'a [u8],
PatternUntil(pattern, len): PatternUntil,
) -> Result<(Self, usize)> {
if pattern.is_empty() {
return Err(Error::BadInput {
err: "Pattern is empty",
});
}
if pattern.len() > len {
return Err(Error::BadInput {
err: "Pattern is longer than restricted length",
});
}
check_len(bytes, pattern.len())?;
let len = (0..bytes.len() - pattern.len() + 1)
.map(|n| bytes[n..].starts_with(pattern))
.take(len - pattern.len())
.position(|p| p)
.map(|position| position + pattern.len())
.unwrap_or(check_len(bytes, len)?);
Ok((&bytes[..len], len))
}
}
Expand All @@ -81,7 +60,7 @@ impl<'a> TryWrite for &'a [u8] {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> Result<usize> {
check_len(bytes, self.len())?;

bytes[..self.len()].clone_from_slice(self);
bytes[..self.len()].copy_from_slice(self);

Ok(self.len())
}
Expand Down
10 changes: 0 additions & 10 deletions src/ctx/mod.rs

This file was deleted.

Loading