|
@@ -285,6 +285,26 @@ struct SendRefInner<'a, T, N: Notify> {
|
|
|
_notify: NotifyRx<'a, N>,
|
|
|
}
|
|
|
|
|
|
+struct RecvRefInner<'a, T, N: Notify + Unpin> {
|
|
|
+ // /!\ LOAD BEARING STRUCT DROP ORDER /!\
|
|
|
+ //
|
|
|
+ // The `Ref` field *must* be dropped before the `NotifyTx` field, or else
|
|
|
+ // loom tests will fail. This ensures that the mutable access to the slot is
|
|
|
+ // considered to have ended *before* the receiver thread/task is notified.
|
|
|
+ //
|
|
|
+ // The alternatives to a load-bearing drop order would be:
|
|
|
+ // (a) put one field inside an `Option` so it can be dropped before the
|
|
|
+ // other (not great, as it adds a little extra overhead even outside
|
|
|
+ // of Loom tests),
|
|
|
+ // (b) use `core::mem::ManuallyDrop` (also not great, requires additional
|
|
|
+ // unsafe code that in this case we can avoid)
|
|
|
+ //
|
|
|
+ // So, given that, relying on struct field drop order seemed like the least
|
|
|
+ // bad option here. Just don't reorder these fields. :)
|
|
|
+ slot: Ref<'a, T>,
|
|
|
+ _notify: crate::mpsc::NotifyTx<'a, N>,
|
|
|
+}
|
|
|
+
|
|
|
struct NotifyRx<'a, N: Notify>(&'a WaitCell<N>);
|
|
|
struct NotifyTx<'a, N: Notify + Unpin>(&'a WaitQueue<N>);
|
|
|
|
|
@@ -356,8 +376,14 @@ where
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn try_recv_ref<'a, T>(&'a self, slots: &'a [Slot<T>]) -> Result<Ref<'a, T>, TryRecvError> {
|
|
|
- self.core.pop_ref(slots)
|
|
|
+ fn try_recv_ref<'a, T>(
|
|
|
+ &'a self,
|
|
|
+ slots: &'a [Slot<T>],
|
|
|
+ ) -> Result<RecvRefInner<'a, T, N>, TryRecvError> {
|
|
|
+ self.core.pop_ref(slots).map(|slot| RecvRefInner {
|
|
|
+ _notify: NotifyTx(&self.tx_wait),
|
|
|
+ slot,
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
fn try_recv<T, R>(&self, slots: &[Slot<T>], recycle: &R) -> Result<T, TryRecvError>
|
|
@@ -484,6 +510,52 @@ impl<T: fmt::Write, N: Notify> fmt::Write for SendRefInner<'_, T, N> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// === impl RecvRefInner ===
|
|
|
+
|
|
|
+impl<T, N: Notify + Unpin> core::ops::Deref for RecvRefInner<'_, T, N> {
|
|
|
+ type Target = T;
|
|
|
+ #[inline]
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
+ self.slot.deref()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T, N: Notify + Unpin> core::ops::DerefMut for RecvRefInner<'_, T, N> {
|
|
|
+ #[inline]
|
|
|
+ fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
+ self.slot.deref_mut()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: fmt::Debug, N: Notify + Unpin> fmt::Debug for RecvRefInner<'_, T, N> {
|
|
|
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
+ self.slot.fmt(f)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: fmt::Display, N: Notify + Unpin> fmt::Display for RecvRefInner<'_, T, N> {
|
|
|
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
+ self.slot.fmt(f)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: fmt::Write, N: Notify + Unpin> fmt::Write for RecvRefInner<'_, T, N> {
|
|
|
+ #[inline]
|
|
|
+ fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
|
+ self.slot.write_str(s)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ fn write_char(&mut self, c: char) -> fmt::Result {
|
|
|
+ self.slot.write_char(c)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ fn write_fmt(&mut self, f: fmt::Arguments<'_>) -> fmt::Result {
|
|
|
+ self.slot.write_fmt(f)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl<N: Notify> Drop for NotifyRx<'_, N> {
|
|
|
#[inline]
|
|
|
fn drop(&mut self) {
|
|
@@ -500,10 +572,10 @@ impl<N: Notify + Unpin> Drop for NotifyTx<'_, N> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-macro_rules! impl_send_ref {
|
|
|
- ($(#[$m:meta])* pub struct $name:ident<$notify:ty>;) => {
|
|
|
+macro_rules! impl_ref_inner {
|
|
|
+ ($(#[$m:meta])*, $inner:ident, $name:ident, $notify:ty) => {
|
|
|
$(#[$m])*
|
|
|
- pub struct $name<'sender, T>(SendRefInner<'sender, T, $notify>);
|
|
|
+ pub struct $name<'a, T>($inner<'a, T, $notify>);
|
|
|
|
|
|
impl<T> core::ops::Deref for $name<'_, T> {
|
|
|
type Target = T;
|
|
@@ -552,73 +624,15 @@ macro_rules! impl_send_ref {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-macro_rules! impl_recv_ref {
|
|
|
+macro_rules! impl_send_ref {
|
|
|
($(#[$m:meta])* pub struct $name:ident<$notify:ty>;) => {
|
|
|
- $(#[$m])*
|
|
|
- pub struct $name<'recv, T> {
|
|
|
- // /!\ LOAD BEARING STRUCT DROP ORDER /!\
|
|
|
- //
|
|
|
- // The `Ref` field *must* be dropped before the `NotifyTx` field, or else
|
|
|
- // loom tests will fail. This ensures that the mutable access to the slot is
|
|
|
- // considered to have ended *before* the receiver thread/task is notified.
|
|
|
- //
|
|
|
- // The alternatives to a load-bearing drop order would be:
|
|
|
- // (a) put one field inside an `Option` so it can be dropped before the
|
|
|
- // other (not great, as it adds a little extra overhead even outside
|
|
|
- // of Loom tests),
|
|
|
- // (b) use `core::mem::ManuallyDrop` (also not great, requires additional
|
|
|
- // unsafe code that in this case we can avoid)
|
|
|
- //
|
|
|
- // So, given that, relying on struct field drop order seemed like the least
|
|
|
- // bad option here. Just don't reorder these fields. :)
|
|
|
- slot: Ref<'recv, T>,
|
|
|
- _notify: crate::mpsc::NotifyTx<'recv, $notify>,
|
|
|
- }
|
|
|
-
|
|
|
- impl<T> core::ops::Deref for $name<'_, T> {
|
|
|
- type Target = T;
|
|
|
-
|
|
|
- #[inline]
|
|
|
- fn deref(&self) -> &Self::Target {
|
|
|
- self.slot.deref()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl<T> core::ops::DerefMut for $name<'_, T> {
|
|
|
- #[inline]
|
|
|
- fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
- self.slot.deref_mut()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl<T: fmt::Debug> fmt::Debug for $name<'_, T> {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
- self.slot.fmt(f)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl<T: fmt::Display> fmt::Display for $name<'_, T> {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
- self.slot.fmt(f)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl<T: fmt::Write> fmt::Write for $name<'_, T> {
|
|
|
- #[inline]
|
|
|
- fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
|
- self.slot.write_str(s)
|
|
|
- }
|
|
|
-
|
|
|
- #[inline]
|
|
|
- fn write_char(&mut self, c: char) -> fmt::Result {
|
|
|
- self.slot.write_char(c)
|
|
|
- }
|
|
|
+ impl_ref_inner!($(#[$m])*, SendRefInner, $name, $notify);
|
|
|
+ };
|
|
|
+}
|
|
|
|
|
|
- #[inline]
|
|
|
- fn write_fmt(&mut self, f: fmt::Arguments<'_>) -> fmt::Result {
|
|
|
- self.slot.write_fmt(f)
|
|
|
- }
|
|
|
- }
|
|
|
+macro_rules! impl_recv_ref {
|
|
|
+ ($(#[$m:meta])* pub struct $name:ident<$notify:ty>;) => {
|
|
|
+ impl_ref_inner!($(#[$m])*, RecvRefInner, $name, $notify);
|
|
|
};
|
|
|
}
|
|
|
|