|
@@ -1,9 +1,12 @@
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
use tokio::sync::Notify;
|
|
|
|
|
|
-/// A multi/single-producer, single-consumer channel for updating an object.
|
|
|
+/// A channel for updating an object.
|
|
|
/// Unlike a mpsc, there is no queue of objects, only the most recent can be obtained.
|
|
|
/// Unlike a watch, the receiver owns the object received.
|
|
|
+/// Any copy of the owner (created via clone) can send or receive objects,
|
|
|
+/// but only one copy will receive any particular object.
|
|
|
+#[derive(Default)]
|
|
|
pub struct Updater<T>(Arc<(Mutex<Option<T>>, Notify)>);
|
|
|
|
|
|
impl<T> Updater<T> {
|
|
@@ -17,6 +20,10 @@ impl<T> Updater<T> {
|
|
|
/// Get the object most recently sent by the sender end.
|
|
|
pub async fn recv(&mut self) -> T {
|
|
|
// According to a dev on GH, tokio's Notify is allowed false notifications.
|
|
|
+ // This is conceptually better suited for a condvar, but the only async
|
|
|
+ // implementations aren't cancellation safe.
|
|
|
+ // Precondition: the only way for the object to be updated is to notify,
|
|
|
+ // and no receiver consumes a notify without consuming the object as well.
|
|
|
loop {
|
|
|
self.0 .1.notified().await;
|
|
|
{
|
|
@@ -34,11 +41,13 @@ impl<T> Updater<T> {
|
|
|
locked_object.take()
|
|
|
}
|
|
|
|
|
|
- /// Create an Updater channel.
|
|
|
- /// Currently there is no distinction between sender and receiver updaters,
|
|
|
- /// it's the caller's job to decide which is which.
|
|
|
- pub fn channel() -> (Self, Self) {
|
|
|
- let body = Arc::new((Mutex::new(None), Notify::new()));
|
|
|
- (Updater(body.clone()), Updater(body))
|
|
|
+ pub fn new() -> Self {
|
|
|
+ Updater(Arc::new((Mutex::new(None), Notify::new())))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T> Clone for Updater<T> {
|
|
|
+ fn clone(&self) -> Self {
|
|
|
+ Updater(Arc::clone(&self.0))
|
|
|
}
|
|
|
}
|