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

Support for async chksum calculation #1

Merged
merged 2 commits into from
Oct 6, 2024
Merged
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
8 changes: 8 additions & 0 deletions .cargo/README.md
Original file line number Diff line number Diff line change
@@ -25,6 +25,14 @@ Alternatively, you can use the [`cargo add`](https://doc.rust-lang.org/cargo/com
cargo add chksum-writer
```

## Features

### Asynchronous Runtime

* `async-runtime-tokio`: Enables async interface for Tokio runtime.

By default, neither of these features is enabled.

## Examples

For implementation-specific examples, refer to the documentation of the following crates:
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -5,10 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Added async support for Tokio runtime.
- Added `doc_auto_cfg` feature.

## [0.0.0] - 2023-12-21

### Added

- Initial release.

[Unreleased]: https://github.com/chksum-rs/writer/compare/v0.0.0...HEAD
[0.0.0]: https://github.com/chksum-rs/writer/releases/tag/v0.0.0
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -16,4 +16,11 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
chksum-core = "0.0.0"
chksum-core = "0.1.0"
tokio = { version = "1.37.0", features = ["io-util"], optional = true }

[features]
default = []

# async runtimes
async-runtime-tokio = ["chksum-core/async-runtime-tokio", "tokio"]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -25,6 +25,14 @@ Alternatively, you can use the [`cargo add`](https://doc.rust-lang.org/cargo/com
cargo add chksum-writer
```

## Features

### Asynchronous Runtime

* `async-runtime-tokio`: Enables async interface for Tokio runtime.

By default, neither of these features is enabled.

## Examples

For implementation-specific examples, refer to the documentation of the following crates:
105 changes: 105 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,14 @@
//! cargo add chksum-writer
//! ```
//!
//! # Features
//!
//! ## Asynchronous Runtime
//!
//! * `async-runtime-tokio`: Enables async interface for Tokio runtime.
//!
//! By default, neither of these features is enabled.
//!
//! # Usage
//!
//! ```rust,ignore
@@ -50,11 +58,18 @@
//!
//! This crate is licensed under the MIT License.

#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![forbid(unsafe_code)]

use std::io::{self, Write};
#[cfg(feature = "async-runtime-tokio")]
use std::pin::{pin, Pin};
#[cfg(feature = "async-runtime-tokio")]
use std::task::{Context, Poll};

use chksum_core::Hash;
#[cfg(feature = "async-runtime-tokio")]
use tokio::io::{AsyncWrite, AsyncWriteExt};

/// Creates new [`Writer`].
pub fn new<H>(inner: impl Write) -> Writer<impl Write, H>
@@ -72,6 +87,24 @@ where
Writer::with_hash(inner, hash)
}

#[cfg(feature = "async-runtime-tokio")]
/// Creates new [`AsyncWriter`].
pub fn async_new<H>(inner: impl AsyncWrite) -> AsyncWriter<impl AsyncWrite, H>
where
H: Hash,
{
AsyncWriter::new(inner)
}

#[cfg(feature = "async-runtime-tokio")]
/// Creates new [`AsyncWriter`] with provided hash.
pub fn async_with_hash<H>(inner: impl AsyncWrite, hash: H) -> AsyncWriter<impl AsyncWrite, H>
where
H: Hash,
{
AsyncWriter::with_hash(inner, hash)
}

/// Wraps a writer and calculates the hash digest on the fly.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Writer<W, H>
@@ -129,3 +162,75 @@ where
self.inner.flush()
}
}

/// Wraps a reader and calculates the hash digest on the fly.
#[cfg(feature = "async-runtime-tokio")]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AsyncWriter<W, H>
where
W: AsyncWriteExt,
H: Hash,
{
inner: W,
hash: H,
}

#[cfg(feature = "async-runtime-tokio")]
impl<W, H> AsyncWriter<W, H>
where
W: AsyncWriteExt,
H: Hash,
{
/// Creates new [`AsyncWriter`].
pub fn new(inner: W) -> Self {
let hash = H::default();
Self::with_hash(inner, hash)
}

/// Creates new [`AsyncWriter`] with provided hash.
#[must_use]
pub const fn with_hash(inner: W, hash: H) -> Self {
Self { inner, hash }
}

/// Unwraps this [`AsyncWriter`], returning the underlying writer.
#[must_use]
pub fn into_inner(self) -> W {
let Self { inner, .. } = self;
inner
}

/// Returns calculated hash digest.
#[must_use]
pub fn digest(&self) -> H::Digest {
self.hash.digest()
}
}

#[cfg(feature = "async-runtime-tokio")]
impl<W, H> AsyncWrite for AsyncWriter<W, H>
where
W: AsyncWrite + Unpin,
H: Hash + Unpin,
{
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, io::Error>> {
let Self { inner, hash } = self.get_mut();
match pin!(inner).poll_write(cx, buf) {
Poll::Ready(Ok(n)) => {
hash.update(&buf[..n]);
Poll::Ready(Ok(n))
},
poll => poll,
}
}

fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
let Self { inner, .. } = self.get_mut();
pin!(inner).poll_flush(cx)
}

fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
let Self { inner, .. } = self.get_mut();
pin!(inner).poll_shutdown(cx)
}
}