synchrony/
bilock.rs

1/// Multithreaded BiLock
2pub mod sync {
3    super::impl_bilock!(sync);
4
5    unsafe impl<T: Send> Send for Inner<T> {}
6    unsafe impl<T: Send> Sync for Inner<T> {}
7
8    impl<T: Send> crate::AssertMt for BiLock<T> {}
9    impl<T: Send> crate::AssertMt for BiLockAcquire<'_, T> {}
10    impl<T: Send> crate::AssertMt for BiLockGuard<'_, T> {}
11}
12
13/// Singlethreaded BiLock
14pub mod unsync {
15    super::impl_bilock!(unsync);
16}
17
18macro_rules! impl_bilock {
19    ($sync:ident) => {
20        use std::{
21            cell::UnsafeCell,
22            fmt::Debug,
23            future::Future,
24            ops::{Deref, DerefMut},
25            pin::Pin,
26            task::{Context, Poll},
27        };
28
29        use crate::$sync::{flag::Flag, shared::Shared, waker_slot::WakerSlot};
30
31        /// A lock shared by two parties.
32        pub struct BiLock<T>(Shared<Inner<T>>);
33
34        impl<T> Debug for BiLock<T>
35        where
36            T: Debug,
37        {
38            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39                f.debug_struct("BiLock")
40                    .field("locked", &self.0.locked.get())
41                    .finish()
42            }
43        }
44
45        impl<T> BiLock<T> {
46            /// Creates a new `BiLock` wrapping the supplied data, returning two
47            /// handles to it.
48            pub fn new(data: T) -> (Self, Self) {
49                let inner = Shared::new(Inner {
50                    data: UnsafeCell::new(data),
51                    waiter: WakerSlot::new(),
52                    locked: Flag::new(false),
53                });
54                (Self(inner.clone()), Self(inner))
55            }
56
57            /// Acquires the lock, returning a future that resolves to a guard
58            pub fn lock(&self) -> BiLockAcquire<'_, T> {
59                BiLockAcquire { inner: &self.0 }
60            }
61
62            /// Attempts to join two `BiLock`s into their original data.
63            pub fn try_join(self, other: Self) -> Option<T> {
64                if Shared::ptr_eq(&self.0, &other.0) {
65                    drop(other);
66                    let value = Shared::try_unwrap(self.0)
67                        .map_err(|_| ())
68                        .expect("BiLock is still shared")
69                        .data
70                        .into_inner();
71                    Some(value)
72                } else {
73                    None
74                }
75            }
76
77            /// Joins two `BiLock`s into their original data.
78            #[allow(unused)]
79            pub fn join(self, other: Self) -> T {
80                if let Some(value) = self.try_join(other) {
81                    value
82                } else {
83                    #[cold]
84                    fn panic_unrelated() -> ! {
85                        panic!("Unrelated `BiLock` passed to `BiLock::join`.")
86                    }
87
88                    panic_unrelated()
89                }
90            }
91        }
92
93        /// Future for acquiring a [`BiLock`]
94        pub struct BiLockAcquire<'a, T> {
95            inner: &'a Inner<T>,
96        }
97
98        impl<'a, T> Future for BiLockAcquire<'a, T> {
99            type Output = BiLockGuard<'a, T>;
100
101            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
102                let this = self.get_mut();
103                if this.inner.locked.swap(true) {
104                    this.inner.waiter.register(cx.waker());
105                    Poll::Pending
106                } else {
107                    Poll::Ready(BiLockGuard { inner: this.inner })
108                }
109            }
110        }
111
112        struct Inner<T: ?Sized> {
113            locked: Flag,
114            waiter: WakerSlot,
115            data: UnsafeCell<T>,
116        }
117
118        /// An RAII guard returned by a successful call to [`BiLock::lock`]
119        pub struct BiLockGuard<'a, T: ?Sized> {
120            inner: &'a Inner<T>,
121        }
122
123        impl<T: ?Sized> Deref for BiLockGuard<'_, T> {
124            type Target = T;
125
126            fn deref(&self) -> &Self::Target {
127                unsafe { &*self.inner.data.get() }
128            }
129        }
130
131        impl<T: ?Sized> DerefMut for BiLockGuard<'_, T> {
132            fn deref_mut(&mut self) -> &mut Self::Target {
133                unsafe { &mut *self.inner.data.get() }
134            }
135        }
136
137        impl<T: ?Sized> Drop for BiLockGuard<'_, T> {
138            fn drop(&mut self) {
139                self.inner.locked.swap(false);
140                self.inner.waiter.wake();
141            }
142        }
143    };
144}
145
146use impl_bilock;