diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs index 940d1c1e..db46f944 100644 --- a/bitcoin/src/internal_macros.rs +++ b/bitcoin/src/internal_macros.rs @@ -34,7 +34,6 @@ macro_rules! impl_consensus_encoding { fn consensus_decode( r: &mut R, ) -> Result<$thing, $crate::consensus::encode::Error> { - use crate::io::Read as _; let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64); Ok($thing { $($field: $crate::consensus::Decodable::consensus_decode(&mut r)?),+ diff --git a/bitcoin/src/p2p/message.rs b/bitcoin/src/p2p/message.rs index d4d0cb59..448e8a1c 100644 --- a/bitcoin/src/p2p/message.rs +++ b/bitcoin/src/p2p/message.rs @@ -10,7 +10,6 @@ use core::convert::TryFrom; use core::{fmt, iter}; use hashes::{sha256d, Hash}; -use io::Read as _; use crate::blockdata::{block, transaction}; use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt}; diff --git a/io/src/lib.rs b/io/src/lib.rs index ee531fc4..c25bd3b9 100644 --- a/io/src/lib.rs +++ b/io/src/lib.rs @@ -32,14 +32,67 @@ extern crate alloc; /// Standard I/O stream definitions which are API-equivalent to `std`'s `io` module. See /// [`std::io`] for more info. pub mod io { + use core::convert::TryInto; + #[cfg(all(not(feature = "std"), not(feature = "core2")))] compile_error!("At least one of std or core2 must be enabled"); #[cfg(feature = "std")] - pub use std::io::{Read, Cursor, Take, Error, ErrorKind, Result}; + pub use std::io::{Cursor, Error, ErrorKind, Result}; #[cfg(not(feature = "std"))] - pub use core2::io::{Read, Cursor, Take, Error, ErrorKind, Result}; + pub use core2::io::{Cursor, Error, ErrorKind, 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(Error::new(ErrorKind::UnexpectedEof, "")), + 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 { + ::read(self, buf) + } + } + + #[cfg(all(feature = "core2", not(feature = "std")))] + impl Read for R { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + ::read(self, buf) + } + } /// A generic trait describing an output stream. See [`std::io::Write`] for more info. pub trait Write {