From 90dc513458c16af021717181fc45e27d8071c39c Mon Sep 17 00:00:00 2001 From: John Nunley Date: Tue, 14 Nov 2023 20:06:19 -0800 Subject: [PATCH] bugfix: Use async-lock as the locking mechanism We can't use `std::sync::Mutex` without further unsafe code, and we can't use `simple-mutex` since it is unmaintained. Therefore we use the `async-lock` crate, since it has a good blocking mutex. Closes #12 Signed-off-by: John Nunley --- .github/workflows/ci.yml | 2 +- Cargo.toml | 3 ++- src/lib.rs | 46 ++++++++++++++++++++++++++-------------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6082200..bc49288 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: matrix: # When updating this, the reminder to update the minimum supported # Rust version in Cargo.toml. - rust: ['1.41.0'] + rust: ['1.59.0'] steps: - uses: actions/checkout@v4 - name: Install Rust diff --git a/Cargo.toml b/Cargo.toml index 58386f2..e2a88c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "async-dup" version = "1.2.3" authors = ["Stjepan Glavina "] edition = "2018" -rust-version = "1.41" +rust-version = "1.59" description = "Duplicate an async I/O handle" license = "Apache-2.0 OR MIT" repository = "https://github.com/smol-rs/async-dup" @@ -17,6 +17,7 @@ categories = ["asynchronous", "concurrency"] exclude = ["/.*"] [dependencies] +async-lock = "3.1.0" futures-io = "0.3.5" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 2b5db2f..2c6338a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,6 @@ use std::hash::{Hash, Hasher}; use std::io::{self, IoSlice, IoSliceMut, SeekFrom}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; -use std::sync::TryLockError; use std::task::{Context, Poll}; use futures_io::{AsyncRead, AsyncSeek, AsyncWrite}; @@ -227,7 +226,7 @@ where /// - `impl AsyncWrite for &Mutex where T: AsyncWrite + Unpin {}` /// - `impl AsyncSeek for Mutex where T: AsyncSeek + Unpin {}` /// - `impl AsyncSeek for &Mutex where T: AsyncSeek + Unpin {}` -pub struct Mutex(std::sync::Mutex); +pub struct Mutex(async_lock::Mutex); impl Mutex { /// Creates a new mutex. @@ -257,7 +256,7 @@ impl Mutex { /// assert_eq!(*guard, 10); /// ``` pub fn lock(&self) -> MutexGuard<'_, T> { - MutexGuard(self.0.lock().unwrap_or_else(|e| e.into_inner())) + MutexGuard(self.0.lock_blocking()) } /// Attempts to acquire the mutex. @@ -279,16 +278,7 @@ impl Mutex { /// # ; /// ``` pub fn try_lock(&self) -> Option> { - self.0 - .try_lock() - .map_or_else( - |e| match e { - TryLockError::Poisoned(e) => Some(e.into_inner()), - TryLockError::WouldBlock => None, - }, - Some, - ) - .map(MutexGuard) + self.0.try_lock().map(MutexGuard) } /// Consumes the mutex, returning the underlying data. @@ -302,7 +292,7 @@ impl Mutex { /// assert_eq!(mutex.into_inner(), 10); /// ``` pub fn into_inner(self) -> T { - self.0.into_inner().unwrap_or_else(|e| e.into_inner()) + self.0.into_inner() } /// Returns a mutable reference to the underlying data. @@ -320,7 +310,7 @@ impl Mutex { /// assert_eq!(*mutex.lock(), 10); /// ``` pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut().unwrap_or_else(|e| e.into_inner()) + self.0.get_mut() } } @@ -461,7 +451,7 @@ impl AsyncSeek for &Mutex { } /// A guard that releases the mutex when dropped. -pub struct MutexGuard<'a, T>(std::sync::MutexGuard<'a, T>); +pub struct MutexGuard<'a, T>(async_lock::MutexGuard<'a, T>); impl fmt::Debug for MutexGuard<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -488,3 +478,27 @@ impl DerefMut for MutexGuard<'_, T> { &mut self.0 } } + +#[cfg(test)] +mod tests { + use super::*; + + fn is_send(_: &T) {} + fn is_sync(_: &T) {} + + #[test] + fn is_send_sync() { + let arc = Arc::new(()); + let mutex = Mutex::new(()); + + is_send(&arc); + is_sync(&arc); + + is_send(&mutex); + is_sync(&mutex); + + let guard = mutex.lock(); + is_send(&guard); + is_sync(&guard); + } +}