I have a tokio tcp server which should hand individual incoming connections to a service. How do I correctly handle indirection so that the server can work with different service implementations? I have resorted to calling tokio::spawn()
inside the service because I couldn't find a way to return a future with indirection.
Here's a minimal example of what I'm doing:
extern crate tokio;
use tokio::prelude::future::FutureResult;
use tokio::prelude::*;
struct Subject {
name: String,
}
struct MySvc {
name: String,
}
trait Svc6 {
fn handle6(&self, subject: Subject);
}
impl Svc6 for MySvc {
fn handle6(&self, subject: Subject) {
let task = future::ok((self.name.to_string(), subject))
.and_then(|(n, s)| Ok(println!("#6. Hi {}! My name is {}.", s.name, n)));
tokio::spawn(task);
}
}
#[test]
fn svc6_works() {
let svc = MySvc {
name: "Zorg".into(),
};
let subj = Subject {
name: "Gandalf".into(),
};
tokio::run(future::ok(svc).and_then(|s| Ok(s.handle6(subj))));
}
While this works with indirection, I'm concerned if I'm using tokio
correctly. Each Svc6
impl has to call tokio::spawn()
rather than just returning a task. I'd also prefer if the server handles spawning as it may need to deal with prioritization and queueing. It is also hard to test a method that doesn't return anything.
Here is a playground link of the other things I've been trying. To see the full context, go to Samotop source and the accept fn.
It would be great if trait method implementation could return impl Trait!
trait Svc1 {
fn handle1(&self, subject: Subject) -> Future<Item = (), Error = ()>;
}
impl Svc1 for MySvc {
// error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
fn handle1(&self, subject: Subject) -> impl Future<Item = (), Error = ()> {
future::ok(println!(
"#1. Hi {}! My name is {}.",
subject.name, self.name
))
}
}