Skip to content

Commit

Permalink
Initial attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
Kixunil committed Mar 14, 2021
1 parent c5c9316 commit 099b0da
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 106 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ edition = "2018"
[dependencies]
void = { version = "1", default-features = false }
byteorder = { version = "1", optional = true }
possibly_uninit = "0.1"

[features]
default = ["std"]
Expand Down
263 changes: 226 additions & 37 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,201 @@ pub mod error;
pub mod ext;
pub mod util;

use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use core::mem::MaybeUninit;

use crate::{
error::{ExtendError, ReadExactError},
util::Chain,
void::Void,
};

/// Abbreviation for OutSlice<u8>
pub type OutBytes = possibly_uninit::slice::OutSlice<u8>;

#[cfg(feature = "byteorder")]
use byteorder::ByteOrder;

/// Buffer of bytes used in readers
pub struct ReadBuffer<'a> {
buffer: &'a mut OutBytes,
// modifying this field is unsafe
// invariant: self.position <= self.buffer.len()
position: usize,
}

impl<'a> ReadBuffer<'a> {
/// Creates a new buffer using provided storage and position starting at 0
#[inline]
pub fn new<T: Into<&'a mut OutBytes>>(buffer: T) -> Self {
ReadBuffer {
buffer: buffer.into(),
position: 0,
}
}

/// Writes a single byte into the buffer and advances the position by one
///
/// ## Panics
///
/// This method panicks if the buffer is full.
#[inline]
//#[track_caller] ?
pub fn write_byte(&mut self, byte: u8) {
if self.position >= self.buffer.len() {
panic!("Attempt to write into a full buffer");
}
self.buffer.at_mut(self.position).write(byte);
self.position += 1;
}

/// Writes a byte slice into the buffer and advance the position by slice length
///
/// ## Panics
///
/// This method panicks if the length of the slice is greater than what buffer can hold.
#[inline]
//#[track_caller] ?
pub fn write_slice(&mut self, bytes: &[u8]) {
self.buffer.copy_from_slice(bytes);
self.position += bytes.len();
}

/// Writes as many bytes from slice as fit into the buffer.
///
/// This method is similar to `write_slice` but it truncates the slice being written
/// instead of panicking.
#[inline]
pub fn write_slice_min(&mut self, bytes: &[u8]) {
let to_write = self.remaining().min(bytes.len());
self.buffer.copy_from_slice(&bytes[0..to_write]);
self.position += to_write;
}

/// Returns how many bytes can be written into the buffer
pub fn remaining(&self) -> usize {
self.buffer.len() - self.position
}

/// Returns true if no more bytes can be written to the buffer
pub fn is_full(&self) -> bool {
self.remaining() == 0
}

/// Returns uninitialized portion of the buffer.
///
/// Readers need to store the bytes into this slice.
/// This method should be only used in low-level Read implementations.
/// If you already have a slice or a byte see `write_slice` and `write_byte` methods.
pub fn uninit_mut(&mut self) -> &mut OutBytes {
&mut self.buffer[self.position..]
}

/// Moves position by `amount` bytes
///
/// This method marks the `amount` bytes after current position as initialized.
///
/// ## Safety
///
/// The caller may only call this method if and only if it has written `amount` consecutive bytes to the slice
/// returned by `uninit_mut()` starting at position 0.
///
/// The behavior is undefined if amount is greater than the length of the slice returned by
/// `uninit_mut()` or if the amount is greater than the number of bytes written to the slice.
///
/// Calling this method with zero `amount` is NO-OP and always sound.
pub unsafe fn advance(&mut self, amount: usize) {
self.position += amount;
}

/// Returns initialized part of the buffer
pub fn init(&self) -> &[u8] {
unsafe {
self.buffer[0..self.position].assume_init()
}
}

/// Returns initialized part of the buffer
pub fn init_mut(&mut self) -> &mut [u8] {
unsafe {
self.buffer[0..self.position].assume_init_mut()
}
}

/// Splits the buffer between initialized and uninitialized part and returns them
pub fn split_at_pos_mut(&mut self) -> (&mut [u8], &mut OutBytes) {
unsafe {
let (init, uninit) = self.buffer.split_at_mut(self.position);
(init.assume_init_mut(), uninit)
}
}
}

pub trait ByteSliceExt: Deref + DerefMut where for<'a> &'a mut <Self as Deref>::Target: Into<&'a OutBytes> {
fn as_read_buffer(&mut self) -> ReadBuffer<'_> {
ReadBuffer::new(&mut **self)
}
}

impl ByteSliceExt for &'_ mut [u8] {}
impl ByteSliceExt for &'_ mut [MaybeUninit<u8>] {}

pub unsafe trait BufferLike {
fn whole_as_out_bytes(&mut self) -> &mut OutBytes;
fn position(&mut self) -> usize;
unsafe fn set_position(&mut self, position: usize);
}

pub trait BufferLikeExt: BufferLike {
fn uninit_as_read_buffer(&mut self) -> BufferUpdater<Self> {
let position = self.position();
let storage = NonNull::from(self);
let buffer = self.whole_as_out_bytes();

BufferUpdater {
storage,
buffer: ReadBuffer {
buffer,
position,
}
}
}
}

/// Ensures position of the underlying storage is updated on drop
pub struct BufferUpdater<'a, T: BufferLike> {
storage: NonNull<T>,
buffer: ReadBuffer<'a>,
}

impl<'a, T: BufferLike> Deref for BufferUpdater<'a, T> {
type Target = ReadBuffer<'a>;

fn deref(&self) -> &Self::Target {
&self.buffer
}
}

impl<'a, T: BufferLike> DerefMut for BufferUpdater<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}

impl<'a, T: BufferLike> Drop for BufferUpdater<'a, T> {
fn drop(&mut self) {
unsafe {
// This is the last time buffer is accessed
let position = self.buffer.position;
// This is sound according to stacked borrows because self.buffer is no longr accessed
// position <= len is enforced by ReadBuffer
// initializedness is enforced by ReadBuffer
self.storage.as_mut().set_position(position);
}
}
}

/// The Read trait allows for reading bytes from a source.
///
/// Implementors of the Read trait are sometimes called 'readers'.
Expand Down Expand Up @@ -81,7 +267,7 @@ pub trait Read {
/// If this function encounters any form of I/O or other error, an error
/// variant will be returned. If an error is returned then it must be
/// guaranteed that no bytes were read.
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError>;
fn read(&mut self, buf: &mut ReadBuffer<'_>) -> Result<usize, Self::ReadError>;

/// Read the exact number of bytes required to fill `buf`.
///
Expand All @@ -90,26 +276,23 @@ pub trait Read {
/// No guarantees are provided about the contents of `buf` when this function is called,
/// implementations cannot rely on any property of the contents of `buf` being true. It is
/// recommended that implementations only write data to `buf` instead of reading its contents.
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), ReadExactError<Self::ReadError>> {
if self.available_bytes(buf.len()) {
while !buf.is_empty() {
fn read_exact(&mut self, buf: &mut ReadBuffer<'_>) -> Result<(), ReadExactError<Self::ReadError>> {
if self.available_bytes(buf.remaining()) {
while !buf.is_full() {
let read_bytes = self.read(buf)?;
if read_bytes == 0 {
return Err(ReadExactError::UnexpectedEnd);
}

let tmp = buf;
buf = &mut tmp[read_bytes..];
}
return Ok(());
Ok(())
} else {
Err(ReadExactError::UnexpectedEnd)
}
}

/// Hints whether there are at least `at_least` bytes available.
///
/// This function should return true if it can't determine exact amount. That is also default.
/// This function should return true if it can't determine exact amount. That is also the default.
///
/// # Errors
///
Expand All @@ -136,7 +319,7 @@ pub trait Read {
container: &mut T,
) -> Result<usize, ExtendError<Self::ReadError, T::ExtendError>>
where
Self: ReadOverwrite,
Self: Sized,
{
let mut total_bytes = 0;

Expand All @@ -149,6 +332,15 @@ pub trait Read {
}
}

/*
fn map_read_err<E, F: FnMut(Self::Error) -> E>(self, f: F) -> MapErr<E, F> where Self: Sized {
MapErr {
reader: self,
map_fn: f,
}
}
*/

/// Creates a "by reference" adaptor for this instance of `Read`.
///
/// The returned adaptor also implements `Read` and will simply borrow this current reader.
Expand Down Expand Up @@ -229,40 +421,33 @@ pub trait Read {
/// Some types can be extended by reading from reader. The most well-known is probably `Vec`. It
/// is possible to implement it manually, but it may be more efficient if the type implements this
/// trait directly. In case of `Vec`, it means reading directly into uninitialized part of reserved
/// memory in case of the fast version of this trait.
pub trait ExtendFromReaderSlow {
/// memory.
pub trait ExtendFromReader {
/// This type is returned when extending fails. For example, if not enough memory could be
/// allocated. All other errors should be passed directly from reader.
type ExtendError;

/// This method performs extending from reader - that means calling `read()` just once.
fn extend_from_reader_slow<R: Read + ?Sized>(
fn extend_from_reader<R: Read + ?Sized>(
&mut self,
reader: &mut R,
) -> Result<usize, ExtendError<R::ReadError, Self::ExtendError>>;
}

/// This trait is similar to slow one. The difference is that thanks to reader guaranteeing
/// correctness, this one can use uninitialized buffer.
pub trait ExtendFromReader: ExtendFromReaderSlow {
/// This method performs extending from reader - that means calling `read()` just once.
fn extend_from_reader<R: Read + ReadOverwrite + ?Sized>(
fn extend_from_reader_to_end<R: Read + ?Sized>(
&mut self,
reader: &mut R,
) -> Result<usize, ExtendError<R::ReadError, Self::ExtendError>>;
}
) -> Result<usize, ExtendError<R::ReadError, Self::ExtendError>> {
let mut total_bytes = 0;

/// This marker trait declares that the Read trait is implemented correctly,
/// that means:
///
/// 1. implementation of `read()` and `read_exact()` doesn't read from provided buffer.
/// 2. if `read()` returns `Ok(n)`, then each of first `n` bytes was overwritten.
/// 3. if `read_exact()` returns `Ok(())` then each byte of buffer was overwritten.
///
/// Breaking this should not cause huge problems since untrusted input should be checked anyway but
/// it might leak internal state of the application, containing secret data like private keys.
/// Think of the Hartbleed bug.
pub unsafe trait ReadOverwrite: Read {}
loop {
let bytes = self.extend_from_reader(reader)?;
if bytes == 0 {
return Ok(total_bytes);
}
total_bytes += bytes;
}
}
}

/// A trait for objects which are byte-oriented sinks.
///
Expand Down Expand Up @@ -443,7 +628,7 @@ pub trait Write {
impl<'a, R: Read + ?Sized> Read for &'a mut R {
type ReadError = R::ReadError;

fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError> {
fn read(&mut self, buf: &mut ReadBuffer<'_>) -> Result<usize, Self::ReadError> {
(*self).read(buf)
}
}
Expand Down Expand Up @@ -474,19 +659,23 @@ impl<'a, W: Write + ?Sized> Write for &'a mut W {
impl<'a> Read for &'a [u8] {
type ReadError = Void;

fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError> {
fn read(&mut self, buf: &mut ReadBuffer<'_>) -> Result<usize, Self::ReadError> {
use core::cmp::min;

let amt = min(buf.len(), self.len());
if self.is_empty() {
return Ok(0);
}

let amt = min(buf.remaining(), self.len());
let (a, b) = self.split_at(amt);

// First check if the amount of bytes we want to read is small:
// `copy_from_slice` will generally expand to a call to `memcpy`, and
// for a single byte the overhead is significant.
if amt == 1 {
buf[0] = a[0];
buf.write_byte(a[0])
} else {
buf[..amt].copy_from_slice(a);
buf.write_slice(a);
}

*self = b;
Expand Down
Loading

0 comments on commit 099b0da

Please sign in to comment.