Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move modules to own files #23

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/async_digest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::{CalculatorSelector, TrySha256Digest};
use bytes::BytesMut;
use std::io;

/// sha256 digest file
///
/// # Examples
///
/// ```rust
/// use sha256::{try_async_digest};
/// use std::path::Path;
/// let input = Path::new("./foo.file");
/// tokio_test::block_on(async{
/// let val = try_async_digest(input).await.unwrap();
/// assert_eq!(val,"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1")
/// });
///
/// ```
pub async fn try_async_digest<D: TrySha256Digest>(input: D) -> Result<String, D::Error> {
input.async_digest().await
}

/// sha256 digest file
///
/// # Examples
///
/// ```rust
/// use sha256::{try_async_openssl_digest};
/// use std::path::Path;
/// let input = Path::new("./foo.file");
/// tokio_test::block_on(async{
/// let val = try_async_openssl_digest(input).await.unwrap();
/// assert_eq!(val,"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1")
/// });
/// ```
#[cfg(feature = "native_openssl")]
pub async fn try_async_openssl_digest<D: TrySha256Digest>(
input: D,
) -> Result<String, D::Error> {
input.async_openssl_digest().await
}

#[async_trait::async_trait]
pub trait AsyncCalculatorInput {
async fn read_inner(&mut self, buf: &mut BytesMut) -> io::Result<usize>;
}

pub async fn async_calc<I, S>(mut input: I, mut selector: S) -> io::Result<String>
where
I: AsyncCalculatorInput,
S: CalculatorSelector,
{
let mut buf = BytesMut::with_capacity(1024);
loop {
buf.clear();
let len = input.read_inner(&mut buf).await?;
if len == 0 {
break;
}
selector.update_inner(&buf[0..len]);
}
let hash = selector.finish_inner();
Ok(hex::encode(hash))
}

#[async_trait::async_trait]
impl<R> AsyncCalculatorInput for tokio::io::BufReader<R>
where
R: tokio::io::AsyncRead + Unpin + Send,
{
async fn read_inner(&mut self, buf: &mut BytesMut) -> io::Result<usize> {
use tokio::io::AsyncReadExt;

self.read_buf(buf).await
}
}
252 changes: 7 additions & 245 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ use std::io;
use std::io::{BufReader, Read};
use std::path::Path;

#[cfg(feature = "async")]
pub mod async_digest;
#[cfg(test)]
mod tests;
#[cfg(feature = "native_openssl")]
mod openssl_sha256;

/// sha256 digest string
///
/// # Examples
Expand Down Expand Up @@ -266,248 +273,3 @@ where
let hash = selector.finish_inner();
Ok(hex::encode(hash))
}

#[cfg(feature = "async")]
pub mod async_digest {
use crate::{CalculatorSelector, TrySha256Digest};
use bytes::BytesMut;
use std::io;

/// sha256 digest file
///
/// # Examples
///
/// ```rust
/// use sha256::{try_async_digest};
/// use std::path::Path;
/// let input = Path::new("./foo.file");
/// tokio_test::block_on(async{
/// let val = try_async_digest(input).await.unwrap();
/// assert_eq!(val,"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1")
/// });
///
/// ```
pub async fn try_async_digest<D: TrySha256Digest>(input: D) -> Result<String, D::Error> {
input.async_digest().await
}

/// sha256 digest file
///
/// # Examples
///
/// ```rust
/// use sha256::{try_async_openssl_digest};
/// use std::path::Path;
/// let input = Path::new("./foo.file");
/// tokio_test::block_on(async{
/// let val = try_async_openssl_digest(input).await.unwrap();
/// assert_eq!(val,"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1")
/// });
/// ```
#[cfg(feature = "native_openssl")]
pub async fn try_async_openssl_digest<D: TrySha256Digest>(
input: D,
) -> Result<String, D::Error> {
input.async_openssl_digest().await
}

#[async_trait::async_trait]
pub trait AsyncCalculatorInput {
async fn read_inner(&mut self, buf: &mut BytesMut) -> io::Result<usize>;
}

pub async fn async_calc<I, S>(mut input: I, mut selector: S) -> io::Result<String>
where
I: AsyncCalculatorInput,
S: CalculatorSelector,
{
let mut buf = BytesMut::with_capacity(1024);
loop {
buf.clear();
let len = input.read_inner(&mut buf).await?;
if len == 0 {
break;
}
selector.update_inner(&buf[0..len]);
}
let hash = selector.finish_inner();
Ok(hex::encode(hash))
}

#[async_trait::async_trait]
impl<R> AsyncCalculatorInput for tokio::io::BufReader<R>
where
R: tokio::io::AsyncRead + Unpin + Send,
{
async fn read_inner(&mut self, buf: &mut BytesMut) -> io::Result<usize> {
use tokio::io::AsyncReadExt;

self.read_buf(buf).await
}
}
}

#[cfg(feature = "native_openssl")]
mod openssl_sha256 {
use crate::CalculatorSelector;

pub type OpenSslSha256 = openssl::sha::Sha256;

impl CalculatorSelector for OpenSslSha256 {
type FinishType = [u8; 32];

fn update_inner(&mut self, data: &[u8]) {
self.update(data)
}

fn finish_inner(self) -> Self::FinishType {
self.finish()
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[cfg(feature = "native_openssl")]
#[test]
fn test_openssl() {
let input = Path::new("./foo.file");
let f = fs::File::open(input).unwrap();
let reader = BufReader::new(f);
let sha = openssl::sha::Sha256::new();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
calc(reader, sha).unwrap()
);
}

#[test]
fn test_sha256() {
let input = Path::new("./foo.file");
let f = fs::File::open(input).unwrap();
let reader = BufReader::new(f);
let sha = Sha256::new();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
calc(reader, sha).unwrap()
);
}

#[cfg(all(feature = "async", feature = "native_openssl"))]
#[tokio::test]
async fn test_async_openssl() {
let input = Path::new("./foo.file");
let f = tokio::fs::File::open(input).await.unwrap();
let reader = tokio::io::BufReader::new(f);
let sha = openssl::sha::Sha256::new();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
async_calc(reader, sha).await.unwrap()
);
}

#[cfg(feature = "async")]
#[tokio::test]
async fn test_async() {
let input = Path::new("./foo.file");
let f = tokio::fs::File::open(input).await.unwrap();
let reader = tokio::io::BufReader::new(f);
let sha = Sha256::new();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
async_calc(reader, sha).await.unwrap()
);
}

#[cfg(all(feature = "async", feature = "native_openssl"))]
#[tokio::test]
async fn test_try_async_openssl_digest() {
let hash = try_async_openssl_digest("./foo.file").await.unwrap();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
hash
);
}

#[cfg(feature = "async")]
#[tokio::test]
async fn test_try_async_digest() {
let hash = try_async_digest("./foo.file").await.unwrap();
assert_eq!(
"433855b7d2b96c23a6f60e70c655eb4305e8806b682a9596a200642f947259b1",
hash
);
}

#[cfg(feature = "async")]
#[tokio::test]
async fn test_async_parity() {
let bytes = (0..0x1000).map(|v| (v % 256) as u8).collect::<Vec<_>>();
let val = digest(&bytes);

let async_res = {
let bytes = &bytes;
// We want to force Poll::Pending on reads during async_calc, which may break parity
// between sync and async hashing.
let (client, mut server) = tokio::io::duplex(64);
let reader = tokio::io::BufReader::new(client);
let sha = Sha256::new();

use tokio::io::AsyncWriteExt;
tokio::join! {
async_calc(reader, sha),
async move {
server.write_all(&bytes[..]).await.unwrap();
core::mem::drop(server);
}
}
.0
.unwrap()
};

let sync_res = {
let reader = BufReader::new(&*bytes);
let sha = Sha256::new();
calc(reader, sha).unwrap()
};
assert_eq!(val, async_res);
assert_eq!(async_res, sync_res);
}

#[cfg(all(feature = "async", feature = "native_openssl"))]
#[tokio::test]
async fn test_async_parity_openssl() {
let bytes = (0..0x1000).map(|v| (v % 256) as u8).collect::<Vec<_>>();
let val = digest(&bytes);

let async_res = {
let bytes = &bytes;
// We want to force Poll::Pending on reads during async_calc, which may break parity
// between sync and async hashing.
let (client, mut server) = tokio::io::duplex(64);
let reader = tokio::io::BufReader::new(client);
let sha = OpenSslSha256::new();

use tokio::io::AsyncWriteExt;
tokio::join! {
async_calc(reader, sha),
async move {
server.write_all(&bytes[..]).await.unwrap();
core::mem::drop(server);
}
}
.0
.unwrap()
};

let sync_res = {
let reader = BufReader::new(&*bytes);
let sha = OpenSslSha256::new();
calc(reader, sha).unwrap()
};
assert_eq!(val, async_res);
assert_eq!(async_res, sync_res);
}
}
15 changes: 15 additions & 0 deletions src/openssl_sha256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::CalculatorSelector;

pub type OpenSslSha256 = openssl::sha::Sha256;

impl CalculatorSelector for OpenSslSha256 {
type FinishType = [u8; 32];

fn update_inner(&mut self, data: &[u8]) {
self.update(data)
}

fn finish_inner(self) -> Self::FinishType {
self.finish()
}
}
Loading
Loading