Skip to content

Commit

Permalink
Hide Repr details from io::Error, and rework io::Error::new_const.
Browse files Browse the repository at this point in the history
  • Loading branch information
thomcc committed Feb 5, 2022
1 parent 71226d7 commit 554918e
Show file tree
Hide file tree
Showing 49 changed files with 345 additions and 269 deletions.
2 changes: 1 addition & 1 deletion library/std/src/ffi/c_str.rs
Expand Up @@ -1077,7 +1077,7 @@ impl fmt::Display for NulError {
impl From<NulError> for io::Error {
/// Converts a [`NulError`] into a [`io::Error`].
fn from(_: NulError) -> io::Error {
io::Error::new_const(io::ErrorKind::InvalidInput, &"data provided contains a nul byte")
io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/std/src/fs.rs
Expand Up @@ -2263,9 +2263,9 @@ impl DirBuilder {
match path.parent() {
Some(p) => self.create_dir_all(p)?,
None => {
return Err(io::Error::new_const(
return Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
&"failed to create whole tree",
"failed to create whole tree",
));
}
}
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/io/buffered/bufreader.rs
Expand Up @@ -357,9 +357,9 @@ impl<R: Read> Read for BufReader<R> {
let mut bytes = Vec::new();
self.read_to_end(&mut bytes)?;
let string = crate::str::from_utf8(&bytes).map_err(|_| {
io::Error::new_const(
io::const_io_error!(
io::ErrorKind::InvalidData,
&"stream did not contain valid UTF-8",
"stream did not contain valid UTF-8",
)
})?;
*buf += string;
Expand Down
6 changes: 3 additions & 3 deletions library/std/src/io/buffered/bufwriter.rs
@@ -1,7 +1,7 @@
use crate::error;
use crate::fmt;
use crate::io::{
self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
};
use crate::mem;
use crate::ptr;
Expand Down Expand Up @@ -168,9 +168,9 @@ impl<W: Write> BufWriter<W> {

match r {
Ok(0) => {
return Err(Error::new_const(
return Err(io::const_io_error!(
ErrorKind::WriteZero,
&"failed to write the buffered data",
"failed to write the buffered data",
));
}
Ok(n) => guard.consume(n),
Expand Down
10 changes: 5 additions & 5 deletions library/std/src/io/cursor.rs
Expand Up @@ -4,7 +4,7 @@ mod tests;
use crate::io::prelude::*;

use crate::cmp;
use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};

use core::convert::TryInto;

Expand Down Expand Up @@ -297,9 +297,9 @@ where
self.pos = n;
Ok(self.pos)
}
None => Err(Error::new_const(
None => Err(io::const_io_error!(
ErrorKind::InvalidInput,
&"invalid seek to a negative or overflowing position",
"invalid seek to a negative or overflowing position",
)),
}
}
Expand Down Expand Up @@ -400,9 +400,9 @@ fn slice_write_vectored(
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
Error::new_const(
io::const_io_error!(
ErrorKind::InvalidInput,
&"cursor position exceeds maximum possible vector length",
"cursor position exceeds maximum possible vector length",
)
})?;
// Make sure the internal buffer is as least as big as where we
Expand Down
160 changes: 95 additions & 65 deletions library/std/src/io/error.rs
@@ -1,6 +1,9 @@
#[cfg(test)]
mod tests;

mod repr_unpacked;
use repr_unpacked::Repr;

use crate::convert::From;
use crate::error;
use crate::fmt;
Expand Down Expand Up @@ -66,15 +69,38 @@ impl fmt::Debug for Error {
}
}

enum Repr {
enum ErrorData<C> {
Os(i32),
Simple(ErrorKind),
// &str is a fat pointer, but &&str is a thin pointer.
SimpleMessage(ErrorKind, &'static &'static str),
Custom(Box<Custom>),
SimpleMessage(&'static SimpleMessage),
Custom(C),
}

#[repr(align(4))]
#[doc(hidden)]
pub(crate) struct SimpleMessage {
kind: ErrorKind,
message: &'static str,
}

impl SimpleMessage {
pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
Self { kind, message }
}
}

/// Create and return an `io::Error` for a given `ErrorKind` and constant
/// message. This doesn't allocate.
pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
$crate::io::error::Error::from_static_message({
const MESSAGE_DATA: $crate::io::error::SimpleMessage =
$crate::io::error::SimpleMessage::new($kind, $message);
&MESSAGE_DATA
})
}

#[derive(Debug)]
#[repr(align(4))]
struct Custom {
kind: ErrorKind,
error: Box<dyn error::Error + Send + Sync>,
Expand Down Expand Up @@ -396,7 +422,7 @@ impl From<ErrorKind> for Error {
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
Error { repr: Repr::Simple(kind) }
Error { repr: Repr::new_simple(kind) }
}
}

Expand Down Expand Up @@ -461,20 +487,22 @@ impl Error {
}

fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
}

/// Creates a new I/O error from a known kind of error as well as a
/// constant message.
/// Creates a new I/O error from a known kind of error as well as a constant
/// message.
///
/// This function does not allocate.
///
/// This function should maybe change to
/// `new_const<const MSG: &'static str>(kind: ErrorKind)`
/// in the future, when const generics allow that.
/// You should not use this directly, and instead use the `const_io_error!`
/// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
///
/// This function should maybe change to `from_static_message<const MSG: &'static
/// str>(kind: ErrorKind)` in the future, when const generics allow that.
#[inline]
pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
Self { repr: Repr::SimpleMessage(kind, message) }
pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
Self { repr: Repr::new_simple_message(msg) }
}

/// Returns an error representing the last OS error which occurred.
Expand Down Expand Up @@ -532,7 +560,7 @@ impl Error {
#[must_use]
#[inline]
pub fn from_raw_os_error(code: i32) -> Error {
Error { repr: Repr::Os(code) }
Error { repr: Repr::new_os(code) }
}

/// Returns the OS error that this error represents (if any).
Expand Down Expand Up @@ -568,11 +596,11 @@ impl Error {
#[must_use]
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
match self.repr.data() {
ErrorData::Os(i) => Some(i),
ErrorData::Custom(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
}
}

Expand Down Expand Up @@ -607,11 +635,11 @@ impl Error {
#[must_use]
#[inline]
pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
Repr::Custom(ref c) => Some(&*c.error),
match self.repr.data() {
ErrorData::Os(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
ErrorData::Custom(c) => Some(&*c.error),
}
}

Expand Down Expand Up @@ -681,11 +709,11 @@ impl Error {
#[must_use]
#[inline]
pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
Repr::Custom(ref mut c) => Some(&mut *c.error),
match self.repr.data_mut() {
ErrorData::Os(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
ErrorData::Custom(c) => Some(&mut *c.error),
}
}

Expand Down Expand Up @@ -720,11 +748,11 @@ impl Error {
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
Repr::Custom(c) => Some(c.error),
match self.repr.into_data() {
ErrorData::Os(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
ErrorData::Custom(c) => Some(c.error),
}
}

Expand All @@ -750,44 +778,46 @@ impl Error {
#[must_use]
#[inline]
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Os(code) => sys::decode_error_kind(code),
Repr::Custom(ref c) => c.kind,
Repr::Simple(kind) => kind,
Repr::SimpleMessage(kind, _) => kind,
match self.repr.data() {
ErrorData::Os(code) => sys::decode_error_kind(code),
ErrorData::Custom(ref c) => c.kind,
ErrorData::Simple(kind) => kind,
ErrorData::SimpleMessage(m) => m.kind,
}
}
}

impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Repr::Os(code) => fmt
match self.data() {
ErrorData::Os(code) => fmt
.debug_struct("Os")
.field("code", &code)
.field("kind", &sys::decode_error_kind(code))
.field("message", &sys::os::error_string(code))
.finish(),
Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
Repr::SimpleMessage(kind, &message) => {
fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
}
ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
ErrorData::SimpleMessage(msg) => fmt
.debug_struct("Error")
.field("kind", &msg.kind)
.field("message", &msg.message)
.finish(),
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.repr {
Repr::Os(code) => {
match self.repr.data() {
ErrorData::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
Repr::Custom(ref c) => c.error.fmt(fmt),
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
ErrorData::Custom(ref c) => c.error.fmt(fmt),
ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
}
}
}
Expand All @@ -796,29 +826,29 @@ impl fmt::Display for Error {
impl error::Error for Error {
#[allow(deprecated, deprecated_in_future)]
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
Repr::SimpleMessage(_, &msg) => msg,
Repr::Custom(ref c) => c.error.description(),
match self.repr.data() {
ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(),
ErrorData::SimpleMessage(msg) => msg.message,
ErrorData::Custom(ref c) => c.error.description(),
}
}

#[allow(deprecated)]
fn cause(&self) -> Option<&dyn error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
Repr::Custom(ref c) => c.error.cause(),
match self.repr.data() {
ErrorData::Os(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
ErrorData::Custom(ref c) => c.error.cause(),
}
}

fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::SimpleMessage(..) => None,
Repr::Custom(ref c) => c.error.source(),
match self.repr.data() {
ErrorData::Os(..) => None,
ErrorData::Simple(..) => None,
ErrorData::SimpleMessage(..) => None,
ErrorData::Custom(ref c) => c.error.source(),
}
}
}
Expand Down

0 comments on commit 554918e

Please sign in to comment.