Merge rust-bitcoin/rust-bitcoin#2240: Require `BufRead` instead of `Read`

263a8b3603 Require BufRead instead of Read (Tobin C. Harding)
32d68fd1fa io: Add BufRead trait (Tobin C. Harding)

Pull request description:

  Require `BufRead` instead of `Read` for consensus decode trait.

ACKs for top commit:
  Kixunil:
    ACK 263a8b3603
  apoelstra:
    ACK 263a8b3603

Tree-SHA512: 58ad04c7267f9091738463331473bd22b61e6b06a13aec38b3602a369cd8e571d7d1388fd81dd7a0a05f2e8d5a9c35270cd8a918a4fafe636506591ed06a4cb2
This commit is contained in:
Andrew Poelstra 2024-01-16 15:10:38 +00:00
commit 2073a40c50
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
23 changed files with 220 additions and 85 deletions

View File

@ -12,7 +12,7 @@ use std::error;
use hashes::{sha256, siphash24, Hash};
use internals::impl_array_newtype;
use io::{Read, Write};
use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
@ -81,7 +81,7 @@ impl Encodable for PrefilledTransaction {
impl Decodable for PrefilledTransaction {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let idx = VarInt::consensus_decode(r)?.0;
let idx = u16::try_from(idx)
.map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
@ -137,7 +137,7 @@ impl Encodable for ShortId {
impl Decodable for ShortId {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
Ok(ShortId(Decodable::consensus_decode(r)?))
}
}
@ -273,7 +273,7 @@ impl Encodable for BlockTransactionsRequest {
}
impl Decodable for BlockTransactionsRequest {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(BlockTransactionsRequest {
block_hash: BlockHash::consensus_decode(r)?,
indexes: {

View File

@ -43,7 +43,7 @@ use core::fmt::{self, Display, Formatter};
use hashes::{sha256d, siphash24, Hash};
use internals::write_err;
use io::{Read, Write};
use io::{BufRead, Write};
use crate::blockdata::block::{Block, BlockHash};
use crate::blockdata::script::Script;
@ -245,7 +245,7 @@ impl BlockFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
R: Read + ?Sized,
R: BufRead + ?Sized,
{
self.reader.match_any(reader, query)
}
@ -255,7 +255,7 @@ impl BlockFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
R: Read + ?Sized,
R: BufRead + ?Sized,
{
self.reader.match_all(reader, query)
}
@ -278,7 +278,7 @@ impl GcsFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
R: Read + ?Sized,
R: BufRead + ?Sized,
{
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp]
@ -321,7 +321,7 @@ impl GcsFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
R: Read + ?Sized,
R: BufRead + ?Sized,
{
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp]
@ -447,7 +447,7 @@ impl GcsFilter {
/// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
where
R: Read + ?Sized,
R: BufRead + ?Sized,
{
let mut q = 0u64;
while reader.read(1)? == 1 {
@ -470,7 +470,7 @@ pub struct BitStreamReader<'a, R: ?Sized> {
reader: &'a mut R,
}
impl<'a, R: Read + ?Sized> BitStreamReader<'a, R> {
impl<'a, R: BufRead + ?Sized> BitStreamReader<'a, R> {
/// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
BitStreamReader { buffer: [0u8], reader, offset: 8 }

View File

@ -11,7 +11,7 @@
use core::fmt;
use hashes::{sha256d, Hash, HashEngine};
use io::{Read, Write};
use io::{BufRead, Write};
use super::Weight;
use crate::blockdata::script;
@ -207,7 +207,7 @@ impl Encodable for Version {
}
impl Decodable for Version {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version)
}
}

View File

@ -10,7 +10,7 @@ use core::cmp::{Ordering, PartialOrd};
use core::{fmt, mem};
use internals::write_err;
use io::{Read, Write};
use io::{BufRead, Write};
#[cfg(all(test, mutate))]
use mutagen::mutate;
@ -345,7 +345,7 @@ impl Encodable for LockTime {
impl Decodable for LockTime {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(LockTime::from_consensus)
}
}

View File

@ -66,7 +66,7 @@ use core::fmt;
use core::ops::{Deref, DerefMut};
use hashes::{hash160, sha256};
use io::{Read, Write};
use io::{BufRead, Write};
#[cfg(feature = "serde")]
use serde;
@ -594,7 +594,7 @@ impl Encodable for ScriptBuf {
impl Decodable for ScriptBuf {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))

View File

@ -16,7 +16,7 @@ use core::{cmp, fmt, str};
use hashes::{self, sha256d, Hash};
use internals::write_err;
use io::{Read, Write};
use io::{BufRead, Write};
use super::Weight;
use crate::blockdata::locktime::absolute::{self, Height, Time};
@ -1030,7 +1030,7 @@ impl Encodable for Version {
}
impl Decodable for Version {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version)
}
}
@ -1048,7 +1048,7 @@ impl Encodable for OutPoint {
}
}
impl Decodable for OutPoint {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(OutPoint {
txid: Decodable::consensus_decode(r)?,
vout: Decodable::consensus_decode(r)?,
@ -1067,7 +1067,7 @@ impl Encodable for TxIn {
}
impl Decodable for TxIn {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
Ok(TxIn {
@ -1086,7 +1086,7 @@ impl Encodable for Sequence {
}
impl Decodable for Sequence {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Sequence)
}
}
@ -1116,7 +1116,7 @@ impl Encodable for Transaction {
}
impl Decodable for Transaction {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let version = Version::consensus_decode_from_finite_reader(r)?;

View File

@ -8,7 +8,7 @@
use core::fmt;
use core::ops::Index;
use io::{Read, Write};
use io::{BufRead, Write};
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
use crate::consensus::{Decodable, Encodable, WriteExt};
@ -124,7 +124,7 @@ pub struct Iter<'a> {
}
impl Decodable for Witness {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let witness_elements = VarInt::consensus_decode(r)?.0 as usize;
// Minimum size of witness element is 1 byte, so if the count is
// greater than MAX_VEC_SIZE we must return an error.

View File

@ -20,7 +20,7 @@ use core::{fmt, mem, u32};
use hashes::{sha256, sha256d, Hash};
use internals::write_err;
use io::{Cursor, Read, Write};
use io::{Cursor, BufRead, Read, Write};
use crate::bip152::{PrefilledTransaction, ShortId};
use crate::bip158::{FilterHash, FilterHeader};
@ -301,7 +301,7 @@ pub trait Decodable: Sized {
/// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
/// performance hit.
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
reader: &mut R,
) -> Result<Self, Error> {
// This method is always strictly less general than, `consensus_decode`, so it's safe and
@ -319,7 +319,7 @@ pub trait Decodable: Sized {
/// for types that override [`Self::consensus_decode_from_finite_reader`]
/// instead.
#[inline]
fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, Error> {
Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64))
}
}
@ -357,7 +357,7 @@ macro_rules! impl_int_encodable {
($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
impl Decodable for $ty {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
ReadExt::$meth_dec(r)
}
}
@ -440,7 +440,7 @@ impl Encodable for VarInt {
impl Decodable for VarInt {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let n = ReadExt::read_u8(r)?;
match n {
0xFF => {
@ -482,7 +482,7 @@ impl Encodable for bool {
impl Decodable for bool {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<bool, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<bool, Error> {
ReadExt::read_bool(r)
}
}
@ -499,7 +499,7 @@ impl Encodable for String {
impl Decodable for String {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<String, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<String, Error> {
String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
}
@ -517,7 +517,7 @@ impl Encodable for Cow<'static, str> {
impl Decodable for Cow<'static, str> {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
.map(Cow::Owned)
@ -539,7 +539,7 @@ macro_rules! impl_array {
impl Decodable for [u8; $size] {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut ret = [0; $size];
r.read_slice(&mut ret)?;
Ok(ret)
@ -560,7 +560,7 @@ impl_array!(33);
impl Decodable for [u16; 8] {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut res = [0; 8];
for item in &mut res {
*item = Decodable::consensus_decode(r)?;
@ -595,7 +595,7 @@ macro_rules! impl_vec {
impl Decodable for Vec<$type> {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, Error> {
let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
@ -685,7 +685,7 @@ impl Encodable for Vec<u8> {
impl Decodable for Vec<u8> {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let len = VarInt::consensus_decode(r)?.0 as usize;
// most real-world vec of bytes data, wouldn't be larger than 128KiB
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
@ -702,7 +702,7 @@ impl Encodable for Box<[u8]> {
impl Decodable for Box<[u8]> {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
<Vec<u8>>::consensus_decode_from_finite_reader(r).map(From::from)
}
}
@ -727,7 +727,7 @@ impl Encodable for CheckedData {
impl Decodable for CheckedData {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let len = u32::consensus_decode_from_finite_reader(r)? as usize;
let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
@ -787,7 +787,7 @@ macro_rules! tuple_encode {
impl<$($x: Decodable),*> Decodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(($({let $x = Decodable::consensus_decode(r)?; $x }),*))
}
}
@ -809,7 +809,7 @@ impl Encodable for sha256d::Hash {
}
impl Decodable for sha256d::Hash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}
@ -821,7 +821,7 @@ impl Encodable for sha256::Hash {
}
impl Decodable for sha256::Hash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}
@ -833,7 +833,7 @@ impl Encodable for TapLeafHash {
}
impl Decodable for TapLeafHash {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}

View File

@ -12,7 +12,7 @@
use core::fmt;
use core::marker::PhantomData;
use io::{Read, Write};
use io::{BufRead, Read, Write};
use serde::de::{SeqAccess, Unexpected, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserializer, Serializer};
@ -420,11 +420,12 @@ where
struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> {
iterator: core::iter::Fuse<I>,
buf: Option<u8>,
error: Option<E>,
}
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } }
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), buf: None, error: None } }
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
let result = T::consensus_decode(&mut self);
@ -443,8 +444,17 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
}
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
let mut count = 0;
if buf.is_empty() {
return Ok(0);
}
if let Some(first) = self.buf.take() {
buf[0] = first;
buf = &mut buf[1..];
count += 1;
}
for (dst, src) in buf.iter_mut().zip(&mut self.iterator) {
match src {
Ok(byte) => *dst = byte,
@ -460,6 +470,34 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> Read for IterReader<E, I>
}
}
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> BufRead for IterReader<E, I> {
fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
// matching on reference rather than using `ref` confuses borrow checker
if let Some(ref byte) = self.buf {
Ok(core::slice::from_ref(byte))
} else {
match self.iterator.next() {
Some(Ok(byte)) => {
self.buf = Some(byte);
Ok(core::slice::from_ref(self.buf.as_ref().expect("we've just filled it")))
},
Some(Err(error)) => {
self.error = Some(error);
Err(io::ErrorKind::Other.into())
},
None => Ok(&[]),
}
}
}
fn consume(&mut self, len: usize) {
debug_assert!(len <= 1);
if len > 0 {
self.buf = None;
}
}
}
/// Helper for `#[serde(with = "")]`.
///
/// To (de)serialize a field using consensus encoding you can write e.g.:

View File

@ -22,7 +22,7 @@ macro_rules! impl_consensus_encoding {
impl $crate::consensus::Decodable for $thing {
#[inline]
fn consensus_decode_from_finite_reader<R: $crate::io::Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: $crate::io::BufRead + ?Sized>(
r: &mut R,
) -> Result<$thing, $crate::consensus::encode::Error> {
Ok($thing {
@ -31,7 +31,7 @@ macro_rules! impl_consensus_encoding {
}
#[inline]
fn consensus_decode<R: $crate::io::Read + ?Sized>(
fn consensus_decode<R: $crate::io::BufRead + ?Sized>(
r: &mut R,
) -> Result<$thing, $crate::consensus::encode::Error> {
let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
@ -202,7 +202,7 @@ macro_rules! impl_hashencode {
}
impl $crate::consensus::Decodable for $hashtype {
fn consensus_decode<R: $crate::io::Read + ?Sized>(r: &mut R) -> Result<Self, $crate::consensus::encode::Error> {
fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> Result<Self, $crate::consensus::encode::Error> {
use $crate::hashes::Hash;
Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
}

View File

@ -172,7 +172,7 @@ pub mod amount {
//! We refer to the documentation on the types for more information.
use crate::consensus::{encode, Decodable, Encodable};
use crate::io;
use crate::io::{BufRead, Write};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@ -184,14 +184,14 @@ pub mod amount {
impl Decodable for Amount {
#[inline]
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Amount::from_sat(Decodable::consensus_decode(r)?))
}
}
impl Encodable for Amount {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.to_sat().consensus_encode(w)
}
}

View File

@ -41,7 +41,7 @@
use core::fmt;
use hashes::Hash;
use io::{Read, Write};
use io::{BufRead, Write};
use self::MerkleBlockError::*;
use crate::blockdata::block::{self, Block, TxMerkleNode};
@ -151,7 +151,7 @@ impl Encodable for MerkleBlock {
}
impl Decodable for MerkleBlock {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(MerkleBlock {
header: Decodable::consensus_decode(r)?,
txn: Decodable::consensus_decode(r)?,
@ -452,7 +452,7 @@ impl Encodable for PartialMerkleTree {
}
impl Decodable for PartialMerkleTree {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let num_transactions: u32 = Decodable::consensus_decode(r)?;

View File

@ -9,7 +9,7 @@
use core::{fmt, iter};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use io::{Read, Write};
use io::{BufRead, Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
use crate::p2p::ServiceFlags;
@ -75,7 +75,7 @@ impl Encodable for Address {
impl Decodable for Address {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Address {
services: Decodable::consensus_decode(r)?,
address: read_be_address(r)?,
@ -167,7 +167,7 @@ impl Encodable for AddrV2 {
}
impl Decodable for AddrV2 {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let network_id = u8::consensus_decode(r)?;
let len = VarInt::consensus_decode(r)?.0;
if len > 512 {
@ -285,7 +285,7 @@ impl Encodable for AddrV2Message {
}
impl Decodable for AddrV2Message {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(AddrV2Message {
time: Decodable::consensus_decode(r)?,
services: ServiceFlags::from(VarInt::consensus_decode(r)?.0),

View File

@ -9,7 +9,7 @@
use core::{fmt, iter};
use hashes::{sha256d, Hash};
use io::{Read, Write};
use io::{BufRead, Write};
use crate::blockdata::{block, transaction};
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
@ -110,7 +110,7 @@ impl Encodable for CommandString {
impl Decodable for CommandString {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
if u > 0 {
@ -407,7 +407,7 @@ struct HeaderDeserializationWrapper(Vec<block::Header>);
impl Decodable for HeaderDeserializationWrapper {
#[inline]
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let len = VarInt::consensus_decode(r)?.0;
@ -426,13 +426,13 @@ impl Decodable for HeaderDeserializationWrapper {
}
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
}
}
impl Decodable for RawNetworkMessage {
fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let magic = Decodable::consensus_decode_from_finite_reader(r)?;
@ -442,7 +442,7 @@ impl Decodable for RawNetworkMessage {
let raw_payload = checked_data.into_data();
let payload_len = raw_payload.len() as u32;
let mut mem_d = io::Cursor::new(raw_payload);
let mut mem_d = raw_payload.as_slice();
let payload = match &cmd.0[..] {
"version" =>
NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
@ -525,13 +525,13 @@ impl Decodable for RawNetworkMessage {
"addrv2" =>
NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
"sendaddrv2" => NetworkMessage::SendAddrV2,
_ => NetworkMessage::Unknown { command: cmd, payload: mem_d.into_inner() },
_ => NetworkMessage::Unknown { command: cmd, payload: raw_payload },
};
Ok(RawNetworkMessage { magic, payload, payload_len, checksum })
}
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
}
}

View File

@ -7,7 +7,7 @@
//!
use hashes::{sha256d, Hash as _};
use io::{Read, Write};
use io::{BufRead, Write};
use crate::blockdata::block::BlockHash;
use crate::blockdata::transaction::{Txid, Wtxid};
@ -83,7 +83,7 @@ impl Encodable for Inventory {
impl Decodable for Inventory {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let inv_type: u32 = Decodable::consensus_decode(r)?;
Ok(match inv_type {
0 => Inventory::Error,

View File

@ -5,7 +5,7 @@
//! This module describes BIP37 Connection Bloom filtering network messages.
//!
use io::{Read, Write};
use io::{BufRead, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
@ -48,7 +48,7 @@ impl Encodable for BloomFlags {
}
impl Decodable for BloomFlags {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? {
0 => BloomFlags::None,
1 => BloomFlags::All,

View File

@ -7,7 +7,7 @@
//!
use hashes::sha256d;
use io::{Read, Write};
use io::{BufRead, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
@ -117,7 +117,7 @@ impl Encodable for RejectReason {
}
impl Decodable for RejectReason {
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? {
0x01 => RejectReason::Malformed,
0x10 => RejectReason::Invalid,

View File

@ -25,7 +25,7 @@ use core::{fmt, ops};
use hex::FromHex;
use internals::{debug_from_display, write_err};
use io::{Read, Write};
use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::prelude::{Borrow, BorrowMut, String, ToOwned};
@ -198,7 +198,7 @@ impl Encodable for ServiceFlags {
impl Decodable for ServiceFlags {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
}
}
@ -290,7 +290,7 @@ impl Encodable for Magic {
}
impl Decodable for Magic {
fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
Ok(Magic(Decodable::consensus_decode(reader)?))
}
}

View File

@ -9,7 +9,7 @@
use core::fmt::{self, LowerHex, UpperHex};
use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub};
use io::{Read, Write};
use io::{BufRead, Write};
#[cfg(all(test, mutate))]
use mutagen::mutate;
@ -301,7 +301,7 @@ impl Encodable for CompactTarget {
impl Decodable for CompactTarget {
#[inline]
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(CompactTarget)
}
}

View File

@ -56,7 +56,7 @@ macro_rules! impl_psbtmap_deserialize {
macro_rules! impl_psbtmap_decoding {
($thing:ty) => {
impl $thing {
pub(crate) fn decode<R: $crate::io::Read + ?Sized>(
pub(crate) fn decode<R: $crate::io::BufRead + ?Sized>(
r: &mut R,
) -> Result<Self, $crate::psbt::Error> {
let mut rv: Self = core::default::Default::default();

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0
use io::{Cursor, Read};
use io::{Cursor, BufRead, Read};
use crate::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpub};
use crate::blockdata::transaction::Transaction;
@ -70,7 +70,7 @@ impl Map for Psbt {
}
impl Psbt {
pub(crate) fn decode_global<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
pub(crate) fn decode_global<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut r = r.take(MAX_VEC_SIZE as u64);
let mut tx: Option<Transaction> = None;
let mut version: Option<u32> = None;

View File

@ -8,7 +8,7 @@
use core::fmt;
use io::{Read, Write};
use io::{BufRead, Read, Write};
use super::serialize::{Deserialize, Serialize};
use crate::consensus::encode::{
@ -74,7 +74,7 @@ impl fmt::Display for Key {
}
impl Key {
pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;
if byte_size == 0 {
@ -137,7 +137,7 @@ impl Deserialize for Pair {
}
impl Pair {
pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
}
}
@ -159,7 +159,7 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?);
let key = read_to_end(r)?;

View File

@ -47,6 +47,19 @@ pub trait Read {
fn take(&mut self, limit: u64) -> Take<Self> { Take { reader: self, remaining: limit } }
}
/// A trait describing an input stream that uses an internal buffer when reading.
pub trait BufRead: Read {
/// Returns data read from this reader, filling the internal buffer if needed.
fn fill_buf(&mut self) -> Result<&[u8]>;
/// Marks the buffered data up to amount as consumed.
///
/// # Panics
///
/// May panic if `amount` is greater than amount of data read by `fill_buf`.
fn consume(&mut self, amount: usize);
}
pub struct Take<'a, R: Read + ?Sized> {
reader: &'a mut R,
remaining: u64,
@ -62,6 +75,30 @@ impl<'a, R: Read + ?Sized> Read for Take<'a, R> {
}
}
// Impl copied from Rust stdlib.
impl<'a, R: BufRead + ?Sized> BufRead for Take<'a, R> {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> {
// Don't call into inner reader at all at EOF because it may still block
if self.remaining == 0 {
return Ok(&[]);
}
let buf = self.reader.fill_buf()?;
// Cast length to a u64 instead of casting `remaining` to a `usize`
// (in case `remaining > u32::MAX` and we are on a 32 bit machine).
let cap = cmp::min(buf.len() as u64, self.remaining) as usize;
Ok(&buf[..cap])
}
#[inline]
fn consume(&mut self, amount: usize) {
assert!(amount as u64 <= self.remaining);
self.remaining -= amount as u64;
self.reader.consume(amount);
}
}
#[cfg(feature = "std")]
impl<R: std::io::Read> Read for R {
#[inline]
@ -70,6 +107,15 @@ impl<R: std::io::Read> Read for R {
}
}
#[cfg(feature = "std")]
impl<R: std::io::BufRead + Read + ?Sized> BufRead for R {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> { Ok(std::io::BufRead::fill_buf(self)?) }
#[inline]
fn consume(&mut self, amount: usize) { std::io::BufRead::consume(self, amount) }
}
#[cfg(not(feature = "std"))]
impl Read for &[u8] {
#[inline]
@ -81,6 +127,16 @@ impl Read for &[u8] {
}
}
#[cfg(not(feature = "std"))]
impl BufRead for &[u8] {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> { Ok(self) }
// This panics if amount is out of bounds, same as the std version.
#[inline]
fn consume(&mut self, amount: usize) { *self = &self[amount..] }
}
pub struct Cursor<T> {
inner: T,
pos: u64,
@ -110,6 +166,20 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
}
}
impl<T: AsRef<[u8]>> BufRead for Cursor<T> {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> {
let inner: &[u8] = self.inner.as_ref();
Ok(&inner[self.pos as usize..])
}
#[inline]
fn consume(&mut self, amount: usize) {
assert!(amount <= self.inner.as_ref().len());
self.pos += amount as u64;
}
}
/// A generic trait describing an output stream. See [`std::io::Write`] for more info.
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
@ -197,3 +267,30 @@ impl std::io::Write for Sink {
/// Returns a sink to which all writes succeed. See [`std::io::sink`] for more info.
#[inline]
pub fn sink() -> Sink { Sink }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buf_read_fill_and_consume_slice() {
let data = [0_u8, 1, 2];
let mut slice = &data[..];
let fill = BufRead::fill_buf(&mut slice).unwrap();
assert_eq!(fill.len(), 3);
assert_eq!(fill, &[0_u8, 1, 2]);
slice.consume(2);
let fill = BufRead::fill_buf(&mut slice).unwrap();
assert_eq!(fill.len(), 1);
assert_eq!(fill, &[2_u8]);
slice.consume(1);
// checks we can attempt to read from a now-empty reader.
let fill = BufRead::fill_buf(&mut slice).unwrap();
assert_eq!(fill.len(), 0);
assert_eq!(fill, &[]);
}
}