nuclei/sync/watch.rs
1//! A multi-producer, multi-consumer channel that retains only the *last* sent
2//! value.
3//!
4//! [`channel`] returns a [`Sender`] and a [`Receiver`] around an initial
5//! value. Each [`Receiver`] tracks the last value *seen* by its own caller.
6//! The API is the established async watch-channel API; nothing here needs a
7//! runtime.
8//!
9//! - [`Receiver::borrow_and_update`] returns the current value and marks it
10//! seen. [`Receiver::borrow`] returns it without marking it seen.
11//! - [`Receiver::changed`] completes when a value the receiver has not seen
12//! is in the channel, and marks it seen. At creation the initial value is
13//! seen, and a receiver made by [`Sender::subscribe`] sees the value that
14//! was current at that moment as seen.
15//! - [`Receiver::has_changed`] is the synchronous check; it errors if and
16//! only if the channel is closed, while `changed` errors only when the
17//! channel is closed *and* the current value is seen.
18//! - [`Sender::is_closed`] and [`Sender::closed`] tell the producer that
19//! every [`Receiver`] is gone. The value is dropped when every sender and
20//! every receiver is gone.
21//!
22//! ```
23//! use nuclei::sync::watch;
24//!
25//! let (tx, mut rx) = watch::channel("hello");
26//! assert_eq!(*rx.borrow_and_update(), "hello");
27//! assert!(!rx.has_changed().unwrap());
28//!
29//! tx.send("world").unwrap();
30//! assert!(rx.has_changed().unwrap());
31//! assert_eq!(*rx.borrow_and_update(), "world");
32//! ```
33//!
34//! # The value lives in an `Atom`
35//!
36//! Where a lock-based channel guards the value with a read-write lock, this
37//! one keeps it in an [`Atom`]. A send publishes a new allocation with
38//! one swap; a borrow is one protected load and never blocks a sender, and a
39//! sender never blocks a borrow. Two consequences follow, and both differ
40//! from the lock-based API:
41//!
42//! - The channel needs `T: Send + Sync + 'static`: values are shared by
43//! reference between threads and reclaimed later.
44//! - A [`Ref`] does not hold a lock but a reclamation guard. A value that was
45//! replaced stays allocated until every `Ref` that can see it is dropped,
46//! so keep a `Ref` short. It is `!Send`: it must be dropped on the thread
47//! that took it, and the compiler therefore refuses to hold one across an
48//! await in a task that may move threads.
49//! - The old value cannot be handed back by value while readers may still
50//! look at it, so [`Sender::send_replace`] returns a *clone* (`T: Clone`),
51//! and the two in-place modifiers, [`Sender::send_modify`] and
52//! [`Sender::send_if_modified`], work on a clone too: they copy the value,
53//! let the closure change the copy and publish it with a
54//! compare-and-swap, retrying on a racing sender. Their closures are
55//! `FnMut` and may run more than once. A closure that panics, or that
56//! returns `false` from `send_if_modified`, publishes nothing, and the
57//! channel keeps the value it had.
58//!
59//! # Progress
60//!
61//! - Wait-free (a bounded number of the caller's own steps whatever other
62//! threads do): [`Receiver::borrow`], [`Receiver::borrow_and_update`],
63//! [`Receiver::has_changed`], [`Receiver::is_closed`],
64//! [`Receiver::mark_changed`], [`Receiver::mark_unchanged`],
65//! [`Sender::borrow`], [`Sender::is_closed`], [`Sender::subscribe`],
66//! [`Sender::receiver_count`], [`Sender::sender_count`], both `same_channel`
67//! checks, the clones, and dropping a [`Ref`]. A borrow is an `Atom`
68//! load, which is wait-free.
69//! - The *publication* of [`Sender::send`] and [`Sender::send_replace`] (the
70//! swap and the version bump) is wait-free, but each ends by waking the
71//! waiting receivers through [`Notify::notify_waiters`](super::Notify),
72//! which is lock-free: it takes the queue's drain role with a
73//! compare-and-swap, or leaves a mark for the thread that holds it, and a
74//! pass may serve waiters other threads queue meanwhile. So `send` and
75//! `send_replace` are lock-free, not wait-free. So is dropping the last
76//! sender or the last receiver, for the same wake.
77//! - [`Sender::send_modify`] and [`Sender::send_if_modified`] are lock-free:
78//! they retry the compare-and-swap whenever another sender published
79//! first, so a call can be delayed without bound by other senders' progress,
80//! and each retry runs the closure again.
81//! - Polling [`Receiver::changed`], [`Receiver::wait_for`] and
82//! [`Sender::closed`] is lock-free: a poll may queue a waiter, which is a
83//! lock-free queue operation.
84
85#![allow(unsafe_code)]
86
87use core::fmt;
88use core::ops::Deref;
89
90use kovan::{Atom, AtomGuard, CachePadded};
91
92use super::Notify;
93use super::internal::{Arc, AtomicU64, AtomicUsize, Ordering};
94
95use self::error::{RecvError, SendError};
96
97/// The low bit of the state word: every sender is gone.
98const CLOSED: u64 = 1;
99/// One send. Two keeps [`CLOSED`] out of the version.
100const STEP: u64 = 2;
101
102/// The version part of a state word.
103fn version_of(state: u64) -> u64 {
104 state & !CLOSED
105}
106
107pub mod error {
108 //! Error types of the watch channel.
109
110 use core::fmt;
111 use std::error::Error;
112
113 /// Error produced when sending a value fails: every receiver is gone.
114 ///
115 /// The value is handed back in the error.
116 #[derive(PartialEq, Eq, Clone, Copy)]
117 pub struct SendError<T>(pub T);
118
119 impl<T> fmt::Debug for SendError<T> {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 f.debug_struct("SendError").finish_non_exhaustive()
122 }
123 }
124
125 impl<T> fmt::Display for SendError<T> {
126 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(fmt, "channel closed")
128 }
129 }
130
131 impl<T> Error for SendError<T> {}
132
133 /// Error produced when receiving a change notification: every sender is
134 /// gone.
135 #[derive(Debug, Clone)]
136 pub struct RecvError(pub(super) ());
137
138 impl fmt::Display for RecvError {
139 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
140 write!(fmt, "channel closed")
141 }
142 }
143
144 impl Error for RecvError {}
145}
146
147struct Shared<T: Send + Sync + 'static> {
148 /// The most recent value.
149 value: Atom<T>,
150 /// The version in the high bits, [`CLOSED`] in the low bit. The version
151 /// moves after the value it counts is published and never before, which
152 /// is what lets a reader pair a version with a value that is at least as
153 /// new. Padded: every send writes it and every borrow reads it.
154 state: CachePadded<AtomicU64>,
155 /// How many [`Receiver`]s exist.
156 ref_count_rx: AtomicUsize,
157 /// How many [`Sender`]s exist.
158 ref_count_tx: AtomicUsize,
159 /// Wakes receivers waiting for a change.
160 notify_rx: Notify,
161 /// Wakes the producer waiting for the receivers to go.
162 notify_tx: Notify,
163}
164
165impl<T: Send + Sync + 'static> Shared<T> {
166 /// A value was just published: count it, then wake the receivers.
167 ///
168 /// The order matters twice. The version moves after the publication so a
169 /// reader that sees the version also finds that value or a newer one
170 /// (see [`Self::snapshot`]), and the wake comes after the version so a
171 /// receiver that was woken finds the new version when it looks (see
172 /// `changed_impl`).
173 fn published(&self) {
174 // Release: pairs with the Acquire loads of the state, publishing the
175 // value written before it.
176 self.state.fetch_add(STEP, Ordering::Release);
177 self.notify_rx.notify_waiters();
178 }
179
180 /// A value and a version that is no newer than it.
181 ///
182 /// The version is read first. It is bumped only after its value is
183 /// published, so the Acquire load of the state makes every publication
184 /// the version counts happen before the load of the value, and the value
185 /// is the newest of those or something newer. The reverse order could
186 /// pair a stale value with a version that already counts a newer one and
187 /// let a receiver mark that newer version seen without ever reading it.
188 /// The cost of this order is that a receiver can read a value one send
189 /// ahead of its version: a harmless extra `changed`, which the docs of
190 /// `Receiver::borrow` warn of.
191 fn snapshot(&self) -> (AtomGuard<'_, T>, u64) {
192 let version = version_of(self.state.load(Ordering::Acquire));
193 (self.value.load(), version)
194 }
195}
196
197impl<T: Send + Sync + 'static + fmt::Debug> fmt::Debug for Shared<T> {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 let state = self.state.load(Ordering::Acquire);
200 f.debug_struct("Shared")
201 .field("value", &*self.value.load())
202 .field("version", &version_of(state))
203 .field("is_closed", &(state & CLOSED != 0))
204 .field("ref_count_rx", &self.ref_count_rx)
205 .finish()
206 }
207}
208
209/// Creates a new watch channel around `init`, returning the send and receive
210/// handles.
211///
212/// All values sent by the [`Sender`] become visible to the [`Receiver`]
213/// handles; only the last value sent is kept, and the ones before it are
214/// dropped. The initial value counts as seen by the first receiver.
215///
216/// ```
217/// use nuclei::sync::watch;
218///
219/// let (tx, rx) = watch::channel(0u32);
220/// tx.send(1).unwrap();
221/// assert_eq!(*rx.borrow(), 1);
222/// ```
223pub fn channel<T: Send + Sync + 'static>(init: T) -> (Sender<T>, Receiver<T>) {
224 let shared = Arc::new(Shared {
225 value: Atom::new(init),
226 state: CachePadded::new(AtomicU64::new(0)),
227 ref_count_rx: AtomicUsize::new(1),
228 ref_count_tx: AtomicUsize::new(1),
229 notify_rx: Notify::new(),
230 notify_tx: Notify::new(),
231 });
232 let tx = Sender {
233 shared: Arc::clone(&shared),
234 };
235 let rx = Receiver { shared, version: 0 };
236 (tx, rx)
237}
238
239/// Sends values to the associated [`Receiver`]s.
240///
241/// Created by [`channel`]. Clone it for more producers. The channel closes
242/// for the receivers when the last sender is dropped.
243///
244/// Requires `T: Send + Sync + 'static`, see the [module docs](self).
245pub struct Sender<T: Send + Sync + 'static> {
246 shared: Arc<Shared<T>>,
247}
248
249/// Receives values from the associated [`Sender`]s.
250///
251/// Created by [`channel`] or [`Sender::subscribe`]; clone it for more
252/// consumers, each with its own record of what it has seen.
253///
254/// Requires `T: Send + Sync + 'static`, see the [module docs](self).
255pub struct Receiver<T: Send + Sync + 'static> {
256 shared: Arc<Shared<T>>,
257 /// The last version this receiver saw.
258 version: u64,
259}
260
261/// A reference to the value inside the channel.
262///
263/// Unlike a lock guard, a `Ref` never blocks a sender. It keeps the value it
264/// points to, and every value replaced since, allocated until it is dropped,
265/// so keep it short. It must be dropped on the thread that took it: it is
266/// not `Send`.
267pub struct Ref<'a, T: Send + Sync + 'static> {
268 guard: AtomGuard<'a, T>,
269 has_changed: bool,
270}
271
272// SAFETY: a shared `&Ref` gives `&T` and a bool. `T: Sync` makes the `&T`
273// safe on any thread, and the reclamation guard inside stays pinned on the
274// thread that owns the `Ref` for as long as the `Ref` lives, so the value
275// outlives every reference a `&Ref` hands out.
276unsafe impl<T: Send + Sync + 'static> Sync for Ref<'_, T> {}
277
278impl<T: Send + Sync + 'static> Ref<'_, T> {
279 /// Whether the borrowed value is considered *changed* since it was last
280 /// marked seen.
281 ///
282 /// Unlike [`Receiver::has_changed`], this does not fail when the channel
283 /// is closed. For a borrow taken from the [`Sender`] it is always
284 /// `false`.
285 ///
286 /// ```
287 /// use nuclei::sync::watch;
288 ///
289 /// let (tx, mut rx) = watch::channel("hello");
290 /// tx.send("goodbye").unwrap();
291 /// assert!(!tx.borrow().has_changed());
292 /// drop(tx);
293 /// assert!(rx.borrow().has_changed());
294 /// assert!(rx.borrow_and_update().has_changed());
295 /// assert!(!rx.borrow().has_changed());
296 /// ```
297 pub fn has_changed(&self) -> bool {
298 self.has_changed
299 }
300}
301
302impl<T: Send + Sync + 'static> Deref for Ref<'_, T> {
303 type Target = T;
304
305 fn deref(&self) -> &T {
306 &self.guard
307 }
308}
309
310impl<T: Send + Sync + 'static + fmt::Debug> fmt::Debug for Ref<'_, T> {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 f.debug_struct("Ref")
313 .field("value", &**self)
314 .field("has_changed", &self.has_changed)
315 .finish()
316 }
317}
318
319impl<T: Send + Sync + 'static> Receiver<T> {
320 fn from_shared(version: u64, shared: Arc<Shared<T>>) -> Self {
321 // Relaxed: a plain counter; no memory is published through it.
322 shared.ref_count_rx.fetch_add(1, Ordering::Relaxed);
323 Self { shared, version }
324 }
325
326 /// Returns a reference to the most recently sent value.
327 ///
328 /// Does not mark the value seen, so a later [`changed`](Self::changed)
329 /// can return at once even though you have read it. If you wait for
330 /// changes in a loop, prefer [`borrow_and_update`](Self::borrow_and_update).
331 ///
332 /// Wait-free, and it never blocks a sender. A borrow keeps the value it
333 /// points to alive; keep it short and drop it before awaiting.
334 ///
335 /// ```
336 /// use nuclei::sync::watch;
337 ///
338 /// let (_tx, rx) = watch::channel("hello");
339 /// assert_eq!(*rx.borrow(), "hello");
340 /// ```
341 pub fn borrow(&self) -> Ref<'_, T> {
342 let (guard, version) = self.shared.snapshot();
343 Ref {
344 guard,
345 has_changed: self.version != version,
346 }
347 }
348
349 /// Returns a reference to the most recently sent value and marks it seen.
350 ///
351 /// Later calls to [`changed`](Self::changed) do not return until a value
352 /// newer than this one is sent. Wait-free; see [`borrow`](Self::borrow)
353 /// for the advice on holding the reference.
354 ///
355 /// ```
356 /// use nuclei::sync::watch;
357 ///
358 /// let (tx, mut rx) = watch::channel("hello");
359 /// tx.send("goodbye").unwrap();
360 /// assert_eq!(*rx.borrow_and_update(), "goodbye");
361 /// assert!(!rx.has_changed().unwrap());
362 /// ```
363 pub fn borrow_and_update(&mut self) -> Ref<'_, T> {
364 let (guard, version) = self.shared.snapshot();
365 let has_changed = self.version != version;
366 self.version = version;
367 Ref { guard, has_changed }
368 }
369
370 /// Checks whether the channel holds a value this receiver has not seen.
371 /// The value is not marked seen.
372 ///
373 /// It does not compare values: the same value sent twice counts as a
374 /// change.
375 ///
376 /// # Errors
377 ///
378 /// Returns a [`RecvError`] if and only if the channel is closed.
379 ///
380 /// ```
381 /// use nuclei::sync::watch;
382 ///
383 /// let (tx, mut rx) = watch::channel("hello");
384 /// tx.send("goodbye").unwrap();
385 /// assert!(rx.has_changed().unwrap());
386 /// assert_eq!(*rx.borrow_and_update(), "goodbye");
387 /// assert!(!rx.has_changed().unwrap());
388 /// drop(tx);
389 /// assert!(rx.has_changed().is_err());
390 /// ```
391 pub fn has_changed(&self) -> Result<bool, RecvError> {
392 let state = self.shared.state.load(Ordering::Acquire);
393 if state & CLOSED != 0 {
394 return Err(RecvError(()));
395 }
396 Ok(self.version != version_of(state))
397 }
398
399 /// Whether the channel is closed: every [`Sender`] has been dropped.
400 ///
401 /// ```
402 /// use nuclei::sync::watch;
403 ///
404 /// let (tx, rx) = watch::channel(());
405 /// assert!(!rx.is_closed());
406 /// drop(tx);
407 /// assert!(rx.is_closed());
408 /// ```
409 pub fn is_closed(&self) -> bool {
410 self.shared.state.load(Ordering::Acquire) & CLOSED != 0
411 }
412
413 /// Marks the current value as not seen.
414 ///
415 /// Afterwards [`has_changed`](Self::has_changed) is `true` and
416 /// [`changed`](Self::changed) returns at once, whether or not a new value
417 /// is sent. Useful to trigger a first notification after subscribing.
418 pub fn mark_changed(&mut self) {
419 // Wrapping: it must agree with the wrapping `fetch_add` of the sender.
420 self.version = self.version.wrapping_sub(STEP);
421 }
422
423 /// Marks the current value as seen, without reading it.
424 pub fn mark_unchanged(&mut self) {
425 self.version = version_of(self.shared.state.load(Ordering::Acquire));
426 }
427
428 /// Waits for a change notification, then marks the current value as seen.
429 ///
430 /// If the current value has not been seen yet, this marks it seen and
431 /// returns at once. Otherwise it waits until a sender sends a new value
432 /// or the last sender is dropped.
433 ///
434 /// # Errors
435 ///
436 /// Returns a [`RecvError`] if the channel is closed *and* the current
437 /// value is seen.
438 ///
439 /// # Cancel safety
440 ///
441 /// Cancel safe: if the future is dropped before it completes, no value
442 /// was marked seen by it.
443 ///
444 /// ```
445 /// use nuclei::sync::watch;
446 /// use std::future::Future;
447 /// use std::pin::pin;
448 /// use std::task::{Context, Poll, Waker};
449 ///
450 /// let (tx, mut rx) = watch::channel("hello");
451 /// let mut cx = Context::from_waker(Waker::noop());
452 /// let mut changed = pin!(rx.changed());
453 /// assert!(changed.as_mut().poll(&mut cx).is_pending());
454 /// tx.send("goodbye").unwrap();
455 /// assert!(matches!(changed.as_mut().poll(&mut cx), Poll::Ready(Ok(()))));
456 /// ```
457 pub async fn changed(&mut self) -> Result<(), RecvError> {
458 changed_impl(&self.shared, &mut self.version).await
459 }
460
461 /// Waits for a value that satisfies `f`.
462 ///
463 /// Calls `f` on the current value first, even if it is already seen, and
464 /// then on the newest value whenever something is sent. When `f` returns
465 /// `true`, returns a reference to that value and marks it seen. The
466 /// channel keeps only the latest value, so a burst of sends can skip
467 /// values: `f` always sees the newest.
468 ///
469 /// # Errors
470 ///
471 /// Returns a [`RecvError`] if the channel is closed. Then `f` has been
472 /// called on the last value and returned `false` for it.
473 ///
474 /// # Cancel safety
475 ///
476 /// Cancel safe: the last value `f` returned `true` for is never marked
477 /// seen by a dropped call.
478 ///
479 /// # Panics
480 ///
481 /// If and only if `f` panics. Nothing the receiver shares is poisoned.
482 ///
483 /// ```
484 /// use nuclei::sync::watch;
485 /// use std::future::Future;
486 /// use std::pin::pin;
487 /// use std::task::{Context, Poll, Waker};
488 ///
489 /// let (tx, mut rx) = watch::channel(0);
490 /// let mut cx = Context::from_waker(Waker::noop());
491 /// let mut wait = pin!(rx.wait_for(|v| *v == 2));
492 /// assert!(wait.as_mut().poll(&mut cx).is_pending());
493 /// tx.send(1).unwrap();
494 /// assert!(wait.as_mut().poll(&mut cx).is_pending());
495 /// tx.send(2).unwrap();
496 /// match wait.as_mut().poll(&mut cx) {
497 /// Poll::Ready(Ok(value)) => assert_eq!(*value, 2),
498 /// _ => panic!("the value 2 was sent"),
499 /// }
500 /// ```
501 pub async fn wait_for(
502 &mut self,
503 mut f: impl FnMut(&T) -> bool,
504 ) -> Result<Ref<'_, T>, RecvError> {
505 let mut closed = false;
506 loop {
507 // A value that fits at once spends one operation of the poll's
508 // budget, as `changed` does.
509 if !crate::coop::has_budget_remaining() {
510 crate::coop::yield_spent().await;
511 }
512 {
513 let (guard, new_version) = self.shared.snapshot();
514 let has_changed = self.version != new_version;
515 self.version = new_version;
516 // After the channel closed, only a value that changed since
517 // `f` last judged is worth another call.
518 if (!closed || has_changed) && f(&guard) {
519 crate::coop::try_spend();
520 return Ok(Ref { guard, has_changed });
521 }
522 }
523 if closed {
524 return Err(RecvError(()));
525 }
526 closed = changed_impl(&self.shared, &mut self.version).await.is_err();
527 }
528 }
529
530 /// Whether the two receivers belong to the same channel.
531 ///
532 /// ```
533 /// use nuclei::sync::watch;
534 ///
535 /// let (_tx, rx) = watch::channel(true);
536 /// let rx2 = rx.clone();
537 /// assert!(rx.same_channel(&rx2));
538 /// let (_tx3, rx3) = watch::channel(true);
539 /// assert!(!rx3.same_channel(&rx2));
540 /// ```
541 pub fn same_channel(&self, other: &Self) -> bool {
542 Arc::ptr_eq(&self.shared, &other.shared)
543 }
544}
545
546/// The version after the one `version` records, or the end of the channel.
547fn maybe_changed<T: Send + Sync + 'static>(
548 shared: &Shared<T>,
549 version: &mut u64,
550) -> Option<Result<(), RecvError>> {
551 let state = shared.state.load(Ordering::Acquire);
552 let new_version = version_of(state);
553 if *version != new_version {
554 *version = new_version;
555 return Some(Ok(()));
556 }
557 if state & CLOSED != 0 {
558 return Some(Err(RecvError(())));
559 }
560 None
561}
562
563/// Waits until `maybe_changed` has an answer.
564///
565/// The wait cannot miss a send. The future for the next wake is created
566/// first, and only then is the version read:
567///
568/// - A [`Notified`](super::Notified) hears every `notify_waiters` made after
569/// it was *created*, polled or not.
570/// - A sender bumps the version and only then calls `notify_waiters`.
571///
572/// So take a send. If its version bump is visible to the read below, the read
573/// returns. If it is not, the bump came after the read, and `notify_waiters`,
574/// which is after the bump, came after the creation of the `Notified` (the
575/// read follows the creation in this thread's order, and a `notify_waiters`
576/// seen by the creation would have made the bump visible through its Release
577/// store), so the `Notified` completes. Either way the loop wakes up.
578/// A completion without a new version is a spurious wake, and the loop
579/// looks again.
580async fn changed_impl<T: Send + Sync + 'static>(
581 shared: &Shared<T>,
582 version: &mut u64,
583) -> Result<(), RecvError> {
584 loop {
585 // A change seen at once spends one operation of the poll's budget
586 // (see `coop`): with the budget spent, the look waits for the next
587 // poll, after the shard's other tasks.
588 if !crate::coop::has_budget_remaining() {
589 crate::coop::yield_spent().await;
590 }
591 let notified = shared.notify_rx.notified();
592 if let Some(ret) = maybe_changed(shared, version) {
593 crate::coop::try_spend();
594 return ret;
595 }
596 notified.await;
597 }
598}
599
600impl<T: Send + Sync + 'static> Clone for Receiver<T> {
601 fn clone(&self) -> Self {
602 Self::from_shared(self.version, Arc::clone(&self.shared))
603 }
604}
605
606impl<T: Send + Sync + 'static> Drop for Receiver<T> {
607 fn drop(&mut self) {
608 // Relaxed: the count publishes no memory. A producer waiting in
609 // `closed` reads it after creating its `Notified`, which hears the
610 // wake below, and that wake's Release makes this decrement visible.
611 if self.shared.ref_count_rx.fetch_sub(1, Ordering::Relaxed) == 1 {
612 self.shared.notify_tx.notify_waiters();
613 }
614 }
615}
616
617impl<T: Send + Sync + 'static + fmt::Debug> fmt::Debug for Receiver<T> {
618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619 f.debug_struct("Receiver")
620 .field("shared", &*self.shared)
621 .field("version", &self.version)
622 .finish()
623 }
624}
625
626impl<T: Send + Sync + 'static> Sender<T> {
627 /// Creates the sending half of a channel with no receiver yet.
628 ///
629 /// Sending fails until [`subscribe`](Self::subscribe) creates one.
630 ///
631 /// ```
632 /// use nuclei::sync::watch::Sender;
633 ///
634 /// let sender = Sender::new(0u8);
635 /// assert!(sender.send(3).is_err());
636 /// let _rx = sender.subscribe();
637 /// assert!(sender.send(4).is_ok());
638 /// ```
639 pub fn new(init: T) -> Self {
640 channel(init).0
641 }
642
643 /// Sends a new value, notifying all receivers.
644 ///
645 /// Fails if every receiver is gone; the value comes back in the error and
646 /// is not kept for receivers that [`subscribe`](Self::subscribe) later.
647 /// To always make a value available, even with no receiver, use
648 /// [`send_replace`](Self::send_replace), [`send_modify`](Self::send_modify)
649 /// or [`send_if_modified`](Self::send_if_modified).
650 ///
651 /// The publication is wait-free; the wake of the receivers makes the
652 /// whole call lock-free (see the [module docs](self)).
653 ///
654 /// ```
655 /// use nuclei::sync::watch;
656 ///
657 /// let (tx, rx) = watch::channel(1);
658 /// tx.send(2).unwrap();
659 /// assert_eq!(*rx.borrow(), 2);
660 /// drop(rx);
661 /// assert_eq!(tx.send(3).unwrap_err().0, 3);
662 /// ```
663 pub fn send(&self, value: T) -> Result<(), SendError<T>> {
664 // Only a hint: a receiver may come or go right after.
665 if self.receiver_count() == 0 {
666 return Err(SendError(value));
667 }
668 self.shared.value.store(value);
669 self.shared.published();
670 Ok(())
671 }
672
673 /// Modifies the watched value **unconditionally**, notifying all
674 /// receivers.
675 ///
676 /// Also works with no receiver. `modify` runs on a clone of the current
677 /// value, and the clone is published by a compare-and-swap; if another
678 /// sender published first, `modify` runs again on the new value, so it is
679 /// `FnMut`. Prefer [`send_if_modified`](Self::send_if_modified) when the
680 /// value is only sometimes changed.
681 ///
682 /// Lock-free: it retries against other senders.
683 ///
684 /// # Panics
685 ///
686 /// Panics if `modify` (or the clone) panics. Nothing is published then
687 /// and no receiver is notified: the channel keeps the value it had.
688 ///
689 /// ```
690 /// use nuclei::sync::watch;
691 ///
692 /// #[derive(Clone)]
693 /// struct State {
694 /// counter: usize,
695 /// }
696 /// let (tx, rx) = watch::channel(State { counter: 0 });
697 /// tx.send_modify(|state| state.counter += 1);
698 /// assert_eq!(rx.borrow().counter, 1);
699 /// ```
700 pub fn send_modify<F>(&self, mut modify: F)
701 where
702 F: FnMut(&mut T),
703 T: Clone,
704 {
705 self.send_if_modified(|value| {
706 modify(value);
707 true
708 });
709 }
710
711 /// Modifies the watched value **conditionally**, notifying all receivers
712 /// only if it was modified.
713 ///
714 /// `modify` runs on a clone of the current value and returns `true` if
715 /// it changed it. Only then is the clone published, by a
716 /// compare-and-swap that starts over on the new value when another
717 /// sender published first (so `modify` is `FnMut` and may run more than
718 /// once). When it returns `false` nothing is published, whatever it did
719 /// to its copy: unlike a lock-based channel there is no silent
720 /// modification.
721 ///
722 /// Returns `true` if a new value was published and `false` if `modify`
723 /// returned `false`.
724 ///
725 /// Lock-free: it retries against other senders.
726 ///
727 /// # Panics
728 ///
729 /// Panics if `modify` (or the clone) panics. Nothing is published then.
730 ///
731 /// ```
732 /// use nuclei::sync::watch;
733 ///
734 /// let (tx, mut rx) = watch::channel(1u32);
735 /// let inc_if_odd = |n: &mut u32| {
736 /// if *n % 2 == 1 {
737 /// *n += 1;
738 /// return true;
739 /// }
740 /// false
741 /// };
742 /// assert!(tx.send_if_modified(inc_if_odd));
743 /// assert_eq!(*rx.borrow_and_update(), 2);
744 /// assert!(!tx.send_if_modified(inc_if_odd));
745 /// assert!(!rx.has_changed().unwrap());
746 /// ```
747 pub fn send_if_modified<F>(&self, mut modify: F) -> bool
748 where
749 F: FnMut(&mut T) -> bool,
750 T: Clone,
751 {
752 loop {
753 let current = self.shared.value.load();
754 let mut next = T::clone(¤t);
755 if !modify(&mut next) {
756 return false;
757 }
758 // The guard in `current` keeps the compared value from being
759 // freed and reused, so the pointer comparison is sound.
760 if self.shared.value.compare_and_swap(¤t, next).is_ok() {
761 break;
762 }
763 // Another sender published first: start over from its value.
764 }
765 self.shared.published();
766 true
767 }
768
769 /// Sends a new value, notifying all receivers, and returns a clone of the
770 /// value it replaced.
771 ///
772 /// Also works with no receiver. The old value is returned as a clone
773 /// because receivers may still be reading it; see the
774 /// [module docs](self). The publication is wait-free; the wake of the
775 /// receivers makes the whole call lock-free.
776 ///
777 /// ```
778 /// use nuclei::sync::watch;
779 ///
780 /// let (tx, _rx) = watch::channel(1);
781 /// assert_eq!(tx.send_replace(2), 1);
782 /// assert_eq!(tx.send_replace(3), 2);
783 /// ```
784 pub fn send_replace(&self, value: T) -> T
785 where
786 T: Clone,
787 {
788 let old = self.shared.value.swap(value);
789 // Published before the clone: a clone that panics must not leave a
790 // new value that no receiver hears about.
791 self.shared.published();
792 T::clone(&old)
793 }
794
795 /// Returns a reference to the most recently sent value.
796 ///
797 /// A borrow from the sender is never marked changed. See
798 /// [`Receiver::borrow`] for the advice on holding the reference.
799 ///
800 /// ```
801 /// use nuclei::sync::watch;
802 ///
803 /// let (tx, _) = watch::channel("hello");
804 /// assert_eq!(*tx.borrow(), "hello");
805 /// ```
806 pub fn borrow(&self) -> Ref<'_, T> {
807 Ref {
808 guard: self.shared.value.load(),
809 has_changed: false,
810 }
811 }
812
813 /// Whether the channel is closed for sending: every [`Receiver`] has been
814 /// dropped. [`subscribe`](Self::subscribe) reopens it.
815 ///
816 /// ```
817 /// use nuclei::sync::watch;
818 ///
819 /// let (tx, rx) = watch::channel(());
820 /// assert!(!tx.is_closed());
821 /// drop(rx);
822 /// assert!(tx.is_closed());
823 /// ```
824 pub fn is_closed(&self) -> bool {
825 self.receiver_count() == 0
826 }
827
828 /// Completes when every receiver has been dropped.
829 ///
830 /// Lets the producer stop work nobody wants. If the channel closes
831 /// briefly (the last receiver is dropped and [`subscribe`](Self::subscribe)
832 /// is called again), this may or may not notice.
833 ///
834 /// # Cancel safety
835 ///
836 /// Cancel safe.
837 ///
838 /// ```
839 /// use nuclei::sync::watch;
840 /// use std::future::Future;
841 /// use std::pin::pin;
842 /// use std::task::{Context, Poll, Waker};
843 ///
844 /// let (tx, rx) = watch::channel("hello");
845 /// let mut cx = Context::from_waker(Waker::noop());
846 /// let mut closed = pin!(tx.closed());
847 /// assert_eq!(closed.as_mut().poll(&mut cx), Poll::Pending);
848 /// drop(rx);
849 /// assert_eq!(closed.as_mut().poll(&mut cx), Poll::Ready(()));
850 /// ```
851 pub async fn closed(&self) {
852 while self.receiver_count() > 0 {
853 // Created before the count is read again, for the reason given at
854 // `changed_impl`: the last receiver's drop wakes it after the
855 // decrement.
856 let notified = self.shared.notify_tx.notified();
857 if self.receiver_count() == 0 {
858 return;
859 }
860 notified.await;
861 // The channel may have been reopened by `subscribe`: look again.
862 }
863 }
864
865 /// Creates a new [`Receiver`] connected to this sender.
866 ///
867 /// The value that is current now counts as seen by the new receiver. It
868 /// works with no other receiver, which reopens the channel.
869 ///
870 /// ```
871 /// use nuclei::sync::watch;
872 ///
873 /// let (tx, _rx) = watch::channel(0u64);
874 /// tx.send(5).unwrap();
875 /// let rx = tx.subscribe();
876 /// assert_eq!(*rx.borrow(), 5);
877 /// assert!(!rx.has_changed().unwrap());
878 /// ```
879 pub fn subscribe(&self) -> Receiver<T> {
880 // The CLOSED bit tracks only whether the senders are gone, so a
881 // reopened channel needs no reset of it.
882 let version = version_of(self.shared.state.load(Ordering::Acquire));
883 Receiver::from_shared(version, Arc::clone(&self.shared))
884 }
885
886 /// How many receivers exist now.
887 ///
888 /// ```
889 /// use nuclei::sync::watch;
890 ///
891 /// let (tx, rx) = watch::channel("hello");
892 /// assert_eq!(tx.receiver_count(), 1);
893 /// let _rx2 = rx.clone();
894 /// assert_eq!(tx.receiver_count(), 2);
895 /// ```
896 pub fn receiver_count(&self) -> usize {
897 // Relaxed: a count; callers that act on it re-check as `closed` does.
898 self.shared.ref_count_rx.load(Ordering::Relaxed)
899 }
900
901 /// How many senders exist now.
902 ///
903 /// ```
904 /// use nuclei::sync::watch;
905 ///
906 /// let (tx, _rx) = watch::channel("hello");
907 /// assert_eq!(tx.sender_count(), 1);
908 /// let tx2 = tx.clone();
909 /// assert_eq!(tx2.sender_count(), 2);
910 /// ```
911 pub fn sender_count(&self) -> usize {
912 // Relaxed: as `receiver_count`.
913 self.shared.ref_count_tx.load(Ordering::Relaxed)
914 }
915
916 /// Whether the two senders belong to the same channel.
917 ///
918 /// ```
919 /// use nuclei::sync::watch;
920 ///
921 /// let (tx, _rx) = watch::channel(true);
922 /// let tx2 = tx.clone();
923 /// assert!(tx.same_channel(&tx2));
924 /// let (tx3, _rx3) = watch::channel(true);
925 /// assert!(!tx3.same_channel(&tx2));
926 /// ```
927 pub fn same_channel(&self, other: &Self) -> bool {
928 Arc::ptr_eq(&self.shared, &other.shared)
929 }
930}
931
932impl<T: Send + Sync + 'static> Clone for Sender<T> {
933 fn clone(&self) -> Self {
934 // Relaxed: a plain counter, and the clone proves a sender exists.
935 self.shared.ref_count_tx.fetch_add(1, Ordering::Relaxed);
936 Self {
937 shared: Arc::clone(&self.shared),
938 }
939 }
940}
941
942impl<T: Send + Sync + 'static + Default> Default for Sender<T> {
943 fn default() -> Self {
944 Self::new(T::default())
945 }
946}
947
948impl<T: Send + Sync + 'static> Drop for Sender<T> {
949 fn drop(&mut self) {
950 // AcqRel: the thread that drops the last sender sees every earlier
951 // sender's sends before it closes the channel.
952 if self.shared.ref_count_tx.fetch_sub(1, Ordering::AcqRel) == 1 {
953 // Release: a receiver that sees CLOSED sees the last version.
954 self.shared.state.fetch_or(CLOSED, Ordering::Release);
955 self.shared.notify_rx.notify_waiters();
956 }
957 }
958}
959
960impl<T: Send + Sync + 'static + fmt::Debug> fmt::Debug for Sender<T> {
961 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
962 f.debug_struct("Sender")
963 .field("shared", &*self.shared)
964 .finish()
965 }
966}
967
968#[cfg(all(test, not(loom)))]
969mod tests {
970 use super::*;
971
972 #[test]
973 fn the_closed_bit_leaves_the_version_alone() {
974 let (tx, rx) = channel(0u8);
975 tx.send(1).unwrap();
976 let before = version_of(tx.shared.state.load(Ordering::Acquire));
977 drop(tx);
978 assert!(rx.is_closed());
979 assert_eq!(version_of(rx.shared.state.load(Ordering::Acquire)), before);
980 }
981
982 #[test]
983 fn the_version_wraps_without_touching_the_closed_bit() {
984 let (tx, rx) = channel(0u8);
985 tx.shared.state.store(u64::MAX - 1, Ordering::SeqCst);
986 tx.send(1).unwrap();
987 let state = tx.shared.state.load(Ordering::SeqCst);
988 assert_eq!(state & CLOSED, 0, "a wrapped version is not a close");
989 assert_eq!(version_of(state), 0);
990 assert!(!rx.is_closed());
991 }
992}