| // Copyright (C) 2018, Cloudflare, Inc. |
| // Copyright (C) 2018, Alessandro Ghedini |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| /// Zero-copy abstraction for parsing and constructing network packets. |
| |
| use std::mem; |
| use std::ptr; |
| |
| use crate::Result; |
| use crate::Error; |
| |
| macro_rules! peek_u { |
| ($b:expr, $ty:ty, $len:expr) => ({ |
| let src = &$b.buf[$b.off..]; |
| |
| if src.len() < $len { |
| return Err(Error::BufferTooShort); |
| } |
| |
| let mut out: $ty = 0; |
| unsafe { |
| let dst = &mut out as *mut $ty as *mut u8; |
| let off = (mem::size_of::<$ty>() - $len) as isize; |
| |
| ptr::copy_nonoverlapping(src.as_ptr(), dst.offset(off), $len); |
| }; |
| |
| Ok(<$ty>::from_be(out)) |
| }); |
| } |
| |
| macro_rules! get_u { |
| ($b:expr, $ty:ty, $len:expr) => ({ |
| let out = peek_u!($b, $ty, $len); |
| |
| $b.off += $len; |
| |
| out |
| }); |
| } |
| |
| macro_rules! put_u { |
| ($b:expr, $ty:ty, $v:expr, $len:expr) => ({ |
| let dst = &mut $b.buf[$b.off..]; |
| |
| if dst.len() < $len { |
| return Err(Error::BufferTooShort) |
| } |
| |
| unsafe { |
| let src = &<$ty>::to_be($v) as *const $ty as *const u8; |
| let off = (mem::size_of::<$ty>() - $len) as isize; |
| |
| ptr::copy_nonoverlapping(src.offset(off), dst.as_mut_ptr(), $len); |
| } |
| |
| $b.off += $len; |
| |
| Ok(dst) |
| }); |
| } |
| |
| /// A zero-copy mutable byte buffer. |
| /// |
| /// `Octets` wraps an in-memory buffer of bytes and provides utility functions |
| /// for manipulating it. The underlying buffer is provided by the user and is |
| /// not copied when creating an `Octets`. Operations are panic-free and will |
| /// avoid indexing the buffer past its end. |
| /// |
| /// Additionally, an offset (initially set to the start of the buffer) is |
| /// incremented as bytes are read from / written to the buffer, to allow for |
| /// sequential operations. |
| #[derive(Debug, PartialEq)] |
| pub struct Octets<'a> { |
| buf: &'a mut [u8], |
| off: usize, |
| } |
| |
| impl<'a> Octets<'a> { |
| /// Creates an `Octets` from the given slice, without copying. |
| /// |
| /// Since there's no copy, the input slice needs to be mutable to allow |
| /// modifications. |
| pub fn with_slice(buf: &'a mut [u8]) -> Octets { |
| Octets { buf, off: 0 } |
| } |
| |
| /// Reads an unsigned 8-bit integer from the current offset and advances |
| /// the buffer. |
| pub fn get_u8(&mut self) -> Result<u8> { |
| get_u!(self, u8, 1) |
| } |
| |
| /// Reads an unsigned 8-bit integer from the current offset without |
| /// advancing the buffer. |
| pub fn peek_u8(&mut self) -> Result<u8> { |
| peek_u!(self, u8, 1) |
| } |
| |
| /// Writes an unsigned 8-bit integer at the current offset and advances |
| /// the buffer. |
| pub fn put_u8(&mut self, v: u8) -> Result<&mut [u8]> { |
| put_u!(self, u8, v, 1) |
| } |
| |
| /// Reads an unsigned 16-bit integer in network byte-order from the current |
| /// offset and advances the buffer. |
| pub fn get_u16(&mut self) -> Result<u16> { |
| get_u!(self, u16, 2) |
| } |
| |
| /// Writes an unsigned 16-bit integer in network byte-order at the current |
| /// offset and advances the buffer. |
| pub fn put_u16(&mut self, v: u16) -> Result<&mut [u8]> { |
| put_u!(self, u16, v, 2) |
| } |
| |
| /// Reads an unsigned 24-bit integer in network byte-order from the current |
| /// offset and advances the buffer. |
| pub fn get_u24(&mut self) -> Result<u32> { |
| get_u!(self, u32, 3) |
| } |
| |
| /// Writes an unsigned 24-bit integer in network byte-order at the current |
| /// offset and advances the buffer. |
| pub fn put_u24(&mut self, v: u32) -> Result<&mut [u8]> { |
| put_u!(self, u32, v, 3) |
| } |
| |
| /// Reads an unsigned 32-bit integer in network byte-order from the current |
| /// offset and advances the buffer. |
| pub fn get_u32(&mut self) -> Result<u32> { |
| get_u!(self, u32, 4) |
| } |
| |
| /// Writes an unsigned 32-bit integer in network byte-order at the current |
| /// offset and advances the buffer. |
| pub fn put_u32(&mut self, v: u32) -> Result<&mut [u8]> { |
| put_u!(self, u32, v, 4) |
| } |
| |
| /// Reads an unsigned 64-bit integer in network byte-order from the current |
| /// offset and advances the buffer. |
| pub fn get_u64(&mut self) -> Result<u64> { |
| get_u!(self, u64, 8) |
| } |
| |
| /// Writes an unsigned 64-bit integer in network byte-order at the current |
| /// offset and advances the buffer. |
| pub fn put_u64(&mut self, v: u64) -> Result<&mut [u8]> { |
| put_u!(self, u64, v, 8) |
| } |
| |
| /// Reads an unsigned variable-length integer in network byte-order from |
| /// the current offset and advances the buffer. |
| pub fn get_varint(&mut self) -> Result<u64> { |
| let first = self.peek_u8()?; |
| |
| let len = match first >> 6 { |
| 0 => 1, |
| 1 => 2, |
| 2 => 4, |
| 3 => 8, |
| _ => return Err(Error::BufferTooShort), |
| }; |
| |
| let mut vec = self.get_bytes(len)?.to_vec(); |
| |
| // Mask the 2 most significant bits to remove the encoded length. |
| vec[0] &= 0x3f; |
| |
| let mut b = Octets::with_slice(&mut vec); |
| |
| let out = match len { |
| 1 => u64::from(b.get_u8()?), |
| 2 => u64::from(b.get_u16()?), |
| 4 => u64::from(b.get_u32()?), |
| 8 => b.get_u64()?, |
| _ => return Err(Error::BufferTooShort), |
| }; |
| |
| Ok(out) |
| } |
| |
| /// Writes an unsigned variable-length integer in network byte-order at the |
| /// current offset and advances the buffer. |
| pub fn put_varint(&mut self, v: u64) -> Result<()> { |
| if self.cap() == 0 { |
| return Err(Error::BufferTooShort); |
| } |
| |
| if v <= 63 { |
| self.put_u8(v as u8)?; |
| } else if v <= 16383 { |
| let buf = self.put_u16(v as u16)?; |
| buf[0] |= 0x40; |
| } else if v <= 1_073_741_823 { |
| let buf = self.put_u32(v as u32)?; |
| buf[0] |= 0x80; |
| } else if v <= 4_611_686_018_427_387_903 { |
| let buf = self.put_u64(v)?; |
| buf[0] |= 0xc0; |
| } else { |
| return Err(Error::BufferTooShort); |
| }; |
| |
| Ok(()) |
| } |
| |
| /// Reads `len` bytes from the current offset without copying and advances |
| /// the buffer. |
| pub fn get_bytes(&mut self, len: usize) -> Result<Octets> { |
| if self.cap() < len { |
| return Err(Error::BufferTooShort) |
| } |
| |
| let out = Octets { |
| buf: &mut self.buf[self.off..self.off + len], |
| off: 0, |
| }; |
| |
| self.off += len; |
| |
| Ok(out) |
| } |
| |
| /// Reads `len` bytes from the current offset without copying and advances |
| /// the buffer, where `len` is an unsigned 8-bit integer prefix. |
| pub fn get_bytes_with_u8_length(&mut self) -> Result<Octets> { |
| let len = self.get_u8()?; |
| self.get_bytes(len as usize) |
| } |
| |
| /// Reads `len` bytes from the current offset without copying and advances |
| /// the buffer, where `len` is an unsigned 16-bit integer prefix in network |
| /// byte-order. |
| pub fn get_bytes_with_u16_length(&mut self) -> Result<Octets> { |
| let len = self.get_u16()?; |
| self.get_bytes(len as usize) |
| } |
| |
| /// Reads `len` bytes from the current offset without copying and advances |
| /// the buffer, where `len` is an unsigned variable-length integer prefix |
| /// in network byte-order. |
| pub fn get_bytes_with_varint_length(&mut self) -> Result<Octets> { |
| let len = self.get_varint()?; |
| self.get_bytes(len as usize) |
| } |
| |
| /// Reads `len` bytes from the current offset without copying and without |
| /// advancing the buffer. |
| pub fn peek_bytes(&mut self, len: usize) -> Result<Octets> { |
| if self.cap() < len { |
| return Err(Error::BufferTooShort) |
| } |
| |
| let out = Octets { |
| buf: &mut self.buf[self.off..self.off + len], |
| off: 0, |
| }; |
| |
| Ok(out) |
| } |
| |
| /// Writes `len` bytes from the current offset without copying and advances |
| /// the buffer. |
| pub fn put_bytes(&mut self, v: &[u8]) -> Result<()> { |
| let len = v.len(); |
| |
| if self.cap() < len { |
| return Err(Error::BufferTooShort) |
| } |
| |
| if len == 0 { |
| return Ok(()); |
| } |
| |
| self.as_mut()[..len].copy_from_slice(v); |
| |
| self.off += len; |
| |
| Ok(()) |
| } |
| |
| /// Splits the buffer in two at the given absolute offset. |
| pub fn split_at(&mut self, off: usize) -> Result<(Octets, Octets)> { |
| if self.len() < off { |
| return Err(Error::BufferTooShort); |
| } |
| |
| let (left, right) = self.buf.split_at_mut(off); |
| |
| let first = Octets { |
| buf: left, |
| off: 0, |
| }; |
| |
| let last = Octets { |
| buf: right, |
| off: 0, |
| }; |
| |
| Ok((first, last)) |
| } |
| |
| /// Returns a slice of `len` elements from the current offset. |
| pub fn slice(&'a mut self, len: usize) -> Result<&'a mut [u8]> { |
| if len > self.cap() { |
| return Err(Error::BufferTooShort); |
| } |
| |
| Ok(&mut self.buf[self.off..self.off + len]) |
| } |
| |
| /// Returns a slice of `len` elements from the end of the buffer. |
| pub fn slice_last(&'a mut self, len: usize) -> Result<&'a mut [u8]> { |
| if len > self.cap() { |
| return Err(Error::BufferTooShort); |
| } |
| |
| let cap = self.cap(); |
| Ok(&mut self.buf[cap - len..]) |
| } |
| |
| /// Returns the remaining capacity in the buffer. |
| pub fn cap(&self) -> usize { |
| self.buf.len() - self.off |
| } |
| |
| /// Returns the total length of the buffer. |
| pub fn len(&self) -> usize { |
| self.buf.len() |
| } |
| |
| /// Returns the current offset of the buffer. |
| pub fn off(&self) -> usize { |
| self.off |
| } |
| |
| /// Copies the buffer from the current offset into a new `Vec<u8>`. |
| pub fn to_vec(&self) -> Vec<u8> { |
| self.as_ref().to_vec() |
| } |
| } |
| |
| impl<'a> AsRef<[u8]> for Octets<'a> { |
| fn as_ref(&self) -> &[u8] { |
| &self.buf[self.off..] |
| } |
| } |
| |
| impl<'a> AsMut<[u8]> for Octets<'a> { |
| fn as_mut(&mut self) -> &mut [u8] { |
| &mut self.buf[self.off..] |
| } |
| } |
| |
| /// Returns how many bytes it would take to encode `v` as a variable-length |
| /// integer. |
| pub fn varint_len(v: u64) -> usize { |
| if v <= 63 { |
| 1 |
| } else if v <= 16383 { |
| 2 |
| } else if v <= 1_073_741_823 { |
| 4 |
| } else if v <= 4_611_686_018_427_387_903 { |
| 8 |
| } else { |
| unreachable!() |
| } |
| } |
| |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn get_u() { |
| let mut d: [u8; 18] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 15, 16, 17, 18]; |
| |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 18); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.get_u8().unwrap(), 1); |
| assert_eq!(b.cap(), 17); |
| assert_eq!(b.off(), 1); |
| |
| assert_eq!(b.get_u16().unwrap(), 0x203); |
| assert_eq!(b.cap(), 15); |
| assert_eq!(b.off(), 3); |
| |
| assert_eq!(b.get_u24().unwrap(), 0x40506); |
| assert_eq!(b.cap(), 12); |
| assert_eq!(b.off(), 6); |
| |
| assert_eq!(b.get_u32().unwrap(), 0x0708090a); |
| assert_eq!(b.cap(), 8); |
| assert_eq!(b.off(), 10); |
| |
| assert_eq!(b.get_u64().unwrap(), 0x0b0c0d0e0f101112); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 18); |
| |
| assert!(b.get_u8().is_err()); |
| assert!(b.get_u16().is_err()); |
| assert!(b.get_u24().is_err()); |
| assert!(b.get_u32().is_err()); |
| assert!(b.get_u64().is_err()); |
| } |
| |
| #[test] |
| fn peek_u() { |
| let mut d: [u8; 2] = [1, 2]; |
| |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 2); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.peek_u8().unwrap(), 1); |
| assert_eq!(b.cap(), 2); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.peek_u8().unwrap(), 1); |
| assert_eq!(b.cap(), 2); |
| assert_eq!(b.off(), 0); |
| |
| b.get_u16().unwrap(); |
| |
| assert!(b.peek_u8().is_err()); |
| } |
| |
| #[test] |
| fn get_bytes() { |
| let mut d: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 10); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.get_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]); |
| assert_eq!(b.cap(), 5); |
| assert_eq!(b.off(), 5); |
| |
| assert_eq!(b.get_bytes(3).unwrap().as_ref(), [6, 7, 8]); |
| assert_eq!(b.cap(), 2); |
| assert_eq!(b.off(), 8); |
| |
| assert!(b.get_bytes(3).is_err()); |
| assert_eq!(b.cap(), 2); |
| assert_eq!(b.off(), 8); |
| |
| assert_eq!(b.get_bytes(2).unwrap().as_ref(), [9, 10]); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 10); |
| |
| assert!(b.get_bytes(2).is_err()); |
| } |
| |
| #[test] |
| fn peek_bytes() { |
| let mut d: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 10); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]); |
| assert_eq!(b.cap(), 10); |
| assert_eq!(b.off(), 0); |
| |
| assert_eq!(b.peek_bytes(5).unwrap().as_ref(), [1, 2, 3, 4, 5]); |
| assert_eq!(b.cap(), 10); |
| assert_eq!(b.off(), 0); |
| |
| b.get_bytes(5).unwrap(); |
| } |
| |
| #[test] |
| fn get_varint() { |
| let mut d: [u8; 8] = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.get_varint().unwrap(), 151288809941952652); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 8); |
| |
| let mut d: [u8; 4] = [0x9d, 0x7f, 0x3e, 0x7d]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.get_varint().unwrap(), 494878333); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 4); |
| |
| let mut d: [u8; 2] = [0x7b, 0xbd]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.get_varint().unwrap(), 15293); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 2); |
| |
| let mut d: [u8; 2] = [0x40, 0x25]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.get_varint().unwrap(), 37); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 2); |
| |
| let mut d: [u8; 1] = [0x25]; |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.get_varint().unwrap(), 37); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 1); |
| } |
| |
| #[test] |
| fn put_varint() { |
| let mut d: [u8; 8] = [0; 8]; |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.put_varint(151288809941952652).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 8); |
| } |
| let exp: [u8; 8] = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c]; |
| assert_eq!(&d, &exp); |
| |
| let mut d: [u8; 4] = [0; 4]; |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.put_varint(494878333).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 4); |
| } |
| let exp: [u8; 4] = [0x9d, 0x7f, 0x3e, 0x7d]; |
| assert_eq!(&d, &exp); |
| |
| let mut d: [u8; 2] = [0; 2]; |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.put_varint(15293).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 2); |
| } |
| let exp: [u8; 2] = [0x7b, 0xbd]; |
| assert_eq!(&d, &exp); |
| |
| let mut d: [u8; 1] = [0; 1]; |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.put_varint(37).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 1); |
| } |
| let exp: [u8; 1] = [0x25]; |
| assert_eq!(&d, &exp); |
| |
| let mut d: [u8; 3] = [0; 3]; |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.put_varint(151288809941952652).is_err()); |
| assert_eq!(b.cap(), 3); |
| assert_eq!(b.off(), 0); |
| } |
| let exp: [u8; 3] = [0; 3]; |
| assert_eq!(&d, &exp); |
| } |
| |
| #[test] |
| fn put_u() { |
| let mut d: [u8; 18] = [0; 18]; |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 18); |
| assert_eq!(b.off(), 0); |
| |
| assert!(b.put_u8(1).is_ok()); |
| assert_eq!(b.cap(), 17); |
| assert_eq!(b.off(), 1); |
| |
| assert!(b.put_u16(0x203).is_ok()); |
| assert_eq!(b.cap(), 15); |
| assert_eq!(b.off(), 3); |
| |
| assert!(b.put_u24(0x40506).is_ok()); |
| assert_eq!(b.cap(), 12); |
| assert_eq!(b.off(), 6); |
| |
| assert!(b.put_u32(0x0708090a).is_ok()); |
| assert_eq!(b.cap(), 8); |
| assert_eq!(b.off(), 10); |
| |
| assert!(b.put_u64(0x0b0c0d0e0f101112).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 18); |
| |
| assert!(b.put_u8(1).is_err()); |
| } |
| |
| let exp: [u8; 18] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 15, 16, 17, 18]; |
| assert_eq!(&d, &exp); |
| } |
| |
| #[test] |
| fn put_bytes() { |
| let mut d: [u8; 5] = [0; 5]; |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 5); |
| assert_eq!(b.off(), 0); |
| |
| let p: [u8; 5] = [0x0a, 0x0b, 0x0c, 0x0d, 0x0e]; |
| assert!(b.put_bytes(&p).is_ok()); |
| assert_eq!(b.cap(), 0); |
| assert_eq!(b.off(), 5); |
| |
| assert!(b.put_u8(1).is_err()); |
| } |
| |
| let exp: [u8; 5] = [0xa, 0xb, 0xc, 0xd, 0xe]; |
| assert_eq!(&d, &exp); |
| } |
| |
| #[test] |
| fn split() { |
| let mut d: [u8; 10] = *b"helloworld"; |
| |
| let mut b = Octets::with_slice(&mut d); |
| assert_eq!(b.cap(), 10); |
| assert_eq!(b.off(), 0); |
| assert_eq!(b.as_ref(), b"helloworld"); |
| |
| assert!(b.get_bytes(5).is_ok()); |
| assert_eq!(b.cap(), 5); |
| assert_eq!(b.off(), 5); |
| assert_eq!(b.as_ref(), b"world"); |
| |
| let off = b.off(); |
| |
| let (first, last) = b.split_at(off).unwrap(); |
| assert_eq!(first.cap(), 5); |
| assert_eq!(first.off(), 0); |
| assert_eq!(first.as_ref(), b"hello"); |
| |
| assert_eq!(last.cap(), 5); |
| assert_eq!(last.off(), 0); |
| assert_eq!(last.as_ref(), b"world"); |
| } |
| |
| #[test] |
| fn split_at() { |
| let mut d: [u8; 10] = *b"helloworld"; |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let (first, second) = b.split_at(5).unwrap(); |
| |
| let mut exp1: [u8; 5] = *b"hello"; |
| assert_eq!(first.as_ref(), &mut exp1[..]); |
| |
| let mut exp2: [u8; 5] = *b"world"; |
| assert_eq!(second.as_ref(), &mut exp2[..]); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let (first, second) = b.split_at(10).unwrap(); |
| |
| let mut exp1: [u8; 10] = *b"helloworld"; |
| assert_eq!(first.as_ref(), &mut exp1[..]); |
| |
| let mut exp2: [u8; 0] = *b""; |
| assert_eq!(second.as_ref(), &mut exp2[..]); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let (first, second) = b.split_at(9).unwrap(); |
| |
| let mut exp1: [u8; 9] = *b"helloworl"; |
| assert_eq!(first.as_ref(), &mut exp1[..]); |
| |
| let mut exp2: [u8; 1] = *b"d"; |
| assert_eq!(second.as_ref(), &mut exp2[..]); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.split_at(11).is_err()); |
| } |
| } |
| |
| #[test] |
| fn slice() { |
| let mut d: [u8; 10] = *b"helloworld"; |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 5] = *b"hello"; |
| assert_eq!(b.slice(5), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 0] = *b""; |
| assert_eq!(b.slice(0), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| b.get_bytes(5).unwrap(); |
| |
| let mut exp: [u8; 5] = *b"world"; |
| assert_eq!(b.slice(5), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.slice(11).is_err()); |
| } |
| } |
| |
| #[test] |
| fn slice_last() { |
| let mut d: [u8; 10] = *b"helloworld"; |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 4] = *b"orld"; |
| assert_eq!(b.slice_last(4), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 1] = *b"d"; |
| assert_eq!(b.slice_last(1), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 0] = *b""; |
| assert_eq!(b.slice_last(0), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| let mut exp: [u8; 10] = *b"helloworld"; |
| assert_eq!(b.slice_last(10), Ok(&mut exp[..])); |
| } |
| |
| { |
| let mut b = Octets::with_slice(&mut d); |
| assert!(b.slice_last(11).is_err()); |
| } |
| } |
| } |