Skip to content

austenadler/single-mpsc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

single-mpsc

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

Usage

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" }

Example

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);

About

No description, website, or topics provided.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages