From bd2c643e17aa62775f84a3449da2b7b47288d008 Mon Sep 17 00:00:00 2001 From: Carl Lerche <me@carllerche.com> Date: Mon, 23 Mar 2015 23:22:21 -0700 Subject: [PATCH] Flesh out ToBytes, ByteStr::concat, and ByteStr eq --- src/byte_str.rs | 16 +++++--- src/bytes.rs | 13 ++++--- src/lib.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++--- src/rope.rs | 8 ++-- test/test_rope.rs | 16 +++++++- 5 files changed, 131 insertions(+), 20 deletions(-) diff --git a/src/byte_str.rs b/src/byte_str.rs index ee420cf..831c9c5 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -1,5 +1,5 @@ -use {alloc, Bytes, ByteBuf, ROByteBuf}; -use traits::{Buf, MutBuf, MutBufExt, ByteStr}; +use {alloc, Bytes, ByteBuf, ROByteBuf, Rope}; +use traits::{Buf, MutBuf, MutBufExt, ByteStr, ToBytes}; use std::{cmp, ops}; /* @@ -53,8 +53,8 @@ impl ByteStr for SeqByteStr { } } - fn concat<B: ByteStr>(&self, _other: B) -> Bytes { - unimplemented!(); + fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes { + Rope::of(self.clone()).concat(other) } fn len(&self) -> usize { @@ -75,7 +75,9 @@ impl ByteStr for SeqByteStr { Bytes::of(bytes) } +} +impl ToBytes for SeqByteStr { fn to_bytes(self) -> Bytes { Bytes::of(self) } @@ -159,8 +161,8 @@ impl ByteStr for SmallByteStr { SmallByteStrBuf { small: self.clone() } } - fn concat<B: ByteStr>(&self, _other: B) -> Bytes { - unimplemented!(); + fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes { + Rope::of(self.clone()).concat(other) } fn len(&self) -> usize { @@ -174,7 +176,9 @@ impl ByteStr for SmallByteStr { fn split_at(&self, _mid: usize) -> (Bytes, Bytes) { unimplemented!(); } +} +impl ToBytes for SmallByteStr { fn to_bytes(self) -> Bytes { Bytes::of(self) } diff --git a/src/bytes.rs b/src/bytes.rs index 963fdb8..149a4d8 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1,4 +1,5 @@ -use {Buf, ByteStr, ByteBuf, SmallByteStr}; +use {ByteBuf, SmallByteStr}; +use traits::{Buf, ByteStr, ToBytes}; use std::{fmt, mem, ops, ptr}; use std::any::{Any, TypeId}; use std::raw::TraitObject; @@ -136,8 +137,8 @@ impl ByteStr for Bytes { self.obj().buf() } - fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes { - self.obj().concat(Bytes::of(other)) + fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes { + self.obj().concat(&Bytes::of(other.clone())) } fn len(&self) -> usize { @@ -151,7 +152,9 @@ impl ByteStr for Bytes { fn split_at(&self, mid: usize) -> (Bytes, Bytes) { self.obj().split_at(mid) } +} +impl ToBytes for Bytes { fn to_bytes(self) -> Bytes { self } @@ -203,7 +206,7 @@ trait ByteStrPriv { fn clone(&self) -> Bytes; - fn concat(&self, other: Bytes) -> Bytes; + fn concat(&self, other: &Bytes) -> Bytes; fn drop(&mut self); @@ -228,7 +231,7 @@ impl<B: ByteStr + 'static> ByteStrPriv for B { Bytes::of(self.clone()) } - fn concat(&self, other: Bytes) -> Bytes { + fn concat(&self, other: &Bytes) -> Bytes { self.concat(other) } diff --git a/src/lib.rs b/src/lib.rs index c4ce64e..adb35b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ mod slice; pub mod traits { //! All traits are re-exported here to allow glob imports. - pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr}; + pub use {Buf, BufExt, MutBuf, MutBufExt, ByteStr, ToBytes}; } const MAX_CAPACITY: usize = u32::MAX as usize; @@ -198,7 +198,7 @@ pub trait MutBufExt { /// An immutable sequence of bytes. Operations will not mutate the original /// value. Since only immutable access is permitted, operations do not require /// copying (though, sometimes copying will happen as an optimization). -pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> { +pub trait ByteStr : Clone + Sized + Send + Sync + ToBytes + ops::Index<usize, Output=u8> { // Until HKT lands, the buf must be bound by 'static type Buf: Buf+'static; @@ -209,7 +209,7 @@ pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> { /// Returns a new `Bytes` value representing the concatenation of `self` /// with the given `Bytes`. - fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes; + fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes; /// Returns the number of bytes in the ByteStr fn len(&self) -> usize; @@ -249,12 +249,75 @@ pub trait ByteStr : Clone + Sized + Send + Sync + ops::Index<usize, Output=u8> { fn split_at(&self, mid: usize) -> (Bytes, Bytes) { (self.slice_to(mid), self.slice_from(mid)) } +} + +impl<B1: ByteStr, B2: ByteStr> cmp::PartialEq<B2> for B1 { + fn eq(&self, other: &B2) -> bool { + if self.len() != other.len() { + return false; + } + + let mut buf1 = self.buf(); + let mut buf2 = self.buf(); + + while buf1.has_remaining() { + let len; + + { + let b1 = buf1.bytes(); + let b2 = buf2.bytes(); + + len = cmp::min(b1.len(), b2.len()); + + if b1[..len] != b2[..len] { + return false; + } + } + + buf1.advance(len); + buf2.advance(len); + } + + true + } + + fn ne(&self, other: &B2) -> bool { + return !self.eq(other) + } +} + +macro_rules! impl_eq { + ($ty:ty) => { + impl cmp::Eq for $ty {} + } +} +impl_eq!(Bytes); + +/* + * + * ===== ToBytes ===== + * + */ + +pub trait ToBytes { /// Consumes the value and returns a `Bytes` instance containing /// identical bytes fn to_bytes(self) -> Bytes; } +impl<'a> ToBytes for &'a [u8] { + fn to_bytes(self) -> Bytes { + Bytes::from_slice(self) + } +} + +impl<'a> ToBytes for &'a Vec<u8> { + fn to_bytes(self) -> Bytes { + self.as_slice().to_bytes() + } +} + /* * * ===== *Ext impls ===== @@ -351,8 +414,33 @@ impl<'a> Source for &'a Vec<u8> { impl<'a> Source for &'a Bytes { type Error = BufError; - fn fill<B: MutBuf>(self, _buf: &mut B) -> Result<usize, BufError> { - unimplemented!(); + fn fill<B: MutBuf>(self, dst: &mut B) -> Result<usize, BufError> { + let mut src = self.buf(); + let mut res = 0; + + while src.has_remaining() && dst.has_remaining() { + let mut l; + + { + let s = src.bytes(); + let d = dst.mut_bytes(); + l = cmp::min(s.len(), d.len()); + + unsafe { + ptr::copy_nonoverlapping( + d.as_mut_ptr(), + s.as_ptr(), + l); + } + } + + src.advance(l); + dst.advance(l); + + res += l; + } + + Ok(res) } } diff --git a/src/rope.rs b/src/rope.rs index 6cae0a6..180859e 100644 --- a/src/rope.rs +++ b/src/rope.rs @@ -1,5 +1,5 @@ use {Bytes, ByteBuf, Source, BufError}; -use traits::*; +use traits::{Buf, ByteStr, MutBuf, MutBufExt, ToBytes}; use std::{cmp, mem, ops}; use std::sync::Arc; @@ -98,9 +98,9 @@ impl ByteStr for Rope { RopeBuf::new(self.clone()) } - fn concat<B: ByteStr+'static>(&self, other: B) -> Bytes { + fn concat<B: ByteStr+'static>(&self, other: &B) -> Bytes { let left = Bytes::of(self.clone()); - let right = Bytes::of(other); + let right = Bytes::of(other.clone()); Bytes::of(concat(left, right)) } @@ -146,7 +146,9 @@ impl ByteStr for Rope { Bytes::of(Rope::new(left_slice, right_slice)) } +} +impl ToBytes for Rope { fn to_bytes(self) -> Bytes { Bytes::of(self) } diff --git a/test/test_rope.rs b/test/test_rope.rs index af7870e..27070cf 100644 --- a/test/test_rope.rs +++ b/test/test_rope.rs @@ -69,7 +69,7 @@ pub fn test_rope_concat_two_byte_str() { let left = Rope::from_slice(TEST_BYTES_1); let right = Rope::from_slice(TEST_BYTES_2); - let both = left.concat(right); + let both = left.concat(&right); assert_eq!(both.len(), TEST_BYTES_1.len() + TEST_BYTES_2.len()); @@ -88,3 +88,17 @@ pub fn test_slice_parity() { // stuff } + +#[test] +pub fn test_rope_equality() { + let a = &b"Mary had a little lamb, its fleece was white as snow; ".to_bytes() + .concat(&b"And everywhere that Mary went, the lamb was sure to go.".to_bytes()); + + let b = &b"Mary had a little lamb, ".to_bytes() + .concat(&b"its fleece was white as snow; ".to_bytes()) + .concat( + &b"And everywhere that Mary went, ".to_bytes() + .concat(&b"the lamb was sure to go.".to_bytes())); + + assert_eq!(a, b); +} -- GitLab