summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2024-03-10 21:27:01 -0400
committerMica White <botahamec@outlook.com>2024-03-10 21:27:01 -0400
commit5eaa4fe1d3bfcda696122ba3d6b4914dba19ef96 (patch)
tree611014ce92c7a52873019b6d52d2468f6083a9ab
parent815c0adedd6207eb406c67ea09c2634f304f8adf (diff)
implement Debug
-rw-r--r--README.md2
-rw-r--r--src/mutex/mutex.rs26
-rw-r--r--src/rwlock/rwlock.rs26
3 files changed, 49 insertions, 5 deletions
diff --git a/README.md b/README.md
index dc926ac..54e0be1 100644
--- a/README.md
+++ b/README.md
@@ -91,7 +91,7 @@ Are the ergonomics here any good? This is completely uncharted territory. Maybe
I want to try to get this working without the standard library. There are a few problems with this though. For instance, this crate uses `thread_local` to allow other threads to have their own keys. Also, the only practical type of mutex that would work is a spinlock. Although, more could be implemented using the `RawMutex` trait. The `LockCollection` requires memory allocation at this time in order to check for duplicate locks.
-It'd be interesting to add some methods such as `lock_clone` or `lock_swap`. This would still require a thread key, in case the mutex is already locked. The only way this could be done without a thread key is with a `&mut Mutex<T>`, but we already have `get_mut`. A special lock that looks like `Cell` but implements `Sync` could be shared without a thread key, because the lock would be dropped immediately (solving non-preemptive allocation). It might make some common operations easier.
+It'd be interesting to add some methods such as `lock_clone` or `lock_swap`. This would still require a thread key, in case the mutex is already locked. The only way this could be done without a thread key is with a `&mut Mutex<T>`, but we already have `get_mut`. A `try_lock_clone` or `try_lock_swap` might not need a `ThreadKey` though. A special lock that looks like `Cell` but implements `Sync` could be shared without a thread key, because the lock would be dropped immediately (preventing non-preemptive allocation). It might make some common operations easier.
There might be some use in trying to prevent circular wait. There could be a special type that only allows the locking mutexes in a specific order. This would still require a thread key so that nobody tries to unlock multiple lock sequences at the same time. The biggest problem is that `LockSequence::lock_next` would need to return the same value each time, which is not very flexible. Most use cases for this are solved already by using `LockCollection<OwnedLockable>`.
diff --git a/src/mutex/mutex.rs b/src/mutex/mutex.rs
index ce93cae..52a4848 100644
--- a/src/mutex/mutex.rs
+++ b/src/mutex/mutex.rs
@@ -26,9 +26,31 @@ impl<T, R: RawMutex> Mutex<T, R> {
}
}
-impl<T: ?Sized, R> Debug for Mutex<T, R> {
+impl<T: ?Sized + Default, R: RawMutex> Default for Mutex<T, R> {
+ fn default() -> Self {
+ Self::new(T::default())
+ }
+}
+
+impl<T: ?Sized + Debug, R: RawMutex> Debug for Mutex<T, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("Mutex<{}>", std::any::type_name::<T>()))
+ // safety: this is just a try lock, and the value is dropped
+ // immediately after, so there's no risk of blocking ourselves
+ // or any other threads
+ if let Some(value) = unsafe { self.try_lock_no_key() } {
+ f.debug_struct("Mutex").field("data", &&*value).finish()
+ } else {
+ struct LockedPlaceholder;
+ impl Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str("<locked>")
+ }
+ }
+
+ f.debug_struct("Mutex")
+ .field("data", &LockedPlaceholder)
+ .finish()
+ }
}
}
diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs
index 946f67e..c1d1792 100644
--- a/src/rwlock/rwlock.rs
+++ b/src/rwlock/rwlock.rs
@@ -17,9 +17,31 @@ impl<T, R: RawRwLock> RwLock<T, R> {
}
}
-impl<T: ?Sized, R> Debug for RwLock<T, R> {
+impl<T: ?Sized + Default, R: RawRwLock> Default for RwLock<T, R> {
+ fn default() -> Self {
+ Self::new(T::default())
+ }
+}
+
+impl<T: ?Sized + Debug, R: RawRwLock> Debug for RwLock<T, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("RwLock<{}>", std::any::type_name::<T>()))
+ // safety: this is just a try lock, and the value is dropped
+ // immediately after, so there's no risk of blocking ourselves
+ // or any other threads
+ if let Some(value) = unsafe { self.try_read_no_key() } {
+ f.debug_struct("RwLock").field("data", &&*value).finish()
+ } else {
+ struct LockedPlaceholder;
+ impl Debug for LockedPlaceholder {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str("<locked>")
+ }
+ }
+
+ f.debug_struct("RwLock")
+ .field("data", &LockedPlaceholder)
+ .finish()
+ }
}
}