blob: 6163984d1c1e8333ef1aef202fe300540ade3b82 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
failure::{Error, ensure, format_err},
zerocopy::{self, LayoutVerified, Unaligned},
};
pub use zerocopy::ByteSliceMut as ByteSliceMut;
pub struct BufferWriter<B: ByteSliceMut> {
buf: B,
written_bytes: usize,
}
impl <B: ByteSliceMut> BufferWriter<B> {
pub fn new(buf: B) -> Self {
Self {written_bytes: 0, buf}
}
/// Writes a single given `byte` and returns a `BufferWriter` to write remaining bytes of the
/// original buffer.
pub fn write_byte(mut self, byte: u8) -> Result<Self, Error> {
ensure!(self.buf.len() >= 1, "buffer too short");
let (mut data, remaining) = self.buf.split_at(1);
data[0] = byte;
Ok(Self {
buf: remaining,
written_bytes: self.written_bytes + 1
})
}
/// Writes the given `bytes` and returns a `BufferWriter` to write remaining bytes of the
/// original buffer.
pub fn write_bytes(mut self, bytes: &[u8]) -> Result<Self, Error> {
ensure!(self.buf.len() >= bytes.len(), "buffer too short");
let (mut data, remaining) = self.buf.split_at(bytes.len());
data.copy_from_slice(bytes);
Ok(Self {
buf: remaining,
written_bytes: self.written_bytes + bytes.len()
})
}
/// Reserves and zeroes a typed chunk of bytes of size |mem::size_of::<T>|.
/// Returns a tuple of the typed reserved chunk and a `BufferWriter` for writing remaining
/// bytes of the original buffer.
pub fn reserve_zeroed<T: Unaligned>(mut self) -> Result<(LayoutVerified<B, T>, Self), Error> {
let (data, remaining) = LayoutVerified::new_unaligned_from_prefix_zeroed(self.buf)
.ok_or(format_err!("buffer too short"))?;
Ok((data, Self {
buf: remaining,
written_bytes: self.written_bytes + std::mem::size_of::<T>()
}))
}
pub fn written_bytes(&self) -> usize {
self.written_bytes
}
pub fn remaining_bytes(&self) -> usize {
self.buf.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buffer_too_short() {
assert!(BufferWriter::new(&mut [0; 0][..]).write_byte(1).is_err());
assert!(BufferWriter::new(&mut [0; 5][..]).write_bytes(&[0; 6]).is_err());
assert!(BufferWriter::new(&mut [0; 5][..]).reserve_zeroed::<[u8; 6]>().is_err());
}
#[test]
fn reserve_zeroed_for_type() {
let mut buf = [1u8; 5];
let (mut data, w) = BufferWriter::new(&mut buf[..])
.reserve_zeroed::<[u8; 3]>().expect("failed writing buffer");
data[0] = 42;
// Don't write `data[1]`: BufferWriter should zero this byte.
data[2] = 43;
assert_eq!(3, w.written_bytes());
assert_eq!(2, w.remaining_bytes());
assert_eq!([42, 0, 43, 1, 1], buf);
}
#[test]
fn write_bytes() {
let mut buf = [1u8; 5];
let w = BufferWriter::new(&mut buf[..])
.write_byte(42).expect("failed writing buffer")
.write_byte(43).expect("failed writing buffer")
.write_bytes(&[2, 3]).expect("failed writing buffer");
assert_eq!(4, w.written_bytes());
assert_eq!(1, w.remaining_bytes());
assert_eq!([42, 43, 2, 3, 1], buf);
}
}