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

Adding Send + Sync trait bounds #13

Closed
wants to merge 12 commits into from
Closed
7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "clamav-client"
version = "1.0.0"
version = "2.0.0"
edition = "2021"
rust-version = "1.56.0"
authors = ["Thorsten Blum <[email protected]>"]
Expand All @@ -17,7 +17,6 @@ exclude = ["clamd", ".github"]
tokio = { version = "1.34.0", default-features = false, features = ["fs", "io-util", "net"], optional = true }
tokio-stream = { version = "0.1.14", default-features = false, optional = true }
async-std = { version = "1.12.0", optional = true }
async-trait = { version = "0.1.77", optional = true }
bytes = { version = "1", optional = true }

[dev-dependencies]
Expand All @@ -26,9 +25,9 @@ tokio-util = { version = "0.7.10", features = ["io"] }
async-std = { version = "1.12.0", features = ["attributes"] }

[features]
tokio = ["dep:async-trait", "dep:tokio"]
tokio = ["dep:tokio"]
tokio-stream = ["tokio", "dep:tokio-stream", "dep:bytes"]
async-std = ["dep:async-trait", "dep:async-std", "dep:bytes"]
async-std = ["dep:async-std", "dep:bytes"]

[package.metadata.docs.rs]
features = ["tokio", "tokio-stream", "async-std"]
26 changes: 13 additions & 13 deletions src/async_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use async_std::{
path::Path,
stream::{Stream, StreamExt},
};
use async_trait::async_trait;

#[cfg(unix)]
use async_std::os::unix::net::UnixStream;
Expand Down Expand Up @@ -95,45 +94,46 @@ async fn _scan_stream<

/// Use a TCP connection to communicate with a ClamAV server
#[derive(Copy, Clone)]
pub struct Tcp<A: ToSocketAddrs> {
pub struct Tcp<A: ToSocketAddrs + Send + Sync> {
/// The address (host and port) of the ClamAV server
pub host_address: A,
}

/// Use a Unix socket connection to communicate with a ClamAV server
#[derive(Copy, Clone)]
#[cfg(unix)]
pub struct Socket<P: AsRef<Path>> {
pub struct Socket<P: AsRef<Path> + Send + Sync> {
/// The socket file path of the ClamAV server
pub socket_path: P,
}

/// The communication protocol to use
#[async_trait(?Send)]
pub trait TransportProtocol {
/// Bidirectional stream
type Stream: ReadExt + WriteExt + Unpin;

/// Converts the protocol instance into the corresponding stream
async fn connect(&self) -> io::Result<Self::Stream>;
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send;
}

#[async_trait(?Send)]
impl<A: ToSocketAddrs> TransportProtocol for Tcp<A> {
impl<A> TransportProtocol for Tcp<A>
where
A: ToSocketAddrs + Send + Sync,
<A as async_std::net::ToSocketAddrs>::Iter: std::marker::Send,
toblux marked this conversation as resolved.
Show resolved Hide resolved
{
type Stream = TcpStream;

async fn connect(&self) -> io::Result<Self::Stream> {
TcpStream::connect(&self.host_address).await
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send {
TcpStream::connect(&self.host_address)
}
}

#[async_trait(?Send)]
#[cfg(unix)]
impl<P: AsRef<Path>> TransportProtocol for Socket<P> {
impl<P: AsRef<Path> + Send + Sync> TransportProtocol for Socket<P> {
type Stream = UnixStream;

async fn connect(&self) -> io::Result<Self::Stream> {
UnixStream::connect(&self.socket_path).await
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send {
UnixStream::connect(&self.socket_path)
}
}

Expand Down
22 changes: 9 additions & 13 deletions src/tokio.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use async_trait::async_trait;
use std::path::Path;
use tokio::{
fs::File,
Expand Down Expand Up @@ -98,45 +97,42 @@ async fn _scan_stream<

/// Use a TCP connection to communicate with a ClamAV server
#[derive(Copy, Clone)]
pub struct Tcp<A: ToSocketAddrs> {
pub struct Tcp<A: ToSocketAddrs + Send + Sync> {
/// The address (host and port) of the ClamAV server
pub host_address: A,
}

/// Use a Unix socket connection to communicate with a ClamAV server
#[derive(Copy, Clone)]
#[cfg(unix)]
pub struct Socket<P: AsRef<Path>> {
pub struct Socket<P: AsRef<Path> + Send + Sync> {
/// The socket file path of the ClamAV server
pub socket_path: P,
}

/// The communication protocol to use
#[async_trait(?Send)]
pub trait TransportProtocol {
/// Bidirectional stream
type Stream: AsyncRead + AsyncWrite + Unpin;

/// Converts the protocol instance into the corresponding stream
async fn connect(&self) -> io::Result<Self::Stream>;
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send;
}

#[async_trait(?Send)]
impl<A: ToSocketAddrs> TransportProtocol for Tcp<A> {
impl<A: ToSocketAddrs + Send + Sync> TransportProtocol for Tcp<A> {
type Stream = TcpStream;

async fn connect(&self) -> io::Result<Self::Stream> {
TcpStream::connect(&self.host_address).await
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send {
TcpStream::connect(&self.host_address)
}
}

#[async_trait(?Send)]
#[cfg(unix)]
impl<P: AsRef<Path>> TransportProtocol for Socket<P> {
impl<P: AsRef<Path> + Send + Sync> TransportProtocol for Socket<P> {
type Stream = UnixStream;

async fn connect(&self) -> io::Result<Self::Stream> {
UnixStream::connect(&self.socket_path).await
fn connect(&self) -> impl std::future::Future<Output = io::Result<Self::Stream>> + Send {
UnixStream::connect(&self.socket_path)
}
}

Expand Down
28 changes: 28 additions & 0 deletions tests/clamav_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,3 +758,31 @@ mod async_std_stream_tests {

#[cfg(feature = "async-std")]
mod async_std_util;

// Checks if the library can be used with work stealing async runtimes like tokio
mod test_future_is_send {
fn is_send<T: Send>(_t: T) {}

#[cfg(feature = "tokio")]
#[tokio::test]
async fn test_tokio_future_is_send() {
use clamav_client::tokio::{self, scan_buffer, Tcp};
is_send(scan_buffer(&[], Tcp { host_address: "" }, None));

#[cfg(unix)]
is_send(scan_buffer(&[], tokio::Socket { socket_path: "" }, None));
}

#[cfg(feature = "async-std")]
#[async_std::test]
async fn test_async_std_future_is_send() {
use clamav_client::async_std::{self, scan_buffer, Tcp};
is_send(scan_buffer(&[], Tcp { host_address: "" }, None));
#[cfg(unix)]
is_send(scan_buffer(
&[],
async_std::Socket { socket_path: "" },
None,
));
}
}
Loading