2
0
Fork 0
mirror of https://git.asonix.dog/asonix/pict-rs synced 2024-12-22 19:31:35 +00:00
pict-rs/src/ingest/hasher.rs

112 lines
2.7 KiB
Rust
Raw Normal View History

2023-08-14 19:25:19 +00:00
use sha2::{digest::FixedOutputReset, Digest, Sha256};
2021-10-18 23:44:05 +00:00
use std::{
2022-09-24 22:18:53 +00:00
cell::RefCell,
2021-10-18 23:44:05 +00:00
pin::Pin,
2022-09-24 22:18:53 +00:00
rc::Rc,
2021-10-18 23:44:05 +00:00
task::{Context, Poll},
};
use tokio::io::{AsyncRead, ReadBuf};
2023-08-14 19:25:19 +00:00
pub(super) struct State {
hasher: Sha256,
size: u64,
}
2021-10-18 23:44:05 +00:00
pin_project_lite::pin_project! {
2023-08-14 19:25:19 +00:00
pub(crate) struct Hasher<I> {
2021-10-18 23:44:05 +00:00
#[pin]
inner: I,
2023-08-14 19:25:19 +00:00
state: Rc<RefCell<State>>,
2021-10-18 23:44:05 +00:00
}
}
2023-08-14 19:25:19 +00:00
impl<I> Hasher<I> {
pub(super) fn new(reader: I) -> Self {
2021-10-18 23:44:05 +00:00
Hasher {
inner: reader,
state: Rc::new(RefCell::new(State {
2023-08-14 19:25:19 +00:00
hasher: Sha256::new(),
size: 0,
})),
2021-10-18 23:44:05 +00:00
}
}
2023-08-14 19:25:19 +00:00
pub(super) fn state(&self) -> Rc<RefCell<State>> {
Rc::clone(&self.state)
2021-10-18 23:44:05 +00:00
}
}
2023-08-14 19:25:19 +00:00
impl State {
pub(super) fn finalize_reset(&mut self) -> ([u8; 32], u64) {
let arr = self.hasher.finalize_fixed_reset().into();
(arr, self.size)
}
}
impl<I> AsyncRead for Hasher<I>
2021-10-18 23:44:05 +00:00
where
I: AsyncRead,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
let this = self.as_mut().project();
let reader = this.inner;
let state = this.state;
2021-10-18 23:44:05 +00:00
let before_len = buf.filled().len();
let poll_res = reader.poll_read(cx, buf);
let after_len = buf.filled().len();
if after_len > before_len {
let mut guard = state.borrow_mut();
guard.hasher.update(&buf.filled()[before_len..after_len]);
guard.size += u64::try_from(after_len - before_len).expect("Size is reasonable");
2021-10-18 23:44:05 +00:00
}
poll_res
}
}
#[cfg(test)]
mod test {
use super::Hasher;
use sha2::{Digest, Sha256};
use std::io::Read;
2023-09-29 16:54:43 +00:00
macro_rules! test_async {
2021-10-18 23:44:05 +00:00
($fut:expr) => {
2023-09-29 16:54:43 +00:00
actix_web::rt::System::new()
.block_on(async move { crate::sync::spawn("tests", $fut).await.unwrap() })
2021-10-18 23:44:05 +00:00
};
}
#[test]
fn hasher_works() {
2023-09-29 16:54:43 +00:00
let (hash, size) = test_async!(async move {
2021-10-18 23:44:05 +00:00
let file1 = tokio::fs::File::open("./client-examples/earth.gif").await?;
2023-08-14 19:25:19 +00:00
let mut reader = Hasher::new(file1);
2021-10-18 23:44:05 +00:00
2022-09-25 14:09:05 +00:00
tokio::io::copy(&mut reader, &mut tokio::io::sink()).await?;
2021-10-18 23:44:05 +00:00
2023-08-14 19:25:19 +00:00
Ok(reader.state().borrow_mut().finalize_reset()) as std::io::Result<_>
2021-10-18 23:44:05 +00:00
})
.unwrap();
let mut file = std::fs::File::open("./client-examples/earth.gif").unwrap();
let mut vec = Vec::new();
file.read_to_end(&mut vec).unwrap();
2023-08-14 19:25:19 +00:00
let correct_size = vec.len() as u64;
2021-10-18 23:44:05 +00:00
let mut hasher = Sha256::new();
hasher.update(vec);
2023-08-14 19:25:19 +00:00
let correct_hash: [u8; 32] = hasher.finalize_reset().into();
2021-10-18 23:44:05 +00:00
assert_eq!(hash, correct_hash);
2023-08-14 19:25:19 +00:00
assert_eq!(size, correct_size);
2021-10-18 23:44:05 +00:00
}
}