events_once/core/
sync_endpoints_nice.rs

1//! This simply wraps the core endpoints with a nicer API surface that eliminates
2//! the outer generic type parameter, leaving only the inner T of the payload.
3
4use std::any::type_name;
5use std::pin::Pin;
6use std::task::Poll;
7use std::{fmt, task};
8
9use crate::{BoxedRef, Disconnected, IntoValueError, PtrRef, ReceiverCore, SenderCore};
10
11/// Delivers a single value to the receiver connected to the same event.
12///
13/// This kind of endpoint is used for boxed events, which are heap-allocated and automatically
14/// destroyed when both the sender and receiver are dropped.
15pub struct BoxedSender<T: Send + 'static> {
16    inner: SenderCore<BoxedRef<T>, T>,
17}
18
19impl<T: Send + 'static> BoxedSender<T> {
20    pub(crate) fn new(inner: SenderCore<BoxedRef<T>, T>) -> Self {
21        Self { inner }
22    }
23
24    /// Sends a value to the receiver connected to the same event.
25    ///
26    /// This method consumes the sender and always succeeds, regardless of whether
27    /// there is a receiver waiting.
28    pub fn send(self, value: T) {
29        self.inner.send(value);
30    }
31}
32
33#[cfg_attr(coverage_nightly, coverage(off))] // No API contract to test.
34impl<T: Send + 'static> fmt::Debug for BoxedSender<T> {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        f.debug_struct(type_name::<Self>())
37            .field("inner", &self.inner)
38            .finish()
39    }
40}
41
42/// Receives a single value from the sender connected to the same event.
43///
44/// Awaiting the receiver will yield either the payload of type `T` or a [`Disconnected`] error.
45///
46/// This kind of endpoint is used for boxed events, which are heap-allocated and automatically
47/// destroyed when both the sender and receiver are dropped.
48pub struct BoxedReceiver<T: Send + 'static> {
49    inner: ReceiverCore<BoxedRef<T>, T>,
50}
51
52impl<T: Send + 'static> BoxedReceiver<T> {
53    pub(crate) fn new(inner: ReceiverCore<BoxedRef<T>, T>) -> Self {
54        Self { inner }
55    }
56
57    /// Checks whether a value is ready to be received.
58    ///
59    /// # Panics
60    ///
61    /// Panics if called after `poll()` has returned `Ready`.
62    #[must_use]
63    pub fn is_ready(&self) -> bool {
64        self.inner.is_ready()
65    }
66
67    /// Consumes the receiver and transforms it into the received value, if the value is available.
68    ///
69    /// This method provides an alternative to awaiting the receiver when you want to check for
70    /// an immediately available value without blocking. It returns `Ok(value)` if a value has
71    /// already been sent, or returns the receiver if no value is currently available.
72    ///
73    /// # Panics
74    ///
75    /// Panics if the value has already been received via `Future::poll()`.
76    ///
77    /// # Examples
78    ///
79    /// ```rust
80    /// use events_once::{Event, IntoValueError};
81    ///
82    /// #[tokio::main]
83    /// async fn main() {
84    ///     let (sender, receiver) = Event::<String>::boxed();
85    ///
86    ///     // into_value() is designed for synchronous scenarios where you do not want to wait but
87    ///     // simply want to either obtain the received value or do nothing. First, we do nothing.
88    ///     //
89    ///     // If no value has been sent yet, into_value() returns Err(IntoValueError::Pending(self)).
90    ///     let Err(IntoValueError::Pending(receiver)) = receiver.into_value() else {
91    ///         panic!(
92    ///             "Expected receiver to indicate that it is still waiting for a payload to be sent."
93    ///         );
94    ///     };
95    ///
96    ///     sender.send("Hello, world!".to_string());
97    ///
98    ///     let message = receiver.into_value().unwrap();
99    ///
100    ///     println!("Received message: {message}");
101    /// }
102    /// ```
103    pub fn into_value(self) -> Result<T, IntoValueError<Self>> {
104        match self.inner.into_value() {
105            Ok(value) => Ok(value),
106            Err(IntoValueError::Pending(inner)) => Err(IntoValueError::Pending(Self { inner })),
107            Err(IntoValueError::Disconnected) => Err(IntoValueError::Disconnected),
108        }
109    }
110}
111
112impl<T: Send + 'static> Future for BoxedReceiver<T> {
113    type Output = Result<T, Disconnected>;
114
115    #[cfg_attr(test, mutants::skip)] // Cargo-mutants tries a boatload of unviable mutations and wastes time on this.
116    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
117        // SAFETY: We never move out of `self`, only access its inner field.
118        let inner = unsafe { self.map_unchecked_mut(|x| &mut x.inner) };
119
120        inner.poll(cx)
121    }
122}
123
124#[cfg_attr(coverage_nightly, coverage(off))] // No API contract to test.
125impl<T: Send + 'static> fmt::Debug for BoxedReceiver<T> {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        f.debug_struct(type_name::<Self>())
128            .field("inner", &self.inner)
129            .finish()
130    }
131}
132
133/// Delivers a single value to the receiver connected to the same event.
134///
135/// This kind of endpoint is used with events for which the storage is provided by the
136/// owner of the endpoint. They are also responsible for ensuring that the event that
137/// connects the sender-receiver pair outlives both endpoints.
138pub struct RawSender<T: Send + 'static> {
139    inner: SenderCore<PtrRef<T>, T>,
140}
141
142impl<T: Send + 'static> RawSender<T> {
143    pub(crate) fn new(inner: SenderCore<PtrRef<T>, T>) -> Self {
144        Self { inner }
145    }
146
147    /// Sends a value to the receiver connected to the same event.
148    ///
149    /// This method consumes the sender and always succeeds, regardless of whether
150    /// there is a receiver waiting.
151    pub fn send(self, value: T) {
152        self.inner.send(value);
153    }
154}
155
156#[cfg_attr(coverage_nightly, coverage(off))] // No API contract to test.
157impl<T: Send + 'static> fmt::Debug for RawSender<T> {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        f.debug_struct(type_name::<Self>())
160            .field("inner", &self.inner)
161            .finish()
162    }
163}
164
165/// Receives a single value from the sender connected to the same event.
166///
167/// Awaiting the receiver will yield either the payload of type `T` or a [`Disconnected`] error.
168///
169/// This kind of endpoint is used with events for which the storage is provided by the
170/// owner of the endpoint. They are also responsible for ensuring that the event that
171/// connects the sender-receiver pair outlives both endpoints.
172pub struct RawReceiver<T: Send + 'static> {
173    inner: ReceiverCore<PtrRef<T>, T>,
174}
175
176impl<T: Send + 'static> RawReceiver<T> {
177    pub(crate) fn new(inner: ReceiverCore<PtrRef<T>, T>) -> Self {
178        Self { inner }
179    }
180
181    /// Checks whether a value is ready to be received.
182    ///
183    /// # Panics
184    ///
185    /// Panics if called after `poll()` has returned `Ready`.
186    #[must_use]
187    pub fn is_ready(&self) -> bool {
188        self.inner.is_ready()
189    }
190
191    /// Consumes the receiver and transforms it into the received value, if the value is available.
192    ///
193    /// This method provides an alternative to awaiting the receiver when you want to check for
194    /// an immediately available value without blocking. It returns `Ok(value)` if a value has
195    /// already been sent, or returns the receiver if no value is currently available.
196    ///
197    /// # Panics
198    ///
199    /// Panics if the value has already been received via `Future::poll()`.
200    ///
201    /// # Examples
202    ///
203    /// ```rust
204    /// use events_once::{Event, IntoValueError};
205    ///
206    /// #[tokio::main]
207    /// async fn main() {
208    ///     let (sender, receiver) = Event::<String>::boxed();
209    ///
210    ///     // into_value() is designed for synchronous scenarios where you do not want to wait but
211    ///     // simply want to either obtain the received value or do nothing. First, we do nothing.
212    ///     //
213    ///     // If no value has been sent yet, into_value() returns Err(IntoValueError::Pending(self)).
214    ///     let Err(IntoValueError::Pending(receiver)) = receiver.into_value() else {
215    ///         panic!(
216    ///             "Expected receiver to indicate that it is still waiting for a payload to be sent."
217    ///         );
218    ///     };
219    ///
220    ///     sender.send("Hello, world!".to_string());
221    ///
222    ///     let message = receiver.into_value().unwrap();
223    ///
224    ///     println!("Received message: {message}");
225    /// }
226    /// ```
227    pub fn into_value(self) -> Result<T, IntoValueError<Self>> {
228        match self.inner.into_value() {
229            Ok(value) => Ok(value),
230            Err(IntoValueError::Pending(inner)) => Err(IntoValueError::Pending(Self { inner })),
231            Err(IntoValueError::Disconnected) => Err(IntoValueError::Disconnected),
232        }
233    }
234}
235
236impl<T: Send + 'static> Future for RawReceiver<T> {
237    type Output = Result<T, Disconnected>;
238
239    #[cfg_attr(test, mutants::skip)] // Cargo-mutants tries a boatload of unviable mutations and wastes time on this.
240    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
241        // SAFETY: We never move out of `self`, only access its inner field.
242        let inner = unsafe { self.map_unchecked_mut(|x| &mut x.inner) };
243
244        inner.poll(cx)
245    }
246}
247
248#[cfg_attr(coverage_nightly, coverage(off))] // No API contract to test.
249impl<T: Send + 'static> fmt::Debug for RawReceiver<T> {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        f.debug_struct(type_name::<Self>())
252            .field("inner", &self.inner)
253            .finish()
254    }
255}