Pass self to callback

Hi,

I have the following code which I can't make compile:

struct Node {
    pub channel: Channel,
    pub state: NodeState,
    id: Option<String>,
    next_message_id: u32,
}

impl Node {
    fn new() -> Self {
        Node {
            channel: Channel::new(),
            next_message_id: 0,
            id: None,
        }
    }

    fn handle(&mut self, handler: &mut Box<dyn FnMut(String, &mut Node)>) {
        self.channel.on_data(|data| handler(data, &mut self))
    }
}

#[derive(Debug)]
struct Channel;

impl Channel {
    fn new() -> Self {
        Channel {}
    }

    fn on_data(&self, mut handler: impl FnMut(String)) {
        for line in io::stdin().lines() {
            match line {
                Ok(line) => {
                    handler(line);
                }
                Err(_) => panic!("Unexpected error"),
            }
        }
    }
}

The Node implementation includes a handle method that's called each time there's data coming through the channel. This is the error I get:

error[E0500]: closure requires unique access to `*self` but it is already borrowed
   --> src/bin/unique-ids.rs:104:30
    |
104 |         self.channel.on_data(|data| handler(data, self))
    |         ---------------------^^^^^^---------------------
    |         |            |       |                    |
    |         |            |       |                    second borrow occurs due to use of `*self` in closure
    |         |            |       closure construction occurs here
    |         |            first borrow later used by call
    |         borrow occurs here

For more information about this error, try `rustc --explain E0500`.
error: could not compile `gossip-glomers-rust` (bin "unique-ids") due to previous erro

I tried what I found suggested in other posts (or stack overflow): split the Node into separate structs (Node and NodeState):

struct Node {
    pub channel: Channel,
    pub state: NodeState,
}

#[derive(Debug)]
struct NodeState {
    pub id: Option<String>,
    pub next_message_id: u32,
}

impl Node {
    fn new() -> Self {
        Node {
            channel: Channel::new(),
            state: NodeState {
                next_message_id: 0,
                id: None,
            },
        }
    }

    fn handle(&mut self, handler: &mut Box<dyn FnMut(String, &mut NodeState)>) {
        self.channel.on_data(|data| handler(data, &mut self.state))
    }
}

This works but it won't allow me do what I need next. The thing is that I need the handler closure to invoke mutable methods (not implemented yet) in the node which executed the handler. Something like the following:

   // This could be the handler passed to Node#handle

   Box::new(move |line: String, node_state: &mut NodeState, node: &mut Node| {
      // ...

      node.send(<some data goes here>)

     // ...
   }

What would be the idiomatic way of doing this in Rust? Extract the state I need for the send method into a separate struct?

thanks

That would be one way if possible.

Otherwise, if you boil down, you're asking how to accomplish this:

struct Channel;

impl Channel {
    fn send(&mut self, some_data: u8) { let _ = some_data; }
    fn on_data(&self) {
        indirectly!{ self.send(0) };
    }
}

You can't do it at all with the &self parameter. If you changed on_data to take a &mut self, then it would be possible to call send from on_data directly. However, there's no way to stash a &mut Channel in a closure and then call a method of Channel and pass in the closure. For the duration of the &mut Channel, all access to the Channel has to chain back to the single, exclusive &mut Channel somehow.

So you would need to invert things a bit and have on_data give the handler a reborrow of itself:

fn on_data(&mut self, mut handler: impl FnMut(&mut Self, String)) {
    // ...
    handler(self, data);
}

How good of an idea this is for your use case, I'm not sure. There might be a better way to arrange things at a higher layer.

Related reading.


Side note, this is a weird signature.[1]

fn handle(&mut self, handler: &mut Box<dyn FnMut(String, &mut NodeState)>)

If you don't care about avoiding generics, take a F: FnMut(...). If you need ownership without generics, take Box<dyn FnMut(...)>. If you want to avoid generics for some reason but don't need ownership, take a &mut dyn FnMut(...).


  1. The only reason I can think of it take a &mut Box<dyn FnMut(...)> is if you were planning to replace the caller's closure with a new one. Which would also be a bit weird. â†Šī¸Ž

3 Likes

What you are suggesting changes the design that I had in mind originally. While the Channel might have a send method clients of the node don't interact with the channel directly. They do it via the node#send method, like in the example snippet I pasted:

// This could be the handler passed to Node#handle

   Box::new(move |line: String, node_state: &mut NodeState, node: &mut Node| {
      // ...

      node.send(<some data goes here>)

     // ...
   }

A possible implementation of node#send could be:

fn send(&mut self, data: String) {
   self.next_message_id += 1
   let message = message_from_string(data, self.next_message_id)

   self.channel.send(message)
}

Maybe you already took this into account and I missing your point.

That's the result of me still learning Rust and not knowing what's the best tool for each job :sweat:

This is what I have now

#[derive(Debug)]
struct Node {
    pub channel: Channel,
    pub state: NodeState,
    pub dispatcher: NodeDispatcher,
}

#[derive(Debug)]
struct NodeState {
    id: Option<String>,
    next_message_id: u32,
}

#[derive(Debug)]
struct NodeDispatcher {
    pub next_message_id: u32,
    pub channel: Channel,
}

impl NodeDispatcher {
    fn send(&mut self, message: &Message) {
        self.channel.send(serde_json::to_string(message).unwrap());
        self.next_message_id += 1
    }
}

impl Node {
    fn new() -> Self {
        Node {
            channel: Channel::new(),
            state: NodeState {
                next_message_id: 0,
                id: None,
            },
            dispatcher: NodeDispatcher {
                next_message_id: 0,
                channel: Channel::new(),
            },
        }
    }

    fn handle(
        &mut self,
        handler: &mut Box<dyn FnMut(String, &mut NodeState, &mut NodeDispatcher)>,
    ) {
        self.channel
            .on_data(|data| handler(data, &mut self.state, &mut self.dispatcher))
    }
}

#[derive(Debug)]
struct Channel;

impl Channel {
    fn new() -> Self {
        Channel {}
    }

    fn on_data(&self, mut handler: impl FnMut(String)) {
        for line in io::stdin().lines() {
            match line {
                Ok(line) => {
                    handler(line);
                }
                Err(_) => panic!("Unexpected error"),
            }
        }
    }

    fn send(&self, data: String) {
        println!("{}", data)
    }
}

I have two separate structs NodeState and NodeDispatcher to be able to pass mut references to them while already holding a borrow on the node:

 fn handle(
        &mut self,
        handler: &mut Box<dyn FnMut(String, &mut NodeState, &mut NodeDispatcher)>,
    ) {
        self.channel
            .on_data(|data| handler(data, &mut self.state, &mut self.dispatcher))
    }

iirc this was a because I copy pasted the return type of the function that returns the closure that I then pass to node#on_data

fn make_unique_ids() -> Box<dyn FnMut(String, &mut NodeState, &mut NodeDispatcher)> {
    Box::new(
        move |line: String, node: &mut NodeState, dispatcher: &mut NodeDispatcher| {
            
        }
    )
}

I have simplified it to:

    fn handle(&mut self, mut handler: impl FnMut(String, &mut NodeState, &mut NodeDispatcher)) {
        self.channel
            .on_data(|data| handler(data, &mut self.state, &mut self.dispatcher))
    }

But it's unclear why I need the mut modifier before handler since I'm not mutating the handler.

A FnMut closure is one that potentially modifies what it captures, so you need a &mut to the closure to run it.

// Off the top of my head, might be slightly off

struct _CompilerGeneratedClosure {
    _field0: Vec<String>,
}

impl FnOnce<()> for _CompilerGeneratedClosure {
    type Output = Option<String>;
    fn call_once(mut self, args: ()) -> Self::Output {
        self.call_mut(args)
    }
}

impl FnMut<()> for _CompilerGeneratedClosure {
    fn call_mut(&mut self, args: ()) -> Self::Output {
        self._field0.pop()
    }
}