From f83d68f2466ac6d1775a83b293ec8564b675585a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 28 Nov 2023 11:55:30 +1100 Subject: [PATCH 1/4] Add vertical whitespace Make the `io` crate conform to `rust-bitcoin` code style in regards to whitespace between functions/types etc. Whitespace only, no other changes. --- io/src/lib.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/io/src/lib.rs b/io/src/lib.rs index 7a84eb0a..2b8008f1 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -34,12 +34,15 @@ mod sealed { use alloc::boxed::Box; use alloc::string::String; use core::fmt::Debug; + pub trait IntoBoxDynDebug { fn into(self) -> Box; } + impl IntoBoxDynDebug for &str { fn into(self) -> Box { Box::new(String::from(self)) } } + impl IntoBoxDynDebug for String { fn into(self) -> Box { Box::new(self) } } @@ -54,6 +57,7 @@ pub struct Error { #[cfg(all(feature = "alloc", not(feature = "std")))] error: Option>, } + impl Error { #[cfg(feature = "std")] pub fn new(kind: ErrorKind, error: E) -> Error @@ -62,6 +66,7 @@ impl Error { { Self { kind, error: Some(error.into()) } } + #[cfg(all(feature = "alloc", not(feature = "std")))] pub fn new(kind: ErrorKind, error: E) -> Error { Self { kind, error: Some(error.into()) } @@ -96,6 +101,7 @@ impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.error.as_ref().and_then(|e| e.as_ref().source()) } + #[allow(deprecated)] fn description(&self) -> &str { match self.error.as_ref() { @@ -103,6 +109,7 @@ impl std::error::Error for Error { None => self.kind.description(), } } + #[allow(deprecated)] fn cause(&self) -> Option<&dyn std::error::Error> { self.error.as_ref().and_then(|e| e.as_ref().cause()) @@ -114,6 +121,7 @@ impl Error { pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { self.error.as_deref() } + #[cfg(all(feature = "alloc", not(feature = "std")))] pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { self.error.as_deref() } } @@ -154,12 +162,14 @@ macro_rules! define_errorkind { $(Self::$kind => stringify!($kind)),* } } + #[cfg(feature = "std")] fn to_std(self) -> std::io::ErrorKind { match self { $(Self::$kind => std::io::ErrorKind::$kind),* } } + #[cfg(feature = "std")] fn from_std(o: std::io::ErrorKind) -> ErrorKind { match o { @@ -198,6 +208,7 @@ pub type Result = core::result::Result; /// A generic trait describing an input stream. See [`std::io::Read`] for more info. pub trait Read { fn read(&mut self, buf: &mut [u8]) -> Result; + #[inline] fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { while !buf.is_empty() { @@ -210,6 +221,7 @@ pub trait Read { } Ok(()) } + #[inline] fn take(&mut self, limit: u64) -> Take { Take { reader: self, remaining: limit } } } @@ -218,6 +230,7 @@ pub struct Take<'a, R: Read + ?Sized> { reader: &'a mut R, remaining: u64, } + impl<'a, R: Read + ?Sized> Read for Take<'a, R> { #[inline] fn read(&mut self, buf: &mut [u8]) -> Result { @@ -251,14 +264,18 @@ pub struct Cursor { inner: T, pos: u64, } + impl> Cursor { #[inline] pub fn new(inner: T) -> Self { Cursor { inner, pos: 0 } } + #[inline] pub fn position(&self) -> u64 { self.pos } + #[inline] pub fn into_inner(self) -> T { self.inner } } + impl> Read for Cursor { #[inline] fn read(&mut self, buf: &mut [u8]) -> Result { @@ -275,6 +292,7 @@ impl> Read for Cursor { /// A generic trait describing an output stream. See [`std::io::Write`] for more info. pub trait Write { fn write(&mut self, buf: &[u8]) -> Result; + fn flush(&mut self) -> Result<()>; #[inline] @@ -297,6 +315,7 @@ impl Write for W { fn write(&mut self, buf: &[u8]) -> Result { Ok(::write(self, buf)?) } + #[inline] fn flush(&mut self) -> Result<()> { Ok(::flush(self)?) } } @@ -308,6 +327,7 @@ impl Write for alloc::vec::Vec { self.extend_from_slice(buf); Ok(buf.len()) } + #[inline] fn flush(&mut self) -> Result<()> { Ok(()) } } @@ -321,29 +341,37 @@ impl<'a> Write for &'a mut [u8] { *self = &mut core::mem::take(self)[cnt..]; Ok(cnt) } + #[inline] fn flush(&mut self) -> Result<()> { Ok(()) } } /// A sink to which all writes succeed. See [`std::io::Sink`] for more info. pub struct Sink; + #[cfg(not(feature = "std"))] impl Write for Sink { #[inline] fn write(&mut self, buf: &[u8]) -> Result { Ok(buf.len()) } + #[inline] fn write_all(&mut self, _: &[u8]) -> Result<()> { Ok(()) } + #[inline] fn flush(&mut self) -> Result<()> { Ok(()) } } + #[cfg(feature = "std")] impl std::io::Write for Sink { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Ok(buf.len()) } + #[inline] fn write_all(&mut self, _: &[u8]) -> std::io::Result<()> { Ok(()) } + #[inline] fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } + /// Returns a sink to which all writes succeed. See [`std::io::sink`] for more info. pub fn sink() -> Sink { Sink } From 67511ed03f91a8230e08bd8e45202daaa83536ba Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 28 Nov 2023 11:58:52 +1100 Subject: [PATCH 2/4] Move no_std above comment Currently the no_std attribute is below a comment that does not relate to it. For slightly improved clarity move the attribute above the comment. --- io/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/src/lib.rs b/io/src/lib.rs index 2b8008f1..49862308 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -13,9 +13,9 @@ //! This traits are not one-for-one drop-ins, but are as close as possible while still implementing //! `std::io`'s traits without unnecessary complexity. +#![cfg_attr(not(feature = "std"), no_std)] // Experimental features we need. #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(not(feature = "std"), no_std)] #[cfg(any(feature = "alloc", feature = "std"))] extern crate alloc; From 82ea4ff31d9fbd37822dc1a533ab7171de3681dc Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 28 Nov 2023 12:09:35 +1100 Subject: [PATCH 3/4] Move error code to submodule Move error code to a private `error` submodule and re-export it at the crate root. (Puts private `sealed` module at the bottom of the file i.e., this patch is strictly a code move but we re-order the code while moving it.) --- io/src/error.rs | 177 ++++++++++++++++++++++++++++++++++++++++++++++ io/src/lib.rs | 181 ++---------------------------------------------- 2 files changed, 181 insertions(+), 177 deletions(-) create mode 100644 io/src/error.rs diff --git a/io/src/error.rs b/io/src/error.rs new file mode 100644 index 00000000..c2d18a2a --- /dev/null +++ b/io/src/error.rs @@ -0,0 +1,177 @@ +#[cfg(any(feature = "alloc", feature = "std"))] +use alloc::boxed::Box; +use core::fmt::{Debug, Display, Formatter}; + +#[derive(Debug)] +pub struct Error { + kind: ErrorKind, + + #[cfg(feature = "std")] + error: Option>, + #[cfg(all(feature = "alloc", not(feature = "std")))] + error: Option>, +} + +impl Error { + #[cfg(feature = "std")] + pub fn new(kind: ErrorKind, error: E) -> Error + where + E: Into>, + { + Self { kind, error: Some(error.into()) } + } + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub fn new(kind: ErrorKind, error: E) -> Error { + Self { kind, error: Some(error.into()) } + } + + pub fn kind(&self) -> ErrorKind { self.kind } +} + +impl From for Error { + fn from(kind: ErrorKind) -> Error { + Self { + kind, + #[cfg(any(feature = "std", feature = "alloc"))] + error: None, + } + } +} + +impl Display for Error { + fn fmt(&self, fmt: &mut Formatter) -> core::result::Result<(), core::fmt::Error> { + fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?; + #[cfg(any(feature = "alloc", feature = "std"))] + if let Some(e) = &self.error { + fmt.write_fmt(format_args!(". {:?}", e))?; + } + Ok(()) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.error.as_ref().and_then(|e| e.as_ref().source()) + } + + #[allow(deprecated)] + fn description(&self) -> &str { + match self.error.as_ref() { + Some(e) => e.description(), + None => self.kind.description(), + } + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn std::error::Error> { + self.error.as_ref().and_then(|e| e.as_ref().cause()) + } +} + +impl Error { + #[cfg(feature = "std")] + pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { + self.error.as_deref() + } + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { self.error.as_deref() } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(o: std::io::Error) -> Error { + Self { kind: ErrorKind::from_std(o.kind()), error: o.into_inner() } + } +} + +#[cfg(feature = "std")] +impl From for std::io::Error { + fn from(o: Error) -> std::io::Error { + if let Some(err) = o.error { + std::io::Error::new(o.kind.to_std(), err) + } else { + o.kind.to_std().into() + } + } +} + +macro_rules! define_errorkind { + ($($kind: ident),*) => { + #[non_exhaustive] + #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] + /// A minimal subset of [`std::io::ErrorKind`] which is used for [`Error`]. Note that, as with + /// [`std::io`], only [`Self::Interrupted`] has defined semantics in this crate, all other + /// variants are provided here only to provide higher-fidelity conversions to and from + /// [`std::io::Error`]. + pub enum ErrorKind { + $($kind),* + } + + impl ErrorKind { + fn description(&self) -> &'static str { + match self { + $(Self::$kind => stringify!($kind)),* + } + } + + #[cfg(feature = "std")] + fn to_std(self) -> std::io::ErrorKind { + match self { + $(Self::$kind => std::io::ErrorKind::$kind),* + } + } + + #[cfg(feature = "std")] + fn from_std(o: std::io::ErrorKind) -> ErrorKind { + match o { + $(std::io::ErrorKind::$kind => ErrorKind::$kind),*, + _ => ErrorKind::Other + } + } + } + } +} + +define_errorkind!( + NotFound, + PermissionDenied, + ConnectionRefused, + ConnectionReset, + ConnectionAborted, + NotConnected, + AddrInUse, + AddrNotAvailable, + BrokenPipe, + AlreadyExists, + WouldBlock, + InvalidInput, + InvalidData, + TimedOut, + WriteZero, + Interrupted, + UnexpectedEof, + // Note: Any time we bump the MSRV any new error kinds should be added here! + Other +); + +#[cfg(all(feature = "alloc", not(feature = "std")))] +mod sealed { + use alloc::boxed::Box; + use alloc::string::String; + use core::fmt::Debug; + + pub trait IntoBoxDynDebug { + fn into(self) -> Box; + } + + impl IntoBoxDynDebug for &str { + fn into(self) -> Box { Box::new(String::from(self)) } + } + + impl IntoBoxDynDebug for String { + fn into(self) -> Box { Box::new(self) } + } +} diff --git a/io/src/lib.rs b/io/src/lib.rs index 49862308..32e717da 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -20,188 +20,15 @@ #[cfg(any(feature = "alloc", feature = "std"))] extern crate alloc; +mod error; mod macros; +#[rustfmt::skip] // Keep public re-exports separate. +pub use self::error::{Error, ErrorKind}; + /// Standard I/O stream definitions which are API-equivalent to `std`'s `io` module. See /// [`std::io`] for more info. -#[cfg(any(feature = "alloc", feature = "std"))] -use alloc::boxed::Box; use core::convert::TryInto; -use core::fmt::{Debug, Display, Formatter}; - -#[cfg(all(feature = "alloc", not(feature = "std")))] -mod sealed { - use alloc::boxed::Box; - use alloc::string::String; - use core::fmt::Debug; - - pub trait IntoBoxDynDebug { - fn into(self) -> Box; - } - - impl IntoBoxDynDebug for &str { - fn into(self) -> Box { Box::new(String::from(self)) } - } - - impl IntoBoxDynDebug for String { - fn into(self) -> Box { Box::new(self) } - } -} - -#[derive(Debug)] -pub struct Error { - kind: ErrorKind, - - #[cfg(feature = "std")] - error: Option>, - #[cfg(all(feature = "alloc", not(feature = "std")))] - error: Option>, -} - -impl Error { - #[cfg(feature = "std")] - pub fn new(kind: ErrorKind, error: E) -> Error - where - E: Into>, - { - Self { kind, error: Some(error.into()) } - } - - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub fn new(kind: ErrorKind, error: E) -> Error { - Self { kind, error: Some(error.into()) } - } - - pub fn kind(&self) -> ErrorKind { self.kind } -} - -impl From for Error { - fn from(kind: ErrorKind) -> Error { - Self { - kind, - #[cfg(any(feature = "std", feature = "alloc"))] - error: None, - } - } -} - -impl Display for Error { - fn fmt(&self, fmt: &mut Formatter) -> core::result::Result<(), core::fmt::Error> { - fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?; - #[cfg(any(feature = "alloc", feature = "std"))] - if let Some(e) = &self.error { - fmt.write_fmt(format_args!(". {:?}", e))?; - } - Ok(()) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.error.as_ref().and_then(|e| e.as_ref().source()) - } - - #[allow(deprecated)] - fn description(&self) -> &str { - match self.error.as_ref() { - Some(e) => e.description(), - None => self.kind.description(), - } - } - - #[allow(deprecated)] - fn cause(&self) -> Option<&dyn std::error::Error> { - self.error.as_ref().and_then(|e| e.as_ref().cause()) - } -} - -impl Error { - #[cfg(feature = "std")] - pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { - self.error.as_deref() - } - - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { self.error.as_deref() } -} - -#[cfg(feature = "std")] -impl From for Error { - fn from(o: std::io::Error) -> Error { - Self { kind: ErrorKind::from_std(o.kind()), error: o.into_inner() } - } -} - -#[cfg(feature = "std")] -impl From for std::io::Error { - fn from(o: Error) -> std::io::Error { - if let Some(err) = o.error { - std::io::Error::new(o.kind.to_std(), err) - } else { - o.kind.to_std().into() - } - } -} - -macro_rules! define_errorkind { - ($($kind: ident),*) => { - #[non_exhaustive] - #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] - /// A minimal subset of [`std::io::ErrorKind`] which is used for [`Error`]. Note that, as with - /// [`std::io`], only [`Self::Interrupted`] has defined semantics in this crate, all other - /// variants are provided here only to provide higher-fidelity conversions to and from - /// [`std::io::Error`]. - pub enum ErrorKind { - $($kind),* - } - - impl ErrorKind { - fn description(&self) -> &'static str { - match self { - $(Self::$kind => stringify!($kind)),* - } - } - - #[cfg(feature = "std")] - fn to_std(self) -> std::io::ErrorKind { - match self { - $(Self::$kind => std::io::ErrorKind::$kind),* - } - } - - #[cfg(feature = "std")] - fn from_std(o: std::io::ErrorKind) -> ErrorKind { - match o { - $(std::io::ErrorKind::$kind => ErrorKind::$kind),*, - _ => ErrorKind::Other - } - } - } - } -} - -define_errorkind!( - NotFound, - PermissionDenied, - ConnectionRefused, - ConnectionReset, - ConnectionAborted, - NotConnected, - AddrInUse, - AddrNotAvailable, - BrokenPipe, - AlreadyExists, - WouldBlock, - InvalidInput, - InvalidData, - TimedOut, - WriteZero, - Interrupted, - UnexpectedEof, - // Note: Any time we bump the MSRV any new error kinds should be added here! - Other -); pub type Result = core::result::Result; From b1870656c945d2417c55d46e8ef371b30776f0ba Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 28 Nov 2023 12:12:34 +1100 Subject: [PATCH 4/4] Combine the two Error impl blocks together We have two impl blocks for `Error`, just squash them together into a single one. --- io/src/error.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/io/src/error.rs b/io/src/error.rs index c2d18a2a..8d0a894d 100644 --- a/io/src/error.rs +++ b/io/src/error.rs @@ -27,6 +27,16 @@ impl Error { } pub fn kind(&self) -> ErrorKind { self.kind } + + #[cfg(feature = "std")] + pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { + self.error.as_deref() + } + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { + self.error.as_deref() + } } impl From for Error { @@ -70,16 +80,6 @@ impl std::error::Error for Error { } } -impl Error { - #[cfg(feature = "std")] - pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> { - self.error.as_deref() - } - - #[cfg(all(feature = "alloc", not(feature = "std")))] - pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { self.error.as_deref() } -} - #[cfg(feature = "std")] impl From for Error { fn from(o: std::io::Error) -> Error {