diff --git a/std/src/error.rs b/std/src/error.rs index 18d5e5b..49419e3 100644 --- a/std/src/error.rs +++ b/std/src/error.rs @@ -1,27 +1,54 @@ use crate::boxed::Box; +use crate::fmt::{self, Debug, Display}; +use crate::string::String; -#[cfg(feature = "std")] -pub use std::error::Error; - -#[cfg(not(feature = "std"))] pub trait Error: core::fmt::Debug + core::fmt::Display { fn source(&self) -> Option<&(dyn Error + 'static)> { None } } -#[cfg(not(feature = "std"))] impl<'a, E: Error + 'a> From for Box { fn from(err: E) -> Self { Box::new(err) } } -#[cfg(not(feature = "std"))] +impl<'a, E: Error + Send + Sync + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + impl Error for Box {} -#[cfg(not(feature = "std"))] -impl Error for crate::string::String {} +impl From for Box { + #[inline] + fn from(err: String) -> Box { + struct StringError(String); + + impl Error for StringError {} + + impl Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } + } -#[cfg(not(feature = "std"))] -impl Error for crate::io::Error {} + // Purposefully skip printing "StringError(..)" + impl Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +impl<'a> From<&'a str> for Box { + #[inline] + fn from(err: &'a str) -> Box { + From::from(String::from(err)) + } +} diff --git a/std/src/io.rs b/std/src/io.rs deleted file mode 100644 index a573d82..0000000 --- a/std/src/io.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! no-std io replacement -use crate::{vec::Vec, cmp, mem, fmt}; - -#[derive(Debug)] -pub struct Error; - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "Error") - } -} - -pub type Result = core::result::Result; - -pub trait Read { - fn read_exact(&mut self, data: &mut [u8]) -> Result<()>; -} - -pub trait Write { - fn write_all(&mut self, data: &[u8]) -> Result<()>; -} - -impl Read for &mut R { - #[inline] - fn read_exact(&mut self, data: &mut [u8]) -> Result<()> { - (**self).read_exact(data) - } -} - -impl Read for &[u8] { - fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { - if buf.len() > self.len() { - return Err(Error); - } - let (a, b) = self.split_at(buf.len()); - - // 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 buf.len() == 1 { - buf[0] = a[0]; - } else { - buf.copy_from_slice(a); - } - - *self = b; - Ok(()) - } -} - -impl Write for &mut W { - #[inline] - fn write_all(&mut self, data: &[u8]) -> Result<()> { - (**self).write_all(data) - } -} - -impl Write for &mut [u8] { - #[inline] - fn write_all(&mut self, data: &[u8]) -> Result<()> { - let amt = cmp::min(data.len(), self.len()); - let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); - a.copy_from_slice(&data[..amt]); - *self = b; - - if amt == data.len() { - Ok(()) - } else { - Err(Error) - } - } -} - -impl Write for Vec { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> Result<()> { - self.extend_from_slice(buf); - Ok(()) - } -} - -/// This data structure is used as a workaround for current design of `ToBytes` -/// which does not allow multiple writes to `&mut [u8]`. -pub struct Cursor { - inner: T, - pos: usize, -} - -impl Cursor { - pub fn new(inner: T) -> Self { - Cursor { inner, pos: 0 } - } -} - -impl Write for Cursor<&mut [u8]> { - fn write_all(&mut self, buf: &[u8]) -> Result<()> { - let to_copy = cmp::min(self.inner.len() - self.pos, buf.len()); - self.inner[self.pos..self.pos + to_copy].copy_from_slice(buf); - self.pos += to_copy; - Ok(()) - } -} - -impl Read for Cursor<&mut [u8]> { - fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { - let to_copy = cmp::min(self.inner.len() - self.pos, buf.len()); - buf.copy_from_slice(&self.inner[self.pos..self.pos + to_copy]); - self.pos += to_copy; - Ok(()) - } -} - -impl Read for Cursor<&[u8]> { - fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { - let to_copy = cmp::min(self.inner.len() - self.pos, buf.len()); - buf.copy_from_slice(&self.inner[self.pos..self.pos + to_copy]); - self.pos += to_copy; - Ok(()) - } -} diff --git a/std/src/io/error.rs b/std/src/io/error.rs new file mode 100644 index 0000000..5c71ca8 --- /dev/null +++ b/std/src/io/error.rs @@ -0,0 +1,269 @@ +use crate::boxed::Box; +use crate::convert::From; +use crate::error; +use crate::fmt; + +/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and +/// associated traits. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// [`ErrorKind`]. +/// +/// [`Read`]: crate::io::Read +/// [`Write`]: crate::io::Write +/// [`Seek`]: crate::io::Seek +pub struct Error { + repr: Repr, +} + +pub type Result = core::result::Result; + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.repr, f) + } +} + +enum Repr { + Simple(ErrorKind), + Custom(Box), +} + +#[derive(Debug)] +struct Custom { + kind: ErrorKind, + error: Box, +} + +/// A list specifying general categories of I/O error. +/// +/// This list is intended to grow over time and it is not recommended to +/// exhaustively match against it. +/// +/// It is used with the [`io::Error`] type. +/// +/// [`io::Error`]: Error +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[allow(deprecated)] +#[non_exhaustive] +pub enum ErrorKind { + /// An entity was not found, often a file. + NotFound, + /// The operation lacked the necessary privileges to complete. + PermissionDenied, + /// The connection was refused by the remote server. + ConnectionRefused, + /// The connection was reset by the remote server. + ConnectionReset, + /// The connection was aborted (terminated) by the remote server. + ConnectionAborted, + /// The network operation failed because it was not connected yet. + NotConnected, + /// A socket address could not be bound because the address is already in + /// use elsewhere. + AddrInUse, + /// A nonexistent interface was requested or the requested address was not + /// local. + AddrNotAvailable, + /// The operation failed because a pipe was closed. + BrokenPipe, + /// An entity already exists, often a file. + AlreadyExists, + /// The operation needs to block to complete, but the blocking operation was + /// requested to not occur. + WouldBlock, + /// A parameter was incorrect. + InvalidInput, + /// Data not valid for the operation were encountered. + /// + /// Unlike [`InvalidInput`], this typically means that the operation + /// parameters were valid, however the error was caused by malformed + /// input data. + /// + /// For example, a function that reads a file into a string will error with + /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: ErrorKind::InvalidInput + InvalidData, + /// The I/O operation's timeout expired, causing it to be canceled. + TimedOut, + /// An error returned when an operation could not be completed because a + /// call to [`write`] returned [`Ok(0)`]. + /// + /// This typically means that an operation could only succeed if it wrote a + /// particular number of bytes but only a smaller number of bytes could be + /// written. + /// + /// [`write`]: crate::io::Write::write + /// [`Ok(0)`]: Ok + WriteZero, + /// This operation was interrupted. + /// + /// Interrupted operations can typically be retried. + Interrupted, + /// Any I/O error not part of this list. + /// + /// Errors that are `Other` now may move to a different or a new + /// [`ErrorKind`] variant in the future. It is not recommended to match + /// an error against `Other` and to expect any additional characteristics, + /// e.g., a specific [`Error::raw_os_error`] return value. + Other, + + /// An error returned when an operation could not be completed because an + /// "end of file" was reached prematurely. + /// + /// This typically means that an operation could only succeed if it read a + /// particular number of bytes but only a smaller number of bytes could be + /// read. + UnexpectedEof, +} + +impl ErrorKind { + pub(crate) fn as_str(&self) -> &'static str { + match *self { + ErrorKind::NotFound => "entity not found", + ErrorKind::PermissionDenied => "permission denied", + ErrorKind::ConnectionRefused => "connection refused", + ErrorKind::ConnectionReset => "connection reset", + ErrorKind::ConnectionAborted => "connection aborted", + ErrorKind::NotConnected => "not connected", + ErrorKind::AddrInUse => "address in use", + ErrorKind::AddrNotAvailable => "address not available", + ErrorKind::BrokenPipe => "broken pipe", + ErrorKind::AlreadyExists => "entity already exists", + ErrorKind::WouldBlock => "operation would block", + ErrorKind::InvalidInput => "invalid input parameter", + ErrorKind::InvalidData => "invalid data", + ErrorKind::TimedOut => "timed out", + ErrorKind::WriteZero => "write zero", + ErrorKind::Interrupted => "operation interrupted", + ErrorKind::Other => "other os error", + ErrorKind::UnexpectedEof => "unexpected end of file", + } + } +} + +/// Intended for use for errors not exposed to the user, where allocating onto +/// the heap (for normal construction via Error::new) is too costly. +impl From for Error { + /// Converts an [`ErrorKind`] into an [`Error`]. + /// + /// This conversion allocates a new error with a simple representation of error kind. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::{Error, ErrorKind}; + /// + /// let not_found = ErrorKind::NotFound; + /// let error = Error::from(not_found); + /// assert_eq!("entity not found", format!("{}", error)); + /// ``` + #[inline] + fn from(kind: ErrorKind) -> Error { + Error { + repr: Repr::Simple(kind), + } + } +} + +impl Error { + /// Creates a new I/O error from a known kind of error as well as an + /// arbitrary error payload. + /// + /// This function is used to generically create I/O errors which do not + /// originate from the OS itself. The `error` argument is an arbitrary + /// payload which will be contained in this [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::{Error, ErrorKind}; + /// + /// // errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); + /// + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// ``` + pub fn new(kind: ErrorKind, error: E) -> Error + where + E: Into>, + { + Self::_new(kind, error.into()) + } + + fn _new(kind: ErrorKind, error: Box) -> Error { + Error { + repr: Repr::Custom(Box::new(Custom { kind, error })), + } + } + + pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> { + match self.repr { + Repr::Simple(..) => None, + Repr::Custom(ref c) => Some(&*c.error), + } + } + + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> { + match self.repr { + Repr::Simple(..) => None, + Repr::Custom(ref mut c) => Some(&mut *c.error), + } + } + + /// Consumes the `Error`, returning its inner error (if any). + /// + /// If this [`Error`] was constructed via [`new`] then this function will + /// return [`Some`], otherwise it will return [`None`]. + /// + /// [`new`]: Error::new + pub fn into_inner(self) -> Option> { + match self.repr { + Repr::Simple(..) => None, + Repr::Custom(c) => Some(c.error), + } + } + + /// Returns the corresponding [`ErrorKind`] for this error. + pub fn kind(&self) -> ErrorKind { + match self.repr { + Repr::Custom(ref c) => c.kind, + Repr::Simple(kind) => kind, + } + } +} + +impl fmt::Debug for Repr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt), + Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.repr { + Repr::Custom(ref c) => c.error.fmt(fmt), + Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), + } + } +} + +impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.repr { + Repr::Simple(..) => None, + Repr::Custom(ref c) => c.error.source(), + } + } +} + +fn _assert_error_is_sync_send() { + fn _is_sync_send() {} + _is_sync_send::(); +} diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs new file mode 100644 index 0000000..9d8c22b --- /dev/null +++ b/std/src/io/mod.rs @@ -0,0 +1,544 @@ +//! no-std io replacement +use crate::{cmp, convert::TryInto, mem, vec::Vec}; + +mod error; +pub use error::*; + +pub mod prelude { + pub use super::{Read, Result, Write}; +} + +/// The `Read` trait allows for reading bytes from a source. +/// +/// Implementors of the `Read` trait are called 'readers'. +/// +/// Readers are defined by one required method, [`read()`]. Each call to [`read()`] +/// will attempt to pull bytes from this source into a provided buffer. A +/// number of other methods are implemented in terms of [`read()`], giving +/// implementors a number of ways to read bytes while only needing to implement +/// a single method. +/// +/// Readers are intended to be composable with one another. Many implementors +/// throughout [`ark_std::io`] take and provide types which implement the `Read` +/// trait. +/// +/// Please note that each call to [`read()`] may involve a system call, and +/// therefore, using something that implements [`BufRead`], such as +/// [`BufReader`], will be more efficient. +/// +/// +/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`: +/// +/// ```no_run +/// # use ark_std::io; +/// use ark_std::io::prelude::*; +/// +/// fn main() -> Result<()> { +/// let mut b = "This string will be read".as_bytes(); +/// let mut buffer = [0; 10]; +/// +/// // read up to 10 bytes +/// b.read(&mut buffer)?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// [`read()`]: trait.Read.html#tymethod.read +/// [`ark_std::io`]: ../../std/io/index.html +/// [`BufRead`]: trait.BufRead.html +/// [`BufReader`]: struct.BufReader.html +/// [`&str`]: ../../std/primitive.str.html +/// [slice]: ../../std/primitive.slice.html +pub trait Read { + /// Pull some bytes from this source into the specified buffer, returning + /// how many bytes were read. + /// + /// This function does not provide any guarantees about whether it blocks + /// waiting for data, but if an object needs to block for a read but cannot + /// it will typically signal this via an [`Err`] return value. + /// + /// If the return value of this method is [`Ok(n)`], then it must be + /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates + /// that the buffer `buf` has been filled in with `n` bytes of data from this + /// source. If `n` is `0`, then it can indicate that the the buffer + /// specified was 0 bytes in length. + /// + /// 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. + /// + /// # Errors + /// + /// 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. + /// + /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read + /// operation should be retried if there is nothing else to do. + /// + fn read(&mut self, buf: &mut [u8]) -> Result; + + /// Read the exact number of bytes required to fill `buf`. + /// + /// This function reads as many bytes as necessary to completely fill the + /// specified buffer `buf`. + /// + /// 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. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { + while !buf.is_empty() { + match self.read(buf) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(Error::new( + ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )) + } else { + Ok(()) + } + } + + /// Creates a "by reference" adaptor for this instance of `Read`. + /// + /// The returned adaptor also implements `Read` and will simply borrow this + /// current reader. + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } +} + +pub trait Write { + /// Write a buffer into this writer, returning how many bytes were written. + /// + /// This function will attempt to write the entire contents of `buf`, but + /// the entire write may not succeed, or the write may also generate an + /// error. A call to `write` represents *at most one* attempt to write to + /// any wrapped object. + /// + /// Calls to `write` are not guaranteed to block waiting for data to be + /// written, and a write which would otherwise block can be indicated through + /// an [`Err`] variant. + /// + /// If the return value is [`Ok(n)`] then it must be guaranteed that + /// `0 <= n <= buf.len()`. A return value of `0` typically means that the + /// underlying object is no longer able to accept bytes and will likely not + /// be able to in the future as well, or that the buffer provided is empty. + /// + /// # Errors + /// + /// Each call to `write` may generate an I/O error indicating that the + /// operation could not be completed. If an error is returned then no bytes + /// in the buffer were written to this writer. + /// + /// It is **not** considered an error if the entire buffer could not be + /// written to this writer. + /// + /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted + fn write(&mut self, buf: &[u8]) -> Result; + + /// Flush this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// # Errors + /// + /// It is considered an error if not all bytes could be written due to + /// I/O errors or EOF being reached. + /// + fn flush(&mut self) -> Result<()>; + + /// Attempts to write an entire buffer into this writer. + /// + /// This method will continuously call [`write`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns. + /// + /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`write`]: #tymethod.write + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => { + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write whole buffer", + )) + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Creates a "by reference" adaptor for this instance of `Write`. + /// + /// The returned adaptor also implements `Write` and will simply borrow this + /// current writer. + fn by_ref(&mut self) -> &mut Self + where + Self: Sized, + { + self + } +} + +impl Read for &mut R { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + (**self).read(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + (**self).read_exact(buf) + } +} + +impl Read for &[u8] { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + let amt = cmp::min(buf.len(), 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]; + } else { + buf[..amt].copy_from_slice(a); + } + + *self = b; + Ok(amt) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + if buf.len() > self.len() { + return Err(Error::new( + ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )); + } + let (a, b) = self.split_at(buf.len()); + + // 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 buf.len() == 1 { + buf[0] = a[0]; + } else { + buf.copy_from_slice(a); + } + + *self = b; + Ok(()) + } +} + +impl Write for &mut W { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + (**self).write(buf) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + (**self).flush() + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + (**self).write_all(buf) + } +} + +impl Write for &mut [u8] { + fn write(&mut self, data: &[u8]) -> Result { + let amt = cmp::min(data.len(), self.len()); + let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); + a.copy_from_slice(&data[..amt]); + *self = b; + Ok(amt) + } + + #[inline] + fn write_all(&mut self, data: &[u8]) -> Result<()> { + if self.write(data)? == data.len() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::WriteZero, + "failed to write whole buffer", + )) + } + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +impl Write for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +/// This data structure is used as a workaround for current design of `ToBytes` +/// which does not allow multiple writes to `&mut [u8]`. +pub struct Cursor { + inner: T, + pos: u64, +} + +impl Cursor { + /// Creates a new cursor wrapping the provided underlying in-memory buffer. + /// + /// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`) + /// is not empty. So writing to cursor starts with overwriting `Vec` + /// content, not with appending to it. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// ``` + pub fn new(inner: T) -> Self { + Cursor { inner, pos: 0 } + } + + /// Consumes this cursor, returning the underlying value. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let vec = buff.into_inner(); + /// ``` + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying value in this cursor. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let reference = buff.get_ref(); + /// ``` + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying value in this cursor. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying value as it may corrupt this cursor's position. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::Cursor; + /// + /// let mut buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let reference = buff.get_mut(); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + /// Returns the current position of this cursor. + pub fn position(&self) -> u64 { + self.pos + } + + /// Sets the position of this cursor. + /// + /// # Examples + /// + /// ``` + /// use ark_std::io::Cursor; + /// + /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); + /// + /// assert_eq!(buff.position(), 0); + /// + /// buff.set_position(2); + /// assert_eq!(buff.position(), 2); + /// + /// buff.set_position(4); + /// assert_eq!(buff.position(), 4); + /// ``` + pub fn set_position(&mut self, pos: u64) { + self.pos = pos; + } +} + +impl Read for Cursor +where + T: AsRef<[u8]>, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + let n = Read::read(&mut self.get_buf()?, buf)?; + self.pos += n as u64; + Ok(n) + } + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + let n = buf.len(); + Read::read_exact(&mut self.get_buf()?, buf)?; + self.pos += n as u64; + Ok(()) + } +} + +impl Cursor +where + T: AsRef<[u8]>, +{ + fn get_buf(&mut self) -> Result<&[u8]> { + let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); + Ok(&self.inner.as_ref()[(amt as usize)..]) + } +} + +impl Write for Cursor<&mut [u8]> { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + slice_write(&mut self.pos, self.inner, buf) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +impl Write for Cursor> { + fn write(&mut self, buf: &[u8]) -> Result { + vec_write(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +// Non-resizing write implementation +#[inline] +fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> Result { + let pos = cmp::min(*pos_mut, slice.len() as u64); + let amt = (&mut slice[(pos as usize)..]).write(buf)?; + *pos_mut += amt as u64; + Ok(amt) +} + +fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> Result { + let pos: usize = (*pos_mut).try_into().map_err(|_| { + Error::new( + ErrorKind::InvalidInput, + "cursor position exceeds maximum possible vector length", + ) + })?; + // Make sure the internal buffer is as least as big as where we + // currently are + let len = vec.len(); + if len < pos { + // use `resize` so that the zero filling is as efficient as possible + vec.resize(pos, 0); + } + // Figure out what bytes will be used to overwrite what's currently + // there (left), and what will be appended on the end (right) + { + let space = vec.len() - pos; + let (left, right) = buf.split_at(cmp::min(space, buf.len())); + vec[pos..pos + left.len()].copy_from_slice(left); + vec.extend_from_slice(right); + } + + // Bump us forward + *pos_mut = (pos + buf.len()) as u64; + Ok(buf.len()) +} diff --git a/std/src/lib.rs b/std/src/lib.rs index 6b16572..8eaa693 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -12,27 +12,26 @@ pub use core::*; #[cfg(not(feature = "std"))] pub mod fmt { - pub use core::fmt::*; pub use alloc::fmt::*; - + pub use core::fmt::*; } #[cfg(not(feature = "std"))] pub mod borrow { - pub use core::borrow::*; pub use alloc::borrow::*; + pub use core::borrow::*; } #[cfg(not(feature = "std"))] pub mod slice { - pub use core::slice::*; pub use alloc::slice::*; + pub use core::slice::*; } #[cfg(not(feature = "std"))] pub mod str { - pub use core::str::*; pub use alloc::str::*; + pub use core::str::*; } #[cfg(not(feature = "std"))]