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.