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}