Added compile-time distunguishing of internal/external buffer usage

`reuse-buffer` feature available if explicitly opting into it. Buffers can be moved from internal<->external buffers. By default, internal buffers are used when `reuse-buffer` is disabled, and external ones are used when it is enabled.

Fortune for chacha20stream's current commit: Future small blessing − 末小吉
read-stream-wrapper
Avril 3 years ago
parent e18b166514
commit 404d4511f8
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -50,6 +50,12 @@ fn decrypt_message_to<W: Write + ?Sized>(output: &mut W, encrypted: &[u8], key:
#[macro_use] mod ext; #[allow(unused_imports)] use ext::*;
mod private
{
/// This trait cannot be subtraited by downstream crates.
pub trait Sealed{}
}
pub mod key;
mod cha;
mod stream;

@ -1,29 +1,129 @@
//! Syncronous stream `Read` componant.
use super::*;
/// How buffers are used.
pub trait BufferKind : private::Sealed
{
type InternalBuffer;
fn create_buffer(cap: usize) -> Self::InternalBuffer;
fn buffer_len<R: ?Sized>(source: &Source<R, Self>) -> usize;
fn buffer_cap<R: ?Sized>(source: &Source<R, Self>) -> usize;
fn buffer_bytes_mut(source: &mut Self::InternalBuffer) -> &'_ mut [u8];
fn buffer_bytes(source: &Self::InternalBuffer) -> &'_ [u8];
fn buffer_resize<R: ?Sized>(source: &mut Source<R, Self>, to: usize);
}
/// Use struct-internal buffer for `Read`s
#[derive(Debug)]
pub struct UseBufferInternal;
/// Reuse the output buffer for `Read`s
#[derive(Debug)]
pub struct UseBufferExternal;
impl private::Sealed for UseBufferInternal{}
impl BufferKind for UseBufferInternal
{
type InternalBuffer = BufferVec;
#[inline] fn create_buffer(cap: usize) -> Self::InternalBuffer {
if cap == 0 {
BufferVec::new()
} else {
BufferVec::with_capacity(cap)
}
}
#[inline(always)] fn buffer_cap<R: ?Sized>(source: &Source<R, Self>) -> usize {
source.buffer.capacity()
}
#[inline(always)] fn buffer_len<R: ?Sized>(source: &Source<R, Self>) -> usize {
source.buffer.len()
}
#[inline(always)] fn buffer_bytes_mut(source: &mut Self::InternalBuffer) -> &'_ mut [u8]
{
&mut source[..]
}
#[inline(always)] fn buffer_bytes(source: &Self::InternalBuffer) -> &'_ [u8]
{
&source[..]
}
#[inline(always)] fn buffer_resize<R: ?Sized>(source: &mut Source<R, Self>, to: usize)
{
source.buffer.resize(to, 0);
}
}
impl private::Sealed for UseBufferExternal{}
impl BufferKind for UseBufferExternal
{
type InternalBuffer = ();
// -- always used --
#[inline(always)] fn create_buffer(_: usize) -> Self::InternalBuffer {
()
}
#[inline(always)] fn buffer_cap<R: ?Sized>(_: &Source<R, Self>) -> usize {
0
}
// -- conditional --
#[cold]
#[inline(never)] fn buffer_len<R: ?Sized>(_: &Source<R, Self>) -> usize {
panic!("Phantom buffer length cannot be checked")
}
#[cold]
#[inline(never)] fn buffer_bytes_mut(_: &mut Self::InternalBuffer) -> &'_ mut [u8]
{
panic!("Cannot mutref non-existent ibuf.")
}
#[cold]
#[inline(never)] fn buffer_bytes(_: &Self::InternalBuffer) -> &'_ [u8]
{
panic!("Cannot ref non-existent ibuf.")
}
#[cold]
#[inline(never)] fn buffer_resize<R: ?Sized>(_: &mut Source<R, Self>, _: usize)
{
panic!("Cannot resize non-existent ibuf.")
}
}
#[cfg(not(feature="reuse-buffer"))]
pub type DefaultBuffer = UseBufferInternal;
#[cfg(feature="reuse-buffer")]
pub type DefaultBuffer = UseBufferExternal;
/// TODO: Document
//#[derive(Debug)]
pub struct Source<R: ?Sized>
pub struct Source<R: ?Sized, Buffer: ?Sized + BufferKind = DefaultBuffer>
{
crypter: Crypter,
#[cfg(not(feature="reuse-buffer"))] buffer: BufferVec, // When `reuse-buffer` is enabled, this isn't needed. We re-use the output buffer for the initial read of untransformed data from `stream` and the actual transformation of the read bytes.
buffer: Buffer::InternalBuffer, // When `reuse-buffer` is enabled, this isn't needed. We re-use the output buffer for the initial read of untransformed data from `stream` and the actual transformation of the read bytes.
stream: R
}
impl<R: ?Sized+ fmt::Debug> fmt::Debug for Source<R>
impl<R: ?Sized+ fmt::Debug, K: ?Sized + BufferKind> fmt::Debug for Source<R, K>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
#[cfg(feature="reuse-buffer")]
return write!(f, "Source({:?}, (unbounded buffer cap))", &self.stream);
#[cfg(not(feature="reuse-buffer"))]
return write!(f, "Source({:?}, ({} buffer cap))", &self.stream, self.buffer.capacity());
use std::any::type_name;
write!(f, "Source<Wraps: {}, BufferKind: {}>", type_name::<R>(), type_name::<K>())?;
match K::buffer_cap(self) {
0 => write!(f, "({:?}, (unbounded buffer cap))", &self.stream),
cap => write!(f, "({:?}, ({} buffer cap))", &self.stream, cap),
}
}
}
impl<R: ?Sized> Source<R>
impl<R: ?Sized, K: ?Sized + BufferKind> Source<R, K>
where R: Read
{
/// The crypter of this instance
@ -50,39 +150,26 @@ where R: Read
&mut self.stream
}
#[cfg(not(feature="reuse-buffer"))]
/// Grow the inner buffer to fix this size, if needed.
fn grow_to_fit(&mut self, sz: usize)
{
if sz > self.buffer.len() {
self.buffer.resize(sz, 0);
if sz > K::buffer_len(self) {
K::buffer_resize(self, sz);
}
}
#[cfg(not(feature="reuse-buffer"))]
/// Perform the cipher transform on this input to the inner buffer, returning the number of bytes updated.
fn transform(&mut self, bufsz: usize, output: &mut [u8]) -> Result<usize, ErrorStack>
{
//self.grow_to_fix(output.len());
//let bufsz = self.stream.read(&mut self.buffer[..bufsz])?;
let n = self.crypter.update(&self.buffer[..bufsz], &mut output[..])?;
let n = self.crypter.update(& K::buffer_bytes(&self.buffer)[..bufsz], &mut output[..])?;
let _f = self.crypter.finalize(&mut output[..n])?;
debug_assert_eq!(_f, 0);
Ok(n)
/*
if buf.len() > self.buffer.len() {
self.buffer.resize(buf.len(), 0);
}
let n = self.crypter.update(&buf[..], &mut self.buffer[..])?;
let _f = self.crypter.finalize(&mut self.buffer[..n])?; // I don't know if this is needed.
debug_assert_eq!(_f, 0);
Ok(n)*/
}
#[cfg(not(feature="reuse-buffer"))]
/// Clear the internal buffer while keeping it allocated for further use.
///
/// This does not affect operations at all, all it does is 0 out the left-over temporary buffer from the last operation(s).
@ -91,17 +178,44 @@ where R: Read
{
#[cfg(feature="explicit_clear")]
{
bytes::explicit_prune(&mut self.buffer[..]);
bytes::explicit_prune(K::buffer_bytes_mut(self));
return;
}
#[cfg(not(feature="explicit_clear"))]
unsafe {
std::ptr::write_bytes(self.buffer.as_mut_ptr(), 0, self.buffer.len());
std::ptr::write_bytes(K::buffer_bytes_mut(&mut self.buffer).as_mut_ptr(), 0, K::buffer_len(self));
}
}
}
impl<R> Source<R, UseBufferExternal>
{
/// Convert this instance to use external buffer (instead of internal.)
pub fn with_reused_buffer(self) -> Source<R, UseBufferInternal>
{
Source {
buffer: UseBufferInternal::create_buffer(UseBufferExternal::buffer_cap(&self)),
crypter: self.crypter,
stream: self.stream,
}
}
}
impl<R> Source<R, UseBufferInternal>
{
/// Convert this instance to use external buffer (instead of internal.)
pub fn with_reused_buffer(self) -> Source<R, UseBufferExternal>
{
Source {
buffer: UseBufferExternal::create_buffer(UseBufferInternal::buffer_cap(&self)),
crypter: self.crypter,
stream: self.stream,
}
}
}
impl<R: ?Sized> Read for Source<R>
impl<R: ?Sized, K: ?Sized + BufferKind> Read for Source<R, K>
where R: Read
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {

Loading…
Cancel
Save