I am trying to implement a server using Mio and a reactor pattern. I want my Reactor to handle both TcpListeners and TcpStreams, so abstracting over that is my real challenge here.
I have a trait ReAgent that implements various handlers for informing the Reactor about changes in status, while Reactor informs each individual ReAgent about events important to that ReAgent. In turn, I'll have two different ReAgent types, one for accepting (TcpListeners) which will spawn clients (TcpStreams) to pass back to the Reactor for event handling. A very standard Reactor pattern for multiple server endpoints; I've written half a dozen of these in C/C++ over my career. Eliding details about my TokenPool, etc., here's where my headache lies:
pub struct Reactor<'a> {
poll: Poll,
agents: HashMap<Token, Box<ReAgent + 'a>>,
tokens: TokenPool,
}
impl<'a> Reactor<'a> {
pub fn add_agent<R: ReAgent + 'a>(&mut self, mut agent: Box<R>) -> Result<()>
{
if let Some(next_token) = self.tokens.pop() {
agent.set_token(next_token);
self.agents.insert(agent.get_token(), agent);
return Ok(())
}
bail!(ErrorKind::ConnectionsExhausted)
}
}
//...
/// Received a Box<ReAgent> (a Client);
/// add and start conversation
Some(boxed_agent) => self.add_agent(boxed_agent)
When I compile this, I get:
Some(boxed_agent) => self.add_agent(boxed_agent)
^^^^^^^^^ `reagent::ReAgent` does not have a constant size known at compile-time
... which I don't get at all. It's a Box. A Box has a known constant size at compile time. That's the whole point here of using Box to support a dynamic type object, right? The client has a known size, it's a concrete implementation of ReAgent.
What am I missing?
I know I'll probably have to use a RefCell later, since I'm mutating the ReAgent to set its polling token; that's for later, I just want to get past this.