diff options
Diffstat (limited to 'core/io.rs')
-rw-r--r-- | core/io.rs | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/core/io.rs b/core/io.rs new file mode 100644 index 000000000..7baad12e4 --- /dev/null +++ b/core/io.rs @@ -0,0 +1,271 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +use std::ops::Deref; +use std::ops::DerefMut; + +use serde_v8::ZeroCopyBuf; + +/// BufView is a wrapper around an underlying contiguous chunk of bytes. It can +/// be created from a [ZeroCopyBuf], [bytes::Bytes], or [Vec<u8>] and implements +/// `Deref<[u8]>` and `AsRef<[u8]>`. +/// +/// The wrapper has the ability to constrain the exposed view to a sub-region of +/// the underlying buffer. This is useful for write operations, because they may +/// have to be called multiple times, with different views onto the buffer to be +/// able to write it entirely. +pub struct BufView { + inner: BufViewInner, + cursor: usize, +} + +enum BufViewInner { + Empty, + Bytes(bytes::Bytes), + ZeroCopy(ZeroCopyBuf), + Vec(Vec<u8>), +} + +impl BufView { + fn from_inner(inner: BufViewInner) -> Self { + Self { inner, cursor: 0 } + } + + pub fn empty() -> Self { + Self::from_inner(BufViewInner::Empty) + } + + /// Get the length of the buffer view. This is the length of the underlying + /// buffer minus the cursor position. + pub fn len(&self) -> usize { + match &self.inner { + BufViewInner::Empty => 0, + BufViewInner::Bytes(bytes) => bytes.len() - self.cursor, + BufViewInner::ZeroCopy(zero_copy) => zero_copy.len() - self.cursor, + BufViewInner::Vec(vec) => vec.len() - self.cursor, + } + } + + /// Is the buffer view empty? + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Advance the internal cursor of the buffer view by `n` bytes. + pub fn advance_cursor(&mut self, n: usize) { + assert!(self.len() >= n); + self.cursor += n; + } + + /// Reset the internal cursor of the buffer view to the beginning of the + /// buffer. Returns the old cursor position. + pub fn reset_cursor(&mut self) -> usize { + let old = self.cursor; + self.cursor = 0; + old + } +} + +impl Deref for BufView { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + let buf = match &self.inner { + BufViewInner::Empty => &[], + BufViewInner::Bytes(bytes) => bytes.deref(), + BufViewInner::ZeroCopy(zero_copy) => zero_copy.deref(), + BufViewInner::Vec(vec) => vec.deref(), + }; + &buf[self.cursor..] + } +} + +impl AsRef<[u8]> for BufView { + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl From<ZeroCopyBuf> for BufView { + fn from(buf: ZeroCopyBuf) -> Self { + Self::from_inner(BufViewInner::ZeroCopy(buf)) + } +} + +impl From<Vec<u8>> for BufView { + fn from(vec: Vec<u8>) -> Self { + Self::from_inner(BufViewInner::Vec(vec)) + } +} + +impl From<bytes::Bytes> for BufView { + fn from(buf: bytes::Bytes) -> Self { + Self::from_inner(BufViewInner::Bytes(buf)) + } +} + +impl From<BufView> for bytes::Bytes { + fn from(buf: BufView) -> Self { + match buf.inner { + BufViewInner::Empty => bytes::Bytes::new(), + BufViewInner::Bytes(bytes) => bytes, + BufViewInner::ZeroCopy(zero_copy) => zero_copy.into(), + BufViewInner::Vec(vec) => vec.into(), + } + } +} + +/// BufMutView is a wrapper around an underlying contiguous chunk of writable +/// bytes. It can be created from a `ZeroCopyBuf` or a `Vec<u8>` and implements +/// `DerefMut<[u8]>` and `AsMut<[u8]>`. +/// +/// The wrapper has the ability to constrain the exposed view to a sub-region of +/// the underlying buffer. This is useful for write operations, because they may +/// have to be called multiple times, with different views onto the buffer to be +/// able to write it entirely. +/// +/// A `BufMutView` can be turned into a `BufView` by calling `BufMutView::into_view`. +pub struct BufMutView { + inner: BufMutViewInner, + cursor: usize, +} + +enum BufMutViewInner { + ZeroCopy(ZeroCopyBuf), + Vec(Vec<u8>), +} + +impl BufMutView { + fn from_inner(inner: BufMutViewInner) -> Self { + Self { inner, cursor: 0 } + } + + pub fn new(len: usize) -> Self { + Self::from_inner(BufMutViewInner::Vec(vec![0; len])) + } + + /// Get the length of the buffer view. This is the length of the underlying + /// buffer minus the cursor position. + pub fn len(&self) -> usize { + match &self.inner { + BufMutViewInner::ZeroCopy(zero_copy) => zero_copy.len() - self.cursor, + BufMutViewInner::Vec(vec) => vec.len() - self.cursor, + } + } + + /// Is the buffer view empty? + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Advance the internal cursor of the buffer view by `n` bytes. + pub fn advance_cursor(&mut self, n: usize) { + assert!(self.len() >= n); + self.cursor += n; + } + + /// Reset the internal cursor of the buffer view to the beginning of the + /// buffer. Returns the old cursor position. + pub fn reset_cursor(&mut self) -> usize { + let old = self.cursor; + self.cursor = 0; + old + } + + /// Turn this `BufMutView` into a `BufView`. + pub fn into_view(self) -> BufView { + let inner = match self.inner { + BufMutViewInner::ZeroCopy(zero_copy) => BufViewInner::ZeroCopy(zero_copy), + BufMutViewInner::Vec(vec) => BufViewInner::Vec(vec), + }; + BufView { + inner, + cursor: self.cursor, + } + } + + /// Unwrap the underlying buffer into a `Vec<u8>`, consuming the `BufMutView`. + /// + /// This method panics when called on a `BufMutView` that was created from a + /// `ZeroCopyBuf`. + pub fn unwrap_vec(self) -> Vec<u8> { + match self.inner { + BufMutViewInner::ZeroCopy(_) => { + panic!("Cannot unwrap a ZeroCopyBuf backed BufMutView into a Vec"); + } + BufMutViewInner::Vec(vec) => vec, + } + } + + /// Get a mutable reference to an underlying `Vec<u8>`. + /// + /// This method panics when called on a `BufMutView` that was created from a + /// `ZeroCopyBuf`. + pub fn get_mut_vec(&mut self) -> &mut Vec<u8> { + match &mut self.inner { + BufMutViewInner::ZeroCopy(_) => { + panic!("Cannot unwrap a ZeroCopyBuf backed BufMutView into a Vec"); + } + BufMutViewInner::Vec(vec) => vec, + } + } +} + +impl Deref for BufMutView { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + let buf = match &self.inner { + BufMutViewInner::ZeroCopy(zero_copy) => zero_copy.deref(), + BufMutViewInner::Vec(vec) => vec.deref(), + }; + &buf[self.cursor..] + } +} + +impl DerefMut for BufMutView { + fn deref_mut(&mut self) -> &mut [u8] { + let buf = match &mut self.inner { + BufMutViewInner::ZeroCopy(zero_copy) => zero_copy.deref_mut(), + BufMutViewInner::Vec(vec) => vec.deref_mut(), + }; + &mut buf[self.cursor..] + } +} + +impl AsRef<[u8]> for BufMutView { + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl AsMut<[u8]> for BufMutView { + fn as_mut(&mut self) -> &mut [u8] { + self.deref_mut() + } +} + +impl From<ZeroCopyBuf> for BufMutView { + fn from(buf: ZeroCopyBuf) -> Self { + Self::from_inner(BufMutViewInner::ZeroCopy(buf)) + } +} + +impl From<Vec<u8>> for BufMutView { + fn from(buf: Vec<u8>) -> Self { + Self::from_inner(BufMutViewInner::Vec(buf)) + } +} + +pub enum WriteOutcome { + Partial { nwritten: usize, view: BufView }, + Full { nwritten: usize }, +} + +impl WriteOutcome { + pub fn nwritten(&self) -> usize { + match self { + WriteOutcome::Partial { nwritten, .. } => *nwritten, + WriteOutcome::Full { nwritten } => *nwritten, + } + } +} |