summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Yu <yumike@google.com>2022-10-13 04:55:53 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-10-13 04:55:53 +0000
commit8fb77777fa81e54a53a139153e3788af0dc54a8b (patch)
tree3d9eeb7745c7222a7b9cf8f74e49774c94a99d66
parentb41fda302f17ba1fcab187595298ad3665e9c9a7 (diff)
parent296adc60982767eefea22d4bd289da66076d18ef (diff)
downloadoctets-8fb77777fa81e54a53a139153e3788af0dc54a8b.tar.gz
Initial import of octets-0.1.0 am: 1780ec6409 am: 69219c2571 am: 296adc6098
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/octets/+/2231548 Change-Id: I39b683f5d77ffbf0f89bbe7e8ea6db4392abecd3 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Cargo.toml21
-rw-r--r--Cargo.toml.orig10
-rw-r--r--LICENSE23
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_BSD_LIKE0
-rw-r--r--OWNERS1
-rw-r--r--src/lib.rs1274
8 files changed, 1354 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..7eb1d2d
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "1c612215d636616e8ea07f640f3829c7f1b39000"
+ },
+ "path_in_vcs": "octets"
+} \ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..0202601
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,21 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "octets"
+version = "0.1.0"
+authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
+description = "Zero-copy abstraction for parsing and constructing network packets"
+keywords = ["quic", "http3"]
+categories = ["network-programming"]
+license = "BSD-2-Clause"
+repository = "https://github.com/cloudflare/quiche"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..21f589f
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,10 @@
+[package]
+name = "octets"
+version = "0.1.0"
+authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
+edition = "2018"
+description = "Zero-copy abstraction for parsing and constructing network packets"
+repository = "https://github.com/cloudflare/quiche"
+keywords = ["quic", "http3"]
+categories = ["network-programming"]
+license = "BSD-2-Clause"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c044775
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Copyright (C) 2018-2019, Cloudflare, Inc.
+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 <COPYRIGHT HOLDER> 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.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..5b61482
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "octets"
+description: "Zero-copy abstraction for parsing and constructing network packets"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/octets"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/octets/octets-0.1.0.crate"
+ }
+ version: "0.1.0"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2022
+ month: 9
+ day: 20
+ }
+}
diff --git a/MODULE_LICENSE_BSD_LIKE b/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD_LIKE
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..67d40be
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,1274 @@
+// Copyright (C) 2018-2019, Cloudflare, Inc.
+// 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;
+
+/// A specialized [`Result`] type for [`OctetsMut`] operations.
+///
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+/// [`OctetsMut`]: struct.OctetsMut.html
+pub type Result<T> = std::result::Result<T, BufferTooShortError>;
+
+/// An error indicating that the provided [`OctetsMut`] is not big enough.
+///
+/// [`OctetsMut`]: struct.OctetsMut.html
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct BufferTooShortError;
+
+impl std::fmt::Display for BufferTooShortError {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "BufferTooShortError")
+ }
+}
+
+impl std::error::Error for BufferTooShortError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
+
+macro_rules! peek_u {
+ ($b:expr, $ty:ty, $len:expr) => {{
+ let len = $len;
+ let src = &$b.buf[$b.off..];
+
+ if src.len() < len {
+ return Err(BufferTooShortError);
+ }
+
+ 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 len = $len;
+
+ if $b.buf.len() < $b.off + len {
+ return Err(BufferTooShortError);
+ }
+
+ let v = $v;
+
+ let dst = &mut $b.buf[$b.off..($b.off + len)];
+
+ 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 immutable 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 [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 [u8]) -> Self {
+ 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)
+ }
+
+ /// 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)
+ }
+
+ /// 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)
+ }
+
+ /// 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)
+ }
+
+ /// 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)
+ }
+
+ /// 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 = varint_parse_len(first);
+
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let out = match len {
+ 1 => u64::from(self.get_u8()?),
+
+ 2 => u64::from(self.get_u16()? & 0x3fff),
+
+ 4 => u64::from(self.get_u32()? & 0x3fffffff),
+
+ 8 => self.get_u64()? & 0x3fffffffffffffff,
+
+ _ => unreachable!(),
+ };
+
+ Ok(out)
+ }
+
+ /// 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(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &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(&self, len: usize) -> Result<Octets> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ Ok(out)
+ }
+
+ /// Returns a slice of `len` elements from the current offset.
+ pub fn slice(&'a self, len: usize) -> Result<&'a [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ Ok(&self.buf[self.off..self.off + len])
+ }
+
+ /// Returns a slice of `len` elements from the end of the buffer.
+ pub fn slice_last(&'a self, len: usize) -> Result<&'a [u8]> {
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let cap = self.cap();
+ Ok(&self.buf[cap - len..])
+ }
+
+ /// Advances the buffer's offset.
+ pub fn skip(&mut self, skip: usize) -> Result<()> {
+ if skip > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ self.off += skip;
+
+ Ok(())
+ }
+
+ /// 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
+ }
+
+ /// Returns a reference to the internal buffer.
+ pub fn buf(&self) -> &[u8] {
+ self.buf
+ }
+
+ /// 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..]
+ }
+}
+
+/// A zero-copy mutable byte buffer.
+///
+/// Like `Octets` but mutable.
+#[derive(Debug, PartialEq)]
+pub struct OctetsMut<'a> {
+ buf: &'a mut [u8],
+ off: usize,
+}
+
+impl<'a> OctetsMut<'a> {
+ /// Creates an `OctetsMut` 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]) -> Self {
+ OctetsMut { 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 = varint_parse_len(first);
+
+ if len > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ let out = match len {
+ 1 => u64::from(self.get_u8()?),
+
+ 2 => u64::from(self.get_u16()? & 0x3fff),
+
+ 4 => u64::from(self.get_u32()? & 0x3fffffff),
+
+ 8 => self.get_u64()? & 0x3fffffffffffffff,
+
+ _ => unreachable!(),
+ };
+
+ 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<&mut [u8]> {
+ self.put_varint_with_len(v, varint_len(v))
+ }
+
+ /// Writes an unsigned variable-length integer of the specified length, in
+ /// network byte-order at the current offset and advances the buffer.
+ pub fn put_varint_with_len(
+ &mut self, v: u64, len: usize,
+ ) -> Result<&mut [u8]> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let buf = match len {
+ 1 => self.put_u8(v as u8)?,
+
+ 2 => {
+ let buf = self.put_u16(v as u16)?;
+ buf[0] |= 0x40;
+ buf
+ },
+
+ 4 => {
+ let buf = self.put_u32(v as u32)?;
+ buf[0] |= 0x80;
+ buf
+ },
+
+ 8 => {
+ let buf = self.put_u64(v)?;
+ buf[0] |= 0xc0;
+ buf
+ },
+
+ _ => panic!("value is too large for varint"),
+ };
+
+ Ok(buf)
+ }
+
+ /// 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(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &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.
+ pub fn get_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = OctetsMut {
+ 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(BufferTooShortError);
+ }
+
+ let out = Octets {
+ buf: &self.buf[self.off..self.off + len],
+ off: 0,
+ };
+
+ Ok(out)
+ }
+
+ /// Reads `len` bytes from the current offset without copying and without
+ /// advancing the buffer.
+ pub fn peek_bytes_mut(&mut self, len: usize) -> Result<OctetsMut> {
+ if self.cap() < len {
+ return Err(BufferTooShortError);
+ }
+
+ let out = OctetsMut {
+ 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(BufferTooShortError);
+ }
+
+ 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<(OctetsMut, OctetsMut)> {
+ if self.len() < off {
+ return Err(BufferTooShortError);
+ }
+
+ let (left, right) = self.buf.split_at_mut(off);
+
+ let first = OctetsMut { buf: left, off: 0 };
+
+ let last = OctetsMut { 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(BufferTooShortError);
+ }
+
+ 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(BufferTooShortError);
+ }
+
+ let cap = self.cap();
+ Ok(&mut self.buf[cap - len..])
+ }
+
+ /// Advances the buffer's offset.
+ pub fn skip(&mut self, skip: usize) -> Result<()> {
+ if skip > self.cap() {
+ return Err(BufferTooShortError);
+ }
+
+ self.off += skip;
+
+ Ok(())
+ }
+
+ /// 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
+ }
+
+ /// Returns a reference to the internal buffer.
+ pub fn buf(&self) -> &[u8] {
+ self.buf
+ }
+
+ /// 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 OctetsMut<'a> {
+ fn as_ref(&self) -> &[u8] {
+ &self.buf[self.off..]
+ }
+}
+
+impl<'a> AsMut<[u8]> for OctetsMut<'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!()
+ }
+}
+
+/// Returns how long the variable-length integer is, given its first byte.
+pub fn varint_parse_len(first: u8) -> usize {
+ match first >> 6 {
+ 0 => 1,
+ 1 => 2,
+ 2 => 4,
+ 3 => 8,
+ _ => unreachable!(),
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn get_u() {
+ let d = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ ];
+
+ let mut b = Octets::with_slice(&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 get_u_mut() {
+ let mut d = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ ];
+
+ let mut b = OctetsMut::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 d = [1, 2];
+
+ let mut b = Octets::with_slice(&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 peek_u_mut() {
+ let mut d = [1, 2];
+
+ let mut b = OctetsMut::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 d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = Octets::with_slice(&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 get_bytes_mut() {
+ let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = OctetsMut::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 d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = Octets::with_slice(&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 peek_bytes_mut() {
+ let mut d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ let mut b = OctetsMut::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 d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 151288809941952652);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+
+ let d = [0x9d, 0x7f, 0x3e, 0x7d];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 494878333);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+
+ let d = [0x7b, 0xbd];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 15293);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let d = [0x40, 0x25];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let d = [0x25];
+ let mut b = Octets::with_slice(&d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 1);
+ }
+
+ #[test]
+ fn get_varint_mut() {
+ let mut d = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 151288809941952652);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+
+ let mut d = [0x9d, 0x7f, 0x3e, 0x7d];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 494878333);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+
+ let mut d = [0x7b, 0xbd];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 15293);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let mut d = [0x40, 0x25];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.get_varint().unwrap(), 37);
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+
+ let mut d = [0x25];
+ let mut b = OctetsMut::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 = [0; 8];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(151288809941952652).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 8);
+ }
+ let exp = [0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 4];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(494878333).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 4);
+ }
+ let exp = [0x9d, 0x7f, 0x3e, 0x7d];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 2];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(15293).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 2);
+ }
+ let exp = [0x7b, 0xbd];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 1];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(37).is_ok());
+ assert_eq!(b.cap(), 0);
+ assert_eq!(b.off(), 1);
+ }
+ let exp = [0x25];
+ assert_eq!(&d, &exp);
+
+ let mut d = [0; 3];
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(151288809941952652).is_err());
+ assert_eq!(b.cap(), 3);
+ assert_eq!(b.off(), 0);
+ }
+ let exp = [0; 3];
+ assert_eq!(&d, &exp);
+ }
+
+ #[test]
+ #[should_panic]
+ fn varint_too_large() {
+ let mut d = [0; 3];
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.put_varint(std::u64::MAX).is_err());
+ }
+
+ #[test]
+ fn put_u() {
+ let mut d = [0; 18];
+
+ {
+ let mut b = OctetsMut::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 = [
+ 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 = [0; 5];
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert_eq!(b.cap(), 5);
+ assert_eq!(b.off(), 0);
+
+ let p = [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 = [0xa, 0xb, 0xc, 0xd, 0xe];
+ assert_eq!(&d, &exp);
+ }
+
+ #[test]
+ fn split() {
+ let mut d = b"helloworld".to_vec();
+
+ let mut b = OctetsMut::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 = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(5).unwrap();
+
+ let mut exp1 = b"hello".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"world".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(10).unwrap();
+
+ let mut exp1 = b"helloworld".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let (first, second) = b.split_at(9).unwrap();
+
+ let mut exp1 = b"helloworl".to_vec();
+ assert_eq!(first.as_ref(), &mut exp1[..]);
+
+ let mut exp2 = b"d".to_vec();
+ assert_eq!(second.as_ref(), &mut exp2[..]);
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.split_at(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice() {
+ let d = b"helloworld".to_vec();
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"hello".to_vec();
+ assert_eq!(b.slice(5), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"".to_vec();
+ assert_eq!(b.slice(0), Ok(&exp[..]));
+ }
+
+ {
+ let mut b = Octets::with_slice(&d);
+ b.get_bytes(5).unwrap();
+
+ let exp = b"world".to_vec();
+ assert_eq!(b.slice(5), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ assert!(b.slice(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_mut() {
+ let mut d = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"hello".to_vec();
+ assert_eq!(b.slice(5), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"".to_vec();
+ assert_eq!(b.slice(0), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ b.get_bytes(5).unwrap();
+
+ let mut exp = b"world".to_vec();
+ assert_eq!(b.slice(5), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.slice(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_last() {
+ let d = b"helloworld".to_vec();
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"orld".to_vec();
+ assert_eq!(b.slice_last(4), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"d".to_vec();
+ assert_eq!(b.slice_last(1), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"".to_vec();
+ assert_eq!(b.slice_last(0), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ let exp = b"helloworld".to_vec();
+ assert_eq!(b.slice_last(10), Ok(&exp[..]));
+ }
+
+ {
+ let b = Octets::with_slice(&d);
+ assert!(b.slice_last(11).is_err());
+ }
+ }
+
+ #[test]
+ fn slice_last_mut() {
+ let mut d = b"helloworld".to_vec();
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"orld".to_vec();
+ assert_eq!(b.slice_last(4), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"d".to_vec();
+ assert_eq!(b.slice_last(1), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"".to_vec();
+ assert_eq!(b.slice_last(0), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ let mut exp = b"helloworld".to_vec();
+ assert_eq!(b.slice_last(10), Ok(&mut exp[..]));
+ }
+
+ {
+ let mut b = OctetsMut::with_slice(&mut d);
+ assert!(b.slice_last(11).is_err());
+ }
+ }
+}