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 <dev@notgull.net>
This commit is contained in:
John Nunley 2023-11-14 20:06:19 -08:00 committed by GitHub
parent f2b822a618
commit 90dc513458
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 18 deletions

View File

@ -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

View File

@ -6,7 +6,7 @@ name = "async-dup"
version = "1.2.3"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
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]

View File

@ -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<T> AsyncWrite for &Mutex<T> where T: AsyncWrite + Unpin {}`
/// - `impl<T> AsyncSeek for Mutex<T> where T: AsyncSeek + Unpin {}`
/// - `impl<T> AsyncSeek for &Mutex<T> where T: AsyncSeek + Unpin {}`
pub struct Mutex<T>(std::sync::Mutex<T>);
pub struct Mutex<T>(async_lock::Mutex<T>);
impl<T> Mutex<T> {
/// Creates a new mutex.
@ -257,7 +256,7 @@ impl<T> Mutex<T> {
/// 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<T> Mutex<T> {
/// # ;
/// ```
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
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<T> Mutex<T> {
/// 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<T> Mutex<T> {
/// 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<T: AsyncSeek + Unpin> AsyncSeek for &Mutex<T> {
}
/// 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<T: fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -488,3 +478,27 @@ impl<T> DerefMut for MutexGuard<'_, T> {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_send<T: Send>(_: &T) {}
fn is_sync<T: 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);
}
}