io: Use function in place of GeneralHashExt

We would like to remove the `GeneralHash` trait but we want to keep the
`hash_reader` functionality.

Add a stand alone function (when `hashes` is enabled) `hash_reader`.
Remove the extension trait.
This commit is contained in:
Tobin C. Harding 2025-02-20 13:29:05 +11:00
parent 2b6ef31469
commit 791501eabc
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 20 additions and 33 deletions

View File

@ -10,9 +10,11 @@
use hashes::hmac::HmacEngine; use hashes::hmac::HmacEngine;
use hashes::{ use hashes::{
hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24, hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
GeneralHash, HashEngine as _, HashEngine as _,
}; };
use crate::BufRead;
macro_rules! impl_write { macro_rules! impl_write {
($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => { ($ty: ty, $write_fn: expr, $flush_fn: expr $(, $bounded_ty: ident : $bounds: path),*) => {
// `std::io::Write` is implemented in `bitcoin_hashes` because of the orphan rule. // `std::io::Write` is implemented in `bitcoin_hashes` because of the orphan rule.
@ -132,39 +134,24 @@ impl_write!(
); );
/// Hashes data from a reader. /// Hashes data from a reader.
/// pub fn hash_reader<T>(reader: &mut impl BufRead) -> Result<T::Hash, crate::Error>
/// Adds functionality to a [`hashes::GeneralHash`] type to support hashing data read from a where
/// buffered reader. T: hashes::HashEngine + Default,
pub trait GeneralHashExt: GeneralHash + sealed::Sealed { {
/// Hashes the entire contents of the `reader`. let mut engine = T::default();
fn hash_reader<R: crate::BufRead>(reader: &mut R) -> Result<Self, crate::Error> loop {
where let bytes = reader.fill_buf()?;
Self::Engine: Default,
{
let mut engine = Self::engine(); // This calls `Self::Engine::default()`.
loop {
let bytes = reader.fill_buf()?;
let read = bytes.len(); let read = bytes.len();
// Empty slice means EOF. // Empty slice means EOF.
if read == 0 { if read == 0 {
break; break;
}
engine.input(bytes);
reader.consume(read);
} }
Ok(Self::from_engine(engine))
engine.input(bytes);
reader.consume(read);
} }
} Ok(engine.finalize())
impl<T: GeneralHash> GeneralHashExt for T {}
mod sealed {
/// Used to seal the `GeneralHashExt` trait.
pub trait Sealed {}
impl<T: hashes::GeneralHash> Sealed for T {}
} }
#[cfg(test)] #[cfg(test)]
@ -308,7 +295,7 @@ mod tests {
assert_eq!(got, $want); assert_eq!(got, $want);
let mut reader = Cursor::new(DATA); let mut reader = Cursor::new(DATA);
let hash_from_reader = $module::Hash::hash_reader(&mut reader).unwrap(); let hash_from_reader = $crate::hash_reader::<$module::HashEngine>(&mut reader).unwrap();
assert_eq!(hash_from_reader, hash) assert_eq!(hash_from_reader, hash)
} }
)* )*

View File

@ -46,7 +46,7 @@ pub use bridge::{FromStd, ToStd};
#[rustfmt::skip] // Keep public re-exports separate. #[rustfmt::skip] // Keep public re-exports separate.
pub use self::error::{Error, ErrorKind}; pub use self::error::{Error, ErrorKind};
#[cfg(feature = "hashes")] #[cfg(feature = "hashes")]
pub use self::hash::GeneralHashExt; pub use self::hash::hash_reader;
/// Result type returned by functions in this crate. /// Result type returned by functions in this crate.
pub type Result<T> = core::result::Result<T, Error>; pub type Result<T> = core::result::Result<T, Error>;