diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index fb3e4b87..c999e262 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -27,8 +27,8 @@ bitcoinconsensus-std = ["bitcoinconsensus/std", "std"] # The no-std feature doesn't disable std - you need to turn off the std feature for that by disabling default. # Instead no-std enables additional features required for this crate to be usable without std. # As a result, both can be enabled without conflict. -std = ["secp256k1/std", "bitcoin-io/std", "hashes/std", "bech32/std", "internals/std", "hex/std"] -no-std = ["hashes/alloc", "hashes/io", "bitcoin-io/alloc", "bech32/alloc", "secp256k1/alloc", "hex/alloc"] +std = ["secp256k1/std", "io/std", "hashes/std", "bech32/std", "internals/std", "hex/std"] +no-std = ["hashes/alloc", "hashes/io", "io/alloc", "bech32/alloc", "secp256k1/alloc", "hex/alloc"] [package.metadata.docs.rs] all-features = true @@ -40,10 +40,9 @@ hex = { package = "hex-conservative", version = "0.1.1", default-features = fals bech32 = { version = "0.10.0-beta", default-features = false } hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = false } secp256k1 = { version = "0.28.0", default-features = false, features = ["hashes"] } +io = { package = "bitcoin-io", version = "0.1", default-features = false } hex_lit = "0.1.1" -bitcoin-io = { version = "0.1", default-features = false } - base64 = { version = "0.21.3", optional = true } # Only use this feature for no-std builds, otherwise use bitcoinconsensus-std. bitcoinconsensus = { version = "0.20.2-0.5.0", default-features = false, optional = true } diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index 6fd04af2..36fe3ee7 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -74,6 +74,9 @@ pub extern crate hashes; /// Re-export the `hex-conservative` crate. pub extern crate hex; +/// Re-export the `bitcoin-io` crate. +pub extern crate io; + /// Rust wrapper library for Pieter Wuille's libsecp256k1. Implements ECDSA and BIP 340 signatures /// for the SECG elliptic curve group secp256k1 and related utilities. pub extern crate secp256k1; @@ -113,7 +116,6 @@ pub mod sign_message; pub mod string; pub mod taproot; -use bitcoin_io::io; #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] diff --git a/hashes/embedded/src/main.rs b/hashes/embedded/src/main.rs index bba22ff8..447626c5 100644 --- a/hashes/embedded/src/main.rs +++ b/hashes/embedded/src/main.rs @@ -10,7 +10,7 @@ extern crate bitcoin_hashes; #[cfg(feature = "alloc")] use alloc::string::ToString; use bitcoin_hashes::{sha256, Hash, HashEngine}; -use bitcoin_io::io::Write; +use bitcoin_io::Write; use core::str::FromStr; use cortex_m_rt::entry; use cortex_m_semihosting::{debug, hprintln}; diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs index 0f7cc5a0..3f093b83 100644 --- a/hashes/src/impls.rs +++ b/hashes/src/impls.rs @@ -66,7 +66,7 @@ impl_write!( #[cfg(test)] mod tests { - use bitcoin_io::io::Write; + use bitcoin_io::Write; use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash}; diff --git a/io/src/lib.rs b/io/src/lib.rs index c79e6f34..2d14fb0d 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -24,331 +24,330 @@ mod macros; /// Standard I/O stream definitions which are API-equivalent to `std`'s `io` module. See /// [`std::io`] for more info. -pub mod io { - #[cfg(any(feature = "alloc", feature = "std"))] +#[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 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) } - } + use alloc::string::String; + use core::fmt::Debug; + pub trait IntoBoxDynDebug { + fn into(self) -> Box; } - - #[derive(Debug)] - pub struct Error { - kind: ErrorKind, - - #[cfg(feature = "std")] - error: Option>, - #[cfg(all(feature = "alloc", not(feature = "std")))] - error: Option>, + impl IntoBoxDynDebug for &str { + fn into(self) -> Box { Box::new(String::from(self)) } } - 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 IntoBoxDynDebug for String { + fn into(self) -> Box { Box::new(self) } } - - 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; - - /// 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() { - match self.read(buf) { - Ok(0) => return Err(ErrorKind::UnexpectedEof.into()), - Ok(len) => buf = &mut buf[len..], - Err(e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - #[inline] - fn take(&mut self, limit: u64) -> Take { Take { reader: self, remaining: limit } } - } - - 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 { - let len = core::cmp::min(buf.len(), self.remaining.try_into().unwrap_or(buf.len())); - let read = self.reader.read(&mut buf[..len])?; - self.remaining -= read.try_into().unwrap_or(self.remaining); - Ok(read) - } - } - - #[cfg(feature = "std")] - impl Read for R { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> Result { - Ok(::read(self, buf)?) - } - } - - #[cfg(not(feature = "std"))] - impl Read for &[u8] { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> Result { - let cnt = core::cmp::min(self.len(), buf.len()); - buf[..cnt].copy_from_slice(&self[..cnt]); - *self = &self[cnt..]; - Ok(cnt) - } - } - - 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 { - let inner: &[u8] = self.inner.as_ref(); - let start_pos = self.pos.try_into().unwrap_or(inner.len()); - let read = core::cmp::min(inner.len().saturating_sub(start_pos), buf.len()); - buf[..read].copy_from_slice(&inner[start_pos..start_pos + read]); - self.pos = self - .pos - .saturating_add(read.try_into().unwrap_or(u64::max_value() /* unreachable */)); - Ok(read) - } - } - - /// 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] - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => return Err(ErrorKind::UnexpectedEof.into()), - Ok(len) => buf = &buf[len..], - Err(e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - } - - #[cfg(feature = "std")] - impl Write for W { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - Ok(::write(self, buf)?) - } - #[inline] - fn flush(&mut self) -> Result<()> { Ok(::flush(self)?) } - } - - #[cfg(all(feature = "alloc", not(feature = "std")))] - impl Write for alloc::vec::Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - #[inline] - fn flush(&mut self) -> Result<()> { Ok(()) } - } - - #[cfg(not(feature = "std"))] - impl<'a> Write for &'a mut [u8] { - #[inline] - fn write(&mut self, buf: &[u8]) -> Result { - let cnt = core::cmp::min(self.len(), buf.len()); - self[..cnt].copy_from_slice(&buf[..cnt]); - *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 } } + +#[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; + +/// 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() { + match self.read(buf) { + Ok(0) => return Err(ErrorKind::UnexpectedEof.into()), + Ok(len) => buf = &mut buf[len..], + Err(e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + #[inline] + fn take(&mut self, limit: u64) -> Take { Take { reader: self, remaining: limit } } +} + +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 { + let len = core::cmp::min(buf.len(), self.remaining.try_into().unwrap_or(buf.len())); + let read = self.reader.read(&mut buf[..len])?; + self.remaining -= read.try_into().unwrap_or(self.remaining); + Ok(read) + } +} + +#[cfg(feature = "std")] +impl Read for R { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + Ok(::read(self, buf)?) + } +} + +#[cfg(not(feature = "std"))] +impl Read for &[u8] { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + let cnt = core::cmp::min(self.len(), buf.len()); + buf[..cnt].copy_from_slice(&self[..cnt]); + *self = &self[cnt..]; + Ok(cnt) + } +} + +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 { + let inner: &[u8] = self.inner.as_ref(); + let start_pos = self.pos.try_into().unwrap_or(inner.len()); + let read = core::cmp::min(inner.len().saturating_sub(start_pos), buf.len()); + buf[..read].copy_from_slice(&inner[start_pos..start_pos + read]); + self.pos = self + .pos + .saturating_add(read.try_into().unwrap_or(u64::max_value() /* unreachable */)); + Ok(read) + } +} + +/// 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] + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => return Err(ErrorKind::UnexpectedEof.into()), + Ok(len) => buf = &buf[len..], + Err(e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } +} + +#[cfg(feature = "std")] +impl Write for W { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + Ok(::write(self, buf)?) + } + #[inline] + fn flush(&mut self) -> Result<()> { Ok(::flush(self)?) } +} + +#[cfg(all(feature = "alloc", not(feature = "std")))] +impl Write for alloc::vec::Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + #[inline] + fn flush(&mut self) -> Result<()> { Ok(()) } +} + +#[cfg(not(feature = "std"))] +impl<'a> Write for &'a mut [u8] { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + let cnt = core::cmp::min(self.len(), buf.len()); + self[..cnt].copy_from_slice(&buf[..cnt]); + *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 } + diff --git a/io/src/macros.rs b/io/src/macros.rs index a3714188..7ea91836 100644 --- a/io/src/macros.rs +++ b/io/src/macros.rs @@ -11,13 +11,13 @@ #[cfg(not(feature = "std"))] macro_rules! impl_write { ($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => { - impl<$($bounded_ty: $bounds),*> $crate::io::Write for $ty { + impl<$($bounded_ty: $bounds),*> $crate::Write for $ty { #[inline] - fn write(&mut self, buf: &[u8]) -> $crate::io::Result { + fn write(&mut self, buf: &[u8]) -> $crate::Result { $write_fn(self, buf) } #[inline] - fn flush(&mut self) -> $crate::io::Result<()> { + fn flush(&mut self) -> $crate::Result<()> { $flush_fn(self) } }