use std::future::Future;
use std::io;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use digest::Digest;
use digest::Output;
use crate::AsyncByteInput;
use crate::DEFAULT_COPY_BUFFER_SIZE;
use crate::async_io::MAX_READY_OPERATIONS_PER_POLL;
use crate::traits::normalize_async_error;
use crate::traits::validate_read_count;
#[must_use = "futures do nothing unless polled"]
pub struct DigestAllFuture<'a, I, D>
where
I: AsyncByteInput + ?Sized,
D: Digest,
{
input: Pin<&'a mut I>,
hasher: Option<D>,
buffer: [u8; DEFAULT_COPY_BUFFER_SIZE],
}
impl<I, D> Unpin for DigestAllFuture<'_, I, D>
where
I: AsyncByteInput + ?Sized,
D: Digest,
{
}
impl<'a, I, D> DigestAllFuture<'a, I, D>
where
I: AsyncByteInput + ?Sized,
D: Digest,
{
#[inline]
pub fn new(input: Pin<&'a mut I>) -> Self {
Self {
input,
hasher: Some(D::new()),
buffer: [0; DEFAULT_COPY_BUFFER_SIZE],
}
}
}
impl<I, D> Future for DigestAllFuture<'_, I, D>
where
I: AsyncByteInput + ?Sized,
D: Digest,
{
type Output = io::Result<Output<D>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
assert!(this.hasher.is_some(), "DigestAllFuture polled after completion");
for _ in 0..MAX_READY_OPERATIONS_PER_POLL {
match this.input.as_mut().poll_read(cx, &mut this.buffer) {
Poll::Ready(Ok(0)) => {
let hasher = this.hasher.take().expect("digest state is present until completion");
return Poll::Ready(Ok(hasher.finalize()));
}
Poll::Ready(Ok(read)) => {
if let Err(error) = validate_read_count(read, this.buffer.len()) {
this.hasher = None;
return Poll::Ready(Err(error));
}
this.hasher
.as_mut()
.expect("digest state is present until completion")
.update(&this.buffer[..read]);
}
Poll::Ready(Err(error)) => {
this.hasher = None;
return Poll::Ready(Err(normalize_async_error(error)));
}
Poll::Pending => return Poll::Pending,
}
}
cx.waker().wake_by_ref();
Poll::Pending
}
}