From 53cfb8b7f2933dd74e2075335db4f8ce2c8fd1c7 Mon Sep 17 00:00:00 2001 From: Ryo Onodera Date: Fri, 8 Dec 2023 13:37:18 +0900 Subject: [PATCH] Add disconnected flavor which immediately fails --- crossbeam-channel/src/channel.rs | 30 +++++ crossbeam-channel/src/flavors/disconnected.rs | 108 ++++++++++++++++++ crossbeam-channel/src/flavors/mod.rs | 2 + crossbeam-channel/src/lib.rs | 2 +- crossbeam-channel/src/select.rs | 2 + 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 crossbeam-channel/src/flavors/disconnected.rs diff --git a/crossbeam-channel/src/channel.rs b/crossbeam-channel/src/channel.rs index bcbb09afc..fdce709f5 100644 --- a/crossbeam-channel/src/channel.rs +++ b/crossbeam-channel/src/channel.rs @@ -274,6 +274,13 @@ pub fn never() -> Receiver { } } +/// Creates a receiver that is disconnected always. +pub fn disconnected() -> Receiver { + Receiver { + flavor: ReceiverFlavor::Disconnected(flavors::disconnected::Channel::new()), + } +} + /// Creates a receiver that delivers messages periodically. /// /// The channel is bounded with capacity of 1 and never gets disconnected. Messages will be @@ -731,6 +738,9 @@ enum ReceiverFlavor { /// The never flavor. Never(flavors::never::Channel), + + /// The disconnected flavor. + Disconnected(flavors::disconnected::Channel), } unsafe impl Send for Receiver {} @@ -784,6 +794,7 @@ impl Receiver { } } ReceiverFlavor::Never(chan) => chan.try_recv(), + ReceiverFlavor::Disconnected(chan) => chan.try_recv(), } } @@ -839,6 +850,7 @@ impl Receiver { } } ReceiverFlavor::Never(chan) => chan.recv(None), + ReceiverFlavor::Disconnected(chan) => chan.recv(None), } .map_err(|_| RecvError) } @@ -950,6 +962,7 @@ impl Receiver { } } ReceiverFlavor::Never(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::Disconnected(chan) => chan.recv(Some(deadline)), } } @@ -976,6 +989,7 @@ impl Receiver { ReceiverFlavor::At(chan) => chan.is_empty(), ReceiverFlavor::Tick(chan) => chan.is_empty(), ReceiverFlavor::Never(chan) => chan.is_empty(), + ReceiverFlavor::Disconnected(chan) => chan.is_empty(), } } @@ -1002,6 +1016,7 @@ impl Receiver { ReceiverFlavor::At(chan) => chan.is_full(), ReceiverFlavor::Tick(chan) => chan.is_full(), ReceiverFlavor::Never(chan) => chan.is_full(), + ReceiverFlavor::Disconnected(chan) => chan.is_full(), } } @@ -1027,6 +1042,7 @@ impl Receiver { ReceiverFlavor::At(chan) => chan.len(), ReceiverFlavor::Tick(chan) => chan.len(), ReceiverFlavor::Never(chan) => chan.len(), + ReceiverFlavor::Disconnected(chan) => chan.len(), } } @@ -1054,6 +1070,7 @@ impl Receiver { ReceiverFlavor::At(chan) => chan.capacity(), ReceiverFlavor::Tick(chan) => chan.capacity(), ReceiverFlavor::Never(chan) => chan.capacity(), + ReceiverFlavor::Disconnected(chan) => chan.capacity(), } } @@ -1165,6 +1182,7 @@ impl Drop for Receiver { ReceiverFlavor::At(_) => {} ReceiverFlavor::Tick(_) => {} ReceiverFlavor::Never(_) => {} + ReceiverFlavor::Disconnected(_) => {} } } } @@ -1179,6 +1197,9 @@ impl Clone for Receiver { ReceiverFlavor::At(chan) => ReceiverFlavor::At(chan.clone()), ReceiverFlavor::Tick(chan) => ReceiverFlavor::Tick(chan.clone()), ReceiverFlavor::Never(_) => ReceiverFlavor::Never(flavors::never::Channel::new()), + ReceiverFlavor::Disconnected(_) => { + ReceiverFlavor::Disconnected(flavors::disconnected::Channel::new()) + } }; Self { flavor } @@ -1428,6 +1449,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.try_select(token), ReceiverFlavor::Tick(chan) => chan.try_select(token), ReceiverFlavor::Never(chan) => chan.try_select(token), + ReceiverFlavor::Disconnected(chan) => chan.try_select(token), } } @@ -1439,6 +1461,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.deadline(), ReceiverFlavor::Tick(chan) => chan.deadline(), ReceiverFlavor::Never(chan) => chan.deadline(), + ReceiverFlavor::Disconnected(chan) => chan.deadline(), } } @@ -1450,6 +1473,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.register(oper, cx), ReceiverFlavor::Tick(chan) => chan.register(oper, cx), ReceiverFlavor::Never(chan) => chan.register(oper, cx), + ReceiverFlavor::Disconnected(chan) => chan.register(oper, cx), } } @@ -1461,6 +1485,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.unregister(oper), ReceiverFlavor::Tick(chan) => chan.unregister(oper), ReceiverFlavor::Never(chan) => chan.unregister(oper), + ReceiverFlavor::Disconnected(chan) => chan.unregister(oper), } } @@ -1472,6 +1497,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.accept(token, cx), ReceiverFlavor::Tick(chan) => chan.accept(token, cx), ReceiverFlavor::Never(chan) => chan.accept(token, cx), + ReceiverFlavor::Disconnected(chan) => chan.accept(token, cx), } } @@ -1483,6 +1509,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.is_ready(), ReceiverFlavor::Tick(chan) => chan.is_ready(), ReceiverFlavor::Never(chan) => chan.is_ready(), + ReceiverFlavor::Disconnected(chan) => chan.is_ready(), } } @@ -1494,6 +1521,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.watch(oper, cx), ReceiverFlavor::Tick(chan) => chan.watch(oper, cx), ReceiverFlavor::Never(chan) => chan.watch(oper, cx), + ReceiverFlavor::Disconnected(chan) => chan.watch(oper, cx), } } @@ -1505,6 +1533,7 @@ impl SelectHandle for Receiver { ReceiverFlavor::At(chan) => chan.unwatch(oper), ReceiverFlavor::Tick(chan) => chan.unwatch(oper), ReceiverFlavor::Never(chan) => chan.unwatch(oper), + ReceiverFlavor::Disconnected(chan) => chan.unwatch(oper), } } } @@ -1531,5 +1560,6 @@ pub(crate) unsafe fn read(r: &Receiver, token: &mut Token) -> Result, Result>(&chan.read(token)) } ReceiverFlavor::Never(chan) => chan.read(token), + ReceiverFlavor::Disconnected(chan) => chan.read(token), } } diff --git a/crossbeam-channel/src/flavors/disconnected.rs b/crossbeam-channel/src/flavors/disconnected.rs new file mode 100644 index 000000000..86b1d6682 --- /dev/null +++ b/crossbeam-channel/src/flavors/disconnected.rs @@ -0,0 +1,108 @@ +//! Channel that is always disconnected. +//! +//! Messages cannot be sent into this kind of channel. + +use std::marker::PhantomData; +use std::time::Instant; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, TryRecvError}; +use crate::select::{Operation, SelectHandle, Token}; + +/// This flavor doesn't need a token. +pub(crate) type DisconnectedToken = (); + +/// Channel that always delivers messages. +pub(crate) struct Channel { + _marker: PhantomData, +} + +impl Channel { + /// Creates a channel that always delivers messages. + #[inline] + pub(crate) fn new() -> Self { + Channel { + _marker: PhantomData, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub(crate) fn try_recv(&self) -> Result { + Err(TryRecvError::Disconnected) + } + + /// Receives a message from the channel. + #[inline] + pub(crate) fn recv(&self, _deadline: Option) -> Result { + Err(RecvTimeoutError::Disconnected) + } + + /// Reads a message from the channel. + #[inline] + pub(crate) unsafe fn read(&self, _token: &mut Token) -> Result { + Err(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub(crate) fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + #[inline] + pub(crate) fn is_full(&self) -> bool { + true + } + + /// Returns the number of messages in the channel. + #[inline] + pub(crate) fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + #[inline] + pub(crate) fn capacity(&self) -> Option { + Some(0) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, _token: &mut Token) -> bool { + true + } + + #[inline] + fn deadline(&self) -> Option { + None + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + true + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/crossbeam-channel/src/flavors/mod.rs b/crossbeam-channel/src/flavors/mod.rs index 0314bf420..7ad0a35ea 100644 --- a/crossbeam-channel/src/flavors/mod.rs +++ b/crossbeam-channel/src/flavors/mod.rs @@ -6,11 +6,13 @@ //! 2. `array` - Bounded channel based on a preallocated array. //! 3. `list` - Unbounded channel implemented as a linked list. //! 4. `never` - Channel that never delivers messages. +//! 5. `disconnected` - Channel that is always disconnected. //! 5. `tick` - Channel that delivers messages periodically. //! 6. `zero` - Zero-capacity channel. pub(crate) mod array; pub(crate) mod at; +pub(crate) mod disconnected; pub(crate) mod list; pub(crate) mod never; pub(crate) mod tick; diff --git a/crossbeam-channel/src/lib.rs b/crossbeam-channel/src/lib.rs index a3f29a712..593fbfd0c 100644 --- a/crossbeam-channel/src/lib.rs +++ b/crossbeam-channel/src/lib.rs @@ -356,7 +356,7 @@ cfg_if! { pub use crate::select::{select, select_timeout, try_select}; } - pub use crate::channel::{after, at, never, tick}; + pub use crate::channel::{after, at, never, disconnected, tick}; pub use crate::channel::{bounded, unbounded}; pub use crate::channel::{IntoIter, Iter, TryIter}; pub use crate::channel::{Receiver, Sender}; diff --git a/crossbeam-channel/src/select.rs b/crossbeam-channel/src/select.rs index 108eb04f7..07571bcd5 100644 --- a/crossbeam-channel/src/select.rs +++ b/crossbeam-channel/src/select.rs @@ -27,6 +27,8 @@ pub struct Token { pub(crate) list: flavors::list::ListToken, #[allow(dead_code)] pub(crate) never: flavors::never::NeverToken, + #[allow(dead_code)] + pub(crate) disconnected: flavors::disconnected::DisconnectedToken, pub(crate) tick: flavors::tick::TickToken, pub(crate) zero: flavors::zero::ZeroToken, }