This crate provides a single-value mpsc channel that blocks on recv
, but doesn’t block on send
by replacing the single value to send
is called.
This crate is backed by an Option<T>
where send
calls are *single_value = Some(T)
and recv
calls .take()
, but blocks if the value is None
.
Any message sent to this channel will update the latest value and the previous value is dropped.
This is similar to the blocking [std::sync::mpsc::sync_channel
]/crossbeam::channel::bounded(1)
, except senders will not block when sending messages (except for when acquiring a Mutex lock).
A good use-case for this is debouncing expensive code to run only once after any number of sends. For example, when a user is typing, the [Sender
] part can send each key to the channel and the [Receiver
] part can fire an expensive function off on each [Receiver::recv
] call. Since each send just updates the latest value, only 1 value will be available for recv
at a time
This crate isn’t published to rust crates, because I don’t know how to do that yet. You can use it with:
[dependencies]
single-mpsc = { git = "https://github.com/austenadler/single-mpsc" }
use single_mpsc::channel;
use std::sync::atomic::AtomicUsize;
static EXPENSIVE_CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
let (tx, mut rx) = channel();
// This function takes 30 seconds to run
let expensive_fn = |i| {
eprintln!("Expensive function on {i}...");
EXPENSIVE_CALL_COUNT.fetch_add(1, Ordering::SeqCst);
std::thread::sleep(std::time::Duration::from_secs(15));
};
// Add 10 events, 1 per second
std::thread::spawn(move || {
for i in 0..10 {
tx.send(i);
std::thread::sleep(std::time::Duration::from_secs(1));
}
// Receiver knows when the last transmitter is dropped
std::mem::drop(tx);
});
while let Ok(msg) = rx.recv() {
// Runs once with the first message 0
// Then, since this function is so slow, runs a second time with the most recent message 10
expensive_fn(msg);
}
// The expensive should have only been called twice
assert_eq!(EXPENSIVE_CALL_COUNT.load(Ordering::SeqCst), 2);