nuclei/sync/local/
oneshot.rs1#![allow(unsafe_code)]
20
21use core::cell::{Cell, UnsafeCell};
22use core::fmt;
23use core::future::Future;
24use core::pin::Pin;
25use core::task::{Context, Poll, Waker};
26
27use crate::mem::BlockRc as Rc;
28pub use crate::sync::oneshot::error;
29use crate::sync::oneshot::error::{RecvError, TryRecvError};
30
31const VALUE_SENT: u8 = 0b001;
32const RX_CLOSED: u8 = 0b010;
33const TX_DROPPED: u8 = 0b100;
34
35struct Inner<T> {
36 state: Cell<u8>,
37 value: UnsafeCell<Option<T>>,
38 rx_waker: Cell<Option<Waker>>,
39 tx_waker: Cell<Option<Waker>>,
40}
41
42impl<T> Inner<T> {
43 fn has(&self, bit: u8) -> bool {
44 self.state.get() & bit != 0
45 }
46
47 fn set(&self, bit: u8) {
48 self.state.set(self.state.get() | bit);
49 }
50
51 fn put(&self, value: T) {
52 unsafe { *self.value.get() = Some(value) };
55 }
56
57 fn take(&self) -> Option<T> {
58 unsafe { (*self.value.get()).take() }
60 }
61}
62
63#[inline]
66fn register(slot: &Cell<Option<Waker>>, waker: &Waker) {
67 match slot.take() {
68 Some(old) if old.will_wake(waker) => slot.set(Some(old)),
69 old => {
70 slot.set(Some(waker.clone()));
71 drop(old);
72 }
73 }
74}
75
76#[inline]
77fn wake(slot: &Cell<Option<Waker>>) {
78 if let Some(waker) = slot.take() {
79 waker.wake();
80 }
81}
82
83pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
97 let inner = Rc::new(Inner {
98 state: Cell::new(0),
99 value: UnsafeCell::new(None),
100 rx_waker: Cell::new(None),
101 tx_waker: Cell::new(None),
102 });
103 (
104 Sender {
105 inner: Some(Rc::clone(&inner)),
106 },
107 Receiver { inner: Some(inner) },
108 )
109}
110
111pub struct Sender<T> {
116 inner: Option<Rc<Inner<T>>>,
117}
118
119impl<T> Sender<T> {
120 pub fn send(mut self, value: T) -> Result<(), T> {
126 let Some(inner) = self.inner.take() else {
127 return Err(value);
128 };
129 if inner.has(RX_CLOSED) {
130 inner.set(TX_DROPPED);
131 return Err(value);
132 }
133 inner.put(value);
134 inner.set(VALUE_SENT | TX_DROPPED);
135 wake(&inner.rx_waker);
136 Ok(())
137 }
138
139 pub async fn closed(&mut self) {
141 core::future::poll_fn(|cx| self.poll_closed(cx)).await;
142 }
143
144 pub fn is_closed(&self) -> bool {
146 self.inner.as_ref().is_none_or(|inner| inner.has(RX_CLOSED))
147 }
148
149 pub fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<()> {
152 let Some(inner) = self.inner.as_ref() else {
153 return Poll::Ready(());
154 };
155 if inner.has(RX_CLOSED) {
156 return Poll::Ready(());
157 }
158 register(&inner.tx_waker, cx.waker());
159 Poll::Pending
160 }
161}
162
163impl<T> Drop for Sender<T> {
164 fn drop(&mut self) {
165 let Some(inner) = self.inner.as_ref() else {
166 return;
167 };
168 inner.set(TX_DROPPED);
169 wake(&inner.rx_waker);
170 drop(inner.tx_waker.take());
171 }
172}
173
174impl<T> fmt::Debug for Sender<T> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("Sender")
177 .field("is_closed", &self.is_closed())
178 .finish()
179 }
180}
181
182pub struct Receiver<T> {
187 inner: Option<Rc<Inner<T>>>,
188}
189
190impl<T> Receiver<T> {
191 pub fn close(&mut self) {
194 let Some(inner) = self.inner.as_ref() else {
195 return;
196 };
197 inner.set(RX_CLOSED);
198 wake(&inner.tx_waker);
199 }
200
201 pub fn is_terminated(&self) -> bool {
203 self.inner.is_none()
204 }
205
206 pub fn is_empty(&self) -> bool {
208 self.inner
209 .as_ref()
210 .is_none_or(|inner| !inner.has(VALUE_SENT))
211 }
212
213 pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
221 let Some(inner) = self.inner.as_ref() else {
222 return Err(TryRecvError::Closed);
223 };
224 if let Some(value) = inner.take() {
225 self.inner = None;
226 return Ok(value);
227 }
228 if inner.has(RX_CLOSED | TX_DROPPED) {
229 self.inner = None;
230 return Err(TryRecvError::Closed);
231 }
232 Err(TryRecvError::Empty)
233 }
234}
235
236impl<T> Drop for Receiver<T> {
237 fn drop(&mut self) {
238 let Some(inner) = self.inner.as_ref() else {
239 return;
240 };
241 inner.set(RX_CLOSED);
242 wake(&inner.tx_waker);
243 drop(inner.rx_waker.take());
244 drop(inner.take());
245 }
246}
247
248impl<T> Future for Receiver<T> {
249 type Output = Result<T, RecvError>;
250
251 #[expect(
252 clippy::panic,
253 reason = "polled after it completed, which the `Future` contract rules out"
254 )]
255 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
256 let this = self.get_mut();
257 let Some(inner) = this.inner.as_ref() else {
258 panic!("called after complete");
259 };
260 if !inner.has(VALUE_SENT | RX_CLOSED | TX_DROPPED) {
261 register(&inner.rx_waker, cx.waker());
262 return Poll::Pending;
263 }
264 if crate::coop::exhausted(cx.waker()) {
265 return Poll::Pending;
266 }
267 let done = inner.take().ok_or(RecvError(()));
268 this.inner = None;
269 crate::coop::spent_one();
270 Poll::Ready(done)
271 }
272}
273
274impl<T> fmt::Debug for Receiver<T> {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 f.debug_struct("Receiver")
277 .field("is_terminated", &self.is_terminated())
278 .field("is_empty", &self.is_empty())
279 .finish()
280 }
281}