How to get a 'chain of handlers' implemented in Rust?

Hi,

I am struggling to get ownership and lifetimes correct when trying to implement a 'chain of handlers'. I have implementations of handlers abstracted by a trait Handler, which I can add to a handler chain. The chain should then process a data element by applying each of its handlers to the data element. The handlers need to collect statistics during processing and I need to access this data after processing all elements. The closest to a working solution I was able to come up with is the code below. It still doesn't compile (see line commented with 'cannot borrow'). I've tried out many variants of this solution but either struggle with ownership or with lifetime annotations. Any help is appreciated.

trait Handler {
    fn handle(&mut self, data: u32);
}

struct HandlerA {
    field: u32,
}

impl Handler for HandlerA {
    fn handle(&mut self, data: u32) {
        if data % 2 == 0 { self.field += 1 };
    }
}

struct HandlerB {
    field: u32,
}

impl Handler for HandlerB {
    fn handle(&mut self, data: u32) {
        if data % 2 == 1 { self.field += 1 };
    }
}

struct HandlerChain<'a> {
    pub handlers: Vec<&'a dyn Handler>,
}

impl<'a> HandlerChain<'a> {
    fn new() -> HandlerChain<'a> {
        HandlerChain {
            handlers: vec![],
        }
    }

    fn append(&mut self, s: &'a dyn Handler) -> &mut Self {
        self.handlers.push(s);
        self
    }

    fn run_handlers(&mut self, data: u32) {
         for h in &mut self.handlers {
             h.handle(data);  // cannot borrow `**h` as mutable
         }
    }
}

fn main() {
    let one: HandlerA = HandlerA { field: 0 };
    let another: HandlerB = HandlerB { field: 0 };

    let mut chain: HandlerChain = HandlerChain::new();

    chain
        .append(&one)
        .append(&another)
    ;

    for u in 1..5 { 
        chain.run_handlers(u);
    }

    assert_eq!(one.field, 2);
}

Here's a playground where I made this change...

 struct HandlerChain<'a> {
-    pub handlers: Vec<&'a dyn Handler>,
+    pub handlers: Vec<&'a mut dyn Handler>,
 }

...and then followed the compiler errors to change & to &mut and let to let mut wherever needed.

Implicit in this design is that the individual handlers can't be moved or otherwise used while the HandlerChain<'_> exists. You may find this is limiting, but it works for the OP at least.


Short explaination: you can think of an implementation like this existing:

impl Handler for dyn Handler + '_ {
    fn handle(self: &mut (dyn Handler + '_), data: u32) {
        /* code that dispatches to the implementation of the base type */
    }
}

You can't call this method with a &dyn Handler; you need a &mut dyn Handler.

1 Like

Thanks for the prompt reply and explanation! Now I understand the compiler error message and I can't believe I struggled so long to find such a simple solution. Thank you very much!

To get your example working, the mutability of the references needs to be consistent Rust Playground. The Playground I linked compiles and runs. If your program needs something more complex, like sharing handlers between objects, you might want to consider using smart pointers like Rc<RefCell<..>>. Or if you want you chain to permanently own them instead of holding mutable references, they could be wrapped in Box<dyn ...>.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.