Skip to content

Commit

Permalink
Borrow instead of copying in IntoCtx, TryIntoCtx, Cwrite, Pwrite
Browse files Browse the repository at this point in the history
  • Loading branch information
willglynn committed Nov 1, 2018
1 parent dd1dbeb commit 29c9f68
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 104 deletions.
2 changes: 1 addition & 1 deletion scroll_derive/examples/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main () {
println!("data: {:?}", &data);
assert_eq!(data.id, 0xdeadbeefu32);
let mut bytes2 = vec![0; ::std::mem::size_of::<Data>()];
bytes2.pwrite_with(data, 0, LE).unwrap();
bytes2.pwrite_with(&data, 0, LE).unwrap();
let data: Data = bytes.pread_with(0, LE).unwrap();
let data2: Data = bytes2.pread_with(0, LE).unwrap();
assert_eq!(data, data2);
Expand Down
27 changes: 6 additions & 21 deletions scroll_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,16 @@ fn impl_try_into_ctx(name: &syn::Ident, fields: &syn::FieldsNamed) -> proc_macro
}).collect();

quote! {
impl<'a> ::scroll::ctx::TryIntoCtx<::scroll::Endian> for &'a #name {
impl ::scroll::ctx::TryIntoCtx<::scroll::Endian> for #name {
type Error = ::scroll::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> {
fn try_into_ctx(&self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> {
use ::scroll::Pwrite;
let offset = &mut 0;
#(#items;)*;
Ok(*offset)
}
}

impl ::scroll::ctx::TryIntoCtx<::scroll::Endian> for #name {
type Error = ::scroll::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) -> ::scroll::export::result::Result<usize, Self::Error> {
(&self).try_into_ctx(dst, ctx)
}
}
}
}

Expand Down Expand Up @@ -275,37 +267,30 @@ fn impl_into_ctx(name: &syn::Ident, fields: &syn::FieldsNamed) -> proc_macro2::T
quote! {
let size = ::scroll::export::mem::size_of::<#arrty>();
for i in 0..self.#ident.len() {
dst.cwrite_with(self.#ident[i], *offset, ctx);
dst.cwrite_with(&self.#ident[i], *offset, ctx);
*offset += size;
}
}
},
_ => {
quote! {
dst.cwrite_with(self.#ident, *offset, ctx);
dst.cwrite_with(&self.#ident, *offset, ctx);
*offset += #size;
}
}
}
}).collect();

quote! {
impl<'a> ::scroll::ctx::IntoCtx<::scroll::Endian> for &'a #name {
impl ::scroll::ctx::IntoCtx<::scroll::Endian> for #name {
#[inline]
fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) {
fn into_ctx(&self, dst: &mut [u8], ctx: ::scroll::Endian) {
use ::scroll::Cwrite;
let offset = &mut 0;
#(#items;)*;
()
}
}

impl ::scroll::ctx::IntoCtx<::scroll::Endian> for #name {
#[inline]
fn into_ctx(self, dst: &mut [u8], ctx: ::scroll::Endian) {
(&self).into_ctx(dst, ctx)
}
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions scroll_derive/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn test_data (){
assert_eq!(data.id, 0xdeadbeefu32);
assert_eq!(data.timestamp, 0.5f64);
let mut bytes2 = vec![0; ::std::mem::size_of::<Data>()];
bytes2.pwrite_with(data, 0, LE).unwrap();
bytes2.pwrite_with(&data, 0, LE).unwrap();
let data: Data = bytes.pread_with(0, LE).unwrap();
let data2: Data = bytes2.pread_with(0, LE).unwrap();
assert_eq!(data, data2);
Expand Down Expand Up @@ -83,7 +83,7 @@ fn test_iowrite (){
assert_eq!(bytes_null, bytes);

let mut bytes_null = [0u8; 8];
bytes_null.cwrite_with(data, 0, LE);
bytes_null.cwrite_with(&data, 0, LE);
println!("bytes_null: {:?}", &bytes_null);
println!("bytes : {:?}", &bytes);
assert_eq!(bytes_null, bytes);
Expand Down
82 changes: 37 additions & 45 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,14 @@ pub trait TryFromCtx<'a, Ctx: Copy = (), This: ?Sized = [u8]> where Self: 'a + S
}

/// Writes `Self` into `This` using the context `Ctx`
pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
fn into_ctx(self, &mut This, ctx: Ctx);
pub trait IntoCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
fn into_ctx(&self, &mut This, ctx: Ctx);
}

/// Tries to write `Self` into `This` using the context `Ctx`
pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]>: Sized {
pub trait TryIntoCtx<Ctx: Copy = (), This: ?Sized = [u8]> {
type Error;
fn try_into_ctx(self, &mut This, ctx: Ctx) -> Result<usize, Self::Error>;
fn try_into_ctx(&self, &mut This, ctx: Ctx) -> Result<usize, Self::Error>;
}

/// Gets the size of `Self` with a `Ctx`, and in `Self::Units`. Implementors can then call `Gread` related functions
Expand Down Expand Up @@ -176,21 +176,15 @@ macro_rules! into_ctx_impl {
($typ:tt, $size:expr) => {
impl IntoCtx<Endian> for $typ {
#[inline]
fn into_ctx(self, dst: &mut [u8], le: Endian) {
fn into_ctx(&self, dst: &mut [u8], le: Endian) {
assert!(dst.len() >= $size);
write_into!($typ, $size, self, dst, le);
}
}
impl<'a> IntoCtx<Endian> for &'a $typ {
#[inline]
fn into_ctx(self, dst: &mut [u8], le: Endian) {
(*self).into_ctx(dst, le)
}
}
impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
if $size > dst.len () {
Err(error::Error::TooBig{size: $size, len: dst.len()})
} else {
Expand All @@ -199,13 +193,6 @@ macro_rules! into_ctx_impl {
}
}
}
impl<'a> TryIntoCtx<Endian> for &'a $typ {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
(*self).try_into_ctx(dst, le)
}
}
}
}

Expand Down Expand Up @@ -334,21 +321,15 @@ macro_rules! into_ctx_float_impl {
($typ:tt, $size:expr) => {
impl IntoCtx<Endian> for $typ {
#[inline]
fn into_ctx(self, dst: &mut [u8], le: Endian) {
fn into_ctx(&self, dst: &mut [u8], le: Endian) {
assert!(dst.len() >= $size);
write_into!(signed_to_unsigned!($typ), $size, transmute::<$typ, signed_to_unsigned!($typ)>(self), dst, le);
}
}
impl<'a> IntoCtx<Endian> for &'a $typ {
#[inline]
fn into_ctx(self, dst: &mut [u8], le: Endian) {
(*self).into_ctx(dst, le)
write_into!(signed_to_unsigned!($typ), $size, transmute::<$typ, signed_to_unsigned!($typ)>(*self), dst, le);
}
}
impl TryIntoCtx<Endian> for $typ where $typ: IntoCtx<Endian> {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
if $size > dst.len () {
Err(error::Error::TooBig{size: $size, len: dst.len()})
} else {
Expand All @@ -357,13 +338,6 @@ macro_rules! into_ctx_float_impl {
}
}
}
impl<'a> TryIntoCtx<Endian> for &'a $typ {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
(*self).try_into_ctx(dst, le)
}
}
}
}

Expand Down Expand Up @@ -410,10 +384,10 @@ impl<'a, T> TryFromCtx<'a, StrCtx, T> for &'a str where T: AsRef<[u8]> {
}
}

impl<'a> TryIntoCtx for &'a [u8] {
impl TryIntoCtx for [u8] {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
let src_len = self.len() as isize;
let dst_len = dst.len() as isize;
// if src_len < 0 || dst_len < 0 || offset < 0 {
Expand All @@ -429,15 +403,33 @@ impl<'a> TryIntoCtx for &'a [u8] {
}

// TODO: make TryIntoCtx use StrCtx for awesomeness
impl<'a> TryIntoCtx for &'a str {
impl TryIntoCtx for str {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
let bytes = self.as_bytes();
TryIntoCtx::try_into_ctx(bytes, dst, ())
TryIntoCtx::try_into_ctx(&bytes, dst, ())
}
}

// Implement borrowed versions for these types for convenience
impl<'a> TryIntoCtx for &'a [u8] {
type Error = error::Error;
#[inline]
fn try_into_ctx(&self, dst: &mut [u8], ctx: ()) -> error::Result<usize> {
(*self).try_into_ctx(dst, ctx)
}
}

impl<'a> TryIntoCtx for &'a str {
type Error = error::Error;
#[inline]
fn try_into_ctx(&self, dst: &mut [u8], ctx: ()) -> error::Result<usize> {
(*self).try_into_ctx(dst, ctx)
}
}


// TODO: we can make this compile time without size_of call, but compiler probably does that anyway
macro_rules! sizeof_impl {
($ty:ty) => {
Expand Down Expand Up @@ -510,7 +502,7 @@ impl<'a> TryFromCtx<'a, usize> for &'a[u8] {

impl IntoCtx<Endian> for usize {
#[inline]
fn into_ctx(self, dst: &mut [u8], le: Endian) {
fn into_ctx(&self, dst: &mut [u8], le: Endian) {
let size = ::core::mem::size_of::<Self>();
assert!(dst.len() >= size);
let mut data = if le.is_little() { self.to_le() } else { self.to_be() };
Expand All @@ -524,7 +516,7 @@ impl IntoCtx<Endian> for usize {
impl TryIntoCtx<Endian> for usize where usize: IntoCtx<Endian> {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], le: Endian) -> error::Result<usize> {
let size = ::core::mem::size_of::<usize>();
if size > dst.len() {
Err(error::Error::TooBig{size, len: dst.len()})
Expand Down Expand Up @@ -564,10 +556,10 @@ impl<'a> TryFromCtx<'a> for CString {
}

#[cfg(feature = "std")]
impl<'a> TryIntoCtx for &'a CStr {
impl TryIntoCtx for CStr {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
let data = self.to_bytes_with_nul();

if dst.len() < data.len() {
Expand All @@ -589,7 +581,7 @@ impl<'a> TryIntoCtx for &'a CStr {
impl TryIntoCtx for CString {
type Error = error::Error;
#[inline]
fn try_into_ctx(self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
fn try_into_ctx(&self, dst: &mut [u8], _ctx: ()) -> error::Result<usize> {
self.as_c_str().try_into_ctx(dst, ())
}
}
Expand Down
22 changes: 11 additions & 11 deletions src/greater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,16 @@ impl<Ctx: Copy, I, R: ?Sized + Index<I> + Index<RangeFrom<I>>> Cread<Ctx, I> for
/// }
///
/// impl ctx::IntoCtx<scroll::Endian> for Bar {
/// fn into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) {
/// fn into_ctx(&self, bytes: &mut [u8], ctx: scroll::Endian) {
/// use scroll::Cwrite;
/// bytes.cwrite_with(self.foo, 0, ctx);
/// bytes.cwrite_with(self.bar, 4, ctx);
/// bytes.cwrite_with(&self.foo, 0, ctx);
/// bytes.cwrite_with(&self.bar, 4, ctx);
/// }
/// }
///
/// let bar = Bar { foo: -1, bar: 0xdeadbeef };
/// let mut bytes = [0x0; 16];
/// bytes.cwrite::<Bar>(bar, 0);
/// bytes.cwrite::<Bar>(&bar, 0);
/// ```
pub trait Cwrite<Ctx: Copy, I = usize>: Index<I> + IndexMut<RangeFrom<I>> {
/// Writes `n` into `Self` at `offset`; uses default context.
Expand All @@ -121,15 +121,15 @@ pub trait Cwrite<Ctx: Copy, I = usize>: Index<I> + IndexMut<RangeFrom<I>> {
/// ```
/// use scroll::{Cwrite, Cread};
/// let mut bytes = [0x0; 16];
/// bytes.cwrite::<i64>(42, 0);
/// bytes.cwrite::<u32>(0xdeadbeef, 8);
/// bytes.cwrite::<i64>(&42, 0);
/// bytes.cwrite::<u32>(&0xdeadbeef, 8);
///
/// assert_eq!(bytes.cread::<i64>(0), 42);
/// assert_eq!(bytes.cread::<u32>(8), 0xdeadbeef);
#[inline]
fn cwrite<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I) where Ctx: Default {
fn cwrite<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: &N, offset: I) where Ctx: Default {
let ctx = Ctx::default();
n.into_ctx(self.index_mut(offset..), ctx)
n.into_ctx(self.index_mut( offset..), ctx)
}
/// Writes `n` into `Self` at `offset` with `ctx`
///
Expand All @@ -138,12 +138,12 @@ pub trait Cwrite<Ctx: Copy, I = usize>: Index<I> + IndexMut<RangeFrom<I>> {
/// ```
/// use scroll::{Cwrite, Cread, LE, BE};
/// let mut bytes = [0x0; 0x10];
/// bytes.cwrite_with::<i64>(42, 0, LE);
/// bytes.cwrite_with::<u32>(0xdeadbeef, 8, BE);
/// bytes.cwrite_with::<i64>(&42, 0, LE);
/// bytes.cwrite_with::<u32>(&0xdeadbeef, 8, BE);
/// assert_eq!(bytes.cread_with::<i64>(0, LE), 42);
/// assert_eq!(bytes.cread_with::<u32>(8, LE), 0xefbeadde);
#[inline]
fn cwrite_with<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: N, offset: I, ctx: Ctx) {
fn cwrite_with<N: IntoCtx<Ctx, <Self as Index<RangeFrom<I>>>::Output>>(&mut self, n: &N, offset: I, ctx: Ctx) {
n.into_ctx(self.index_mut(offset..), ctx)
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ mod tests {
use super::{Pwrite, Pread, BE};
let mut bytes: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
let b = &mut bytes[..];
b.pwrite_with::<$read>($deadbeef, 0, LE).unwrap();
b.pwrite_with::<$read>(&$deadbeef, 0, LE).unwrap();
assert_eq!(b.pread_with::<$read>(0, LE).unwrap(), $deadbeef);
b.pwrite_with::<$read>($deadbeef, 0, BE).unwrap();
b.pwrite_with::<$read>(&$deadbeef, 0, BE).unwrap();
assert_eq!(b.pread_with::<$read>(0, BE).unwrap(), $deadbeef);
}
}
Expand Down Expand Up @@ -303,13 +303,13 @@ mod tests {
use super::ctx::*;
let astring: &str = "lol hello_world lal\0ala imabytes";
let mut buffer = [0u8; 33];
buffer.pwrite(astring, 0).unwrap();
buffer.pwrite(&astring, 0).unwrap();
{
let hello_world = buffer.pread_with::<&str>(4, StrCtx::Delimiter(SPACE)).unwrap();
assert_eq!(hello_world, "hello_world");
}
let bytes: &[u8] = b"more\0bytes";
buffer.pwrite(bytes, 0).unwrap();
buffer.pwrite(&bytes, 0).unwrap();
let more = bytes.pread_with::<&str>(0, StrCtx::Delimiter(NULL)).unwrap();
assert_eq!(more, "more");
let bytes = bytes.pread_with::<&str>(more.len() + 1, StrCtx::Delimiter(NULL)).unwrap();
Expand Down Expand Up @@ -349,10 +349,10 @@ mod tests {

impl super::ctx::TryIntoCtx<super::Endian> for Foo {
type Error = ExternalError;
fn try_into_ctx(self, this: &mut [u8], le: super::Endian) -> Result<usize, Self::Error> {
fn try_into_ctx(&self, this: &mut [u8], le: super::Endian) -> Result<usize, Self::Error> {
use super::Pwrite;
if this.len() < 2 { return Err((ExternalError {}).into()) }
this.pwrite_with(self.0, 0, le)?;
this.pwrite_with(&self.0, 0, le)?;
Ok(2)
}
}
Expand Down Expand Up @@ -430,14 +430,14 @@ mod tests {
use super::{LE, BE, Pread, Pwrite};
let mut buffer = [0u8; 16];
let offset = &mut 0;
buffer.gwrite_with($val.clone(), offset, LE).unwrap();
buffer.gwrite_with(&$val, offset, LE).unwrap();
let o2 = &mut 0;
let val: $typ = buffer.gread_with(o2, LE).unwrap();
assert_eq!(val, $val);
assert_eq!(*offset, ::std::mem::size_of::<$typ>());
assert_eq!(*o2, ::std::mem::size_of::<$typ>());
assert_eq!(*o2, *offset);
buffer.gwrite_with($val.clone(), offset, BE).unwrap();
buffer.gwrite_with(&$val, offset, BE).unwrap();
let val: $typ = buffer.gread_with(o2, BE).unwrap();
assert_eq!(val, $val);
}
Expand Down
Loading

0 comments on commit 29c9f68

Please sign in to comment.