Generic Reference Type for function input

I have a trait ProcessNode which essentially is just a stateful function that takes in an input A and outputs B:

pub trait ProcessNode<A, B> {
    fn process(&mut self, input: A) -> B;
}

Then I have a struct Branch which is also a ProcessNode. All Branch does is take two ProcessNodes, feeds the input into one, feeds the output of that one to the other, and then returns the output of both. Since it would be inefficient to clone the output of the first node, I want to pass it as reference to the second node to generate the second output. This is what I currently have:

pub struct Branch<'a, A, B, C, D: ProcessNode<A, B>, E: ProcessNode<&'a B, C>> {
    _marker: PhantomData<(A, &'a B, C)>,
    node1: D,
    node2: E
}

impl <'a, A, B, C, D: ProcessNode<A, B>, E: ProcessNode<&'a B, C>>ProcessNode<A, (B,C)> for Branch<'a, A, B, C, D, E> {
    fn process(&mut self, input: A) -> (B, C) {
        let out1 = self.node1.process(input);
        let out2 = self.node2.process(&out1);
        (out1, out2)
    }
}

This throws an error because the refrence I pass to the second function doesn't live for 'a. I could make another generic that would be the input of the second function, but then the output of the first and the input of the second will not be linked. Is there a way to solve this?

You could infect the trait with a lifetime parameter so that implementations could be bounded based on lifetimes... but I don't recommend it. What you probably really mean is that node2 can take any arbitrarily short lifetime. Here's what that looks like:

// n.b. I didn't see why the bounds had to be on the struct itself,
// and this doesn't require `PhantomData`
pub struct Branch<F, G> {
    node1: F,
    node2: G,
}

impl<In, Middle, Out, F, G> ProcessNode<In, (Middle, Out)> for Branch<F, G>
where
    F: ProcessNode<In, Middle>,
    G: for<'any> ProcessNode<&'any Middle, Out>,
{
    fn process(&mut self, input: In) -> (Middle, Out) {
        let middle = self.node1.process(input);
        let out = self.node2.process(&middle);
        (middle, out)
    }
}

Bonus(?) obversation: ProcessNode looks a lot like FnMut (modulo variadic parameters). It may be the case that it makes more sense for Out to be an associated type instead of a type parameter. (Will anything every implement ProcessNode for more than one output type?)

So, here's the associated type version in case you don't need multiple outputs per implementer.

pub trait ProcessNode<In> {
    type Out;
    fn process(&mut self, input: In) -> Self::Out;
}

pub struct Branch<F, G> {
    node1: F,
    node2: G,
}

impl<In, Middle, Out, F, G> ProcessNode<In> for Branch<F, G>
where
    F: ProcessNode<In, Out=Middle>,
    G: for<'any> ProcessNode<&'any Middle, Out=Out>,
{
    type Out = (Middle, Out);
    fn process(&mut self, input: In) -> Self::Out {
        let middle = self.node1.process(input);
        let out = self.node2.process(&middle);
        (middle, out)
    }
}

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.