Cheap mpsc in single threaded situations?

Short Question: Is there something like mpsc, but cheaper and used in single threaded situations?

Long Question: I have some "Objects", which need to receive messages. I want to be able to send an object a message with only a (non-mutable) reference -- as the object does not "update" until the "run_update" function is called.

One way to do this is for each object to have a mpsc. However, given everything is single threaded, I am wondering if there is a less expensive solution.

Rc<RefCell<VecDeque>> springs to mind, just needs a simple wrapper interface.

2 Likes

This is what I have so far:


#[derive(Clone)]
pub struct PipePut<T> {
    data: Rc<RefCell<VecDeque<T>>>,
}

pub struct PipePop<T> {
    data: Rc<RefCell<VecDeque<T>>>,
}

pub struct PipeUtil {}

impl PipeUtil {
    pub fn new<T>() -> (PipePut<T>, PipePop<T>) {
        let data = Rc::new(RefCell::new(VecDeque::new()));
        (PipePut{data: data.clone()}, PipePop{data: data.clone()})
    }
}


impl <T> PipePut<T> {
    pub fn put(&self, t: T) {
        self.data.borrow_mut().push_back(t);
    }
}

impl <T> PipePop<T> {
    pub fn pop(&self) -> Option<T> {
        self.data.borrow_mut().pop_front()
    }
}


Advice / criticism / suggestions ?

I would probably not put the new function in a PipeUtil struct — it seems like the idiomatic way of doing this would be a free standing function, in the same way as with channel.

1 Like

I think your advice certainly matches Rust conventions -- but I have never understood this Rust convention. Free standing functions seem to clutter the namespaces via imports; whereas with a "empty util struct" we can group things together and just import the one Struct.

Free standing functions seem to clutter the namespaces via imports; whereas with a “empty util struct” we can group things together and just import the one Struct.

Unless you want the util struct to implement some trait, I don't see a benefit to this. If you just want to namespace your util functions under some name, a module provides that same namespacing.

The struct does not implement any trait. Nor is it ever constructed.

This is purely a personal preference that goes against standard Rust convention.

I recommend importing free standing functions as:

use std::sync::mpsc;

let (tx, rx) = mpsc::channel();

or if you also need one of the types

use std::sync::mpsc::{self, Receiver};

let (tx, rx) = mpsc::channel();
let recv: Receiver = rx;
1 Like