2

I'm working on embedding actix-web into a binding library. I would like to declare a HttpServer within a struct so that I can easily call .start() and .system_exit(). From my very basic reading of the source code it's already implemented as a struct with two dependencies: <H, F>. It also comes with a factory to instantiate itself.

If I'm understanding this correctly, then I would have to implement the HttpServer as a dependency in my new struct and add my own characteristics within it. My previous thought was to create a new struct and just declare HttpServer as a property within it. That seemed troublesome with the generics that needed to be declared within it.

What I've come up with so far is:

struct CustomServer<T> {
    srv: T,
}

impl<T> CustomServer<T>
where
    T: HttpServer,
{
    fn init() {
        self.srv = HttpServer::new(|| App /* etc. */)
    }
}

I'm not sure if I'm grasping at straws or in the right direction.

The question is: how should/can I go about defining a struct that has HttpServer and it's functions accessible in my struct?

ddibiase
  • 1,412
  • 1
  • 20
  • 44

1 Answers1

2

HttpServer is a generic struct, not a trait (so “T: HttpServer” doesn’t make sense).

You can either make a generic struct that contains a totally arbitrary instantiation of HttpServer (this is likely not very useful to you):

struct CustomServer<H: IntoHttpHandler + 'static, F: Fn() -> H + Send + Clone + 'static> {
    srv: HttpServer<H, F>,
}

impl<H: IntoHttpHandler + 'static, F: Fn() -> H + Send + Clone + 'static> CustomServer<H, F> {
    fn new(factory: F) -> CustomServer<H, F> {
        CustomServer {
            srv: HttpServer::new(factory),
        }
    }
}

or a concrete struct that contains a particular kind of HttpServer (I’m guessing this is what you’ll want, though it’s hard to say without details of your use case):

struct CustomServer {
    srv: HttpServer<App, fn() -> App>,
}

impl CustomServer {
    fn new() -> CustomServer {
        CustomServer {
            srv: HttpServer::new(|| App),
        }
    }
}

There are also many points in between (e.g. specialize H but not F, or specialize slightly based on other generic parameters), depending on what you’re trying to do.

Anders Kaseorg
  • 3,657
  • 22
  • 35
  • Ahhhhh. I ended up going with the generic struct in case I want to have more flexibility. Thank you very much, I was definitely overthinking this. :-( – ddibiase Jan 16 '19 at 19:02
  • Hmmm strange...when I attempt initializing the struct I'm getting: server expected fn pointer, found closure: let server = server::new( || App::new() .middleware(middleware::Logger::default()) .default_resource(|r| r.f(index)) ); Ok(CustomServer { address: address.value(), port: port.value() as i32, server: server }). Why would it complain about the closure, it's following the same structure. – ddibiase Jan 16 '19 at 19:09
  • Sorry the above includes the error, then exactly what I'm feeding into the struct. – ddibiase Jan 16 '19 at 19:37
  • @ddibiase The difference between a function and a closure is that a closure brings in variables from the surrounding scope: in this case, `index`. This would be a case where you need to make the struct generic in `F` and use impl trait to represent the closure in the return type (`fn new() -> CustomServer App>`). – Anders Kaseorg Jan 16 '19 at 20:57
  • I see. I forget that closures bring in scope like that. I decided to go with the concrete struct so now I'm thinking through what you mentioned. Sorry just really confused and grasping at comprehending a few things happening here. :-p – ddibiase Jan 16 '19 at 22:24
  • sorry I'm still stumped by this. I've posted a pastebin with some pseudo code that roughly describes what I'm doing: https://pastebin.com/aUreUhH6 I'm still getting "expected fn pointer, found closure" and I feel like I'm just not grasping this entirely. – ddibiase Jan 20 '19 at 03:33