4

I am trying to store a hyper::server::Server as a member of my struct (struct MyApp below). I can do this from, for example, my program's main() function.

How can I do this in my struct's MyApp::new() method? I think I need the concrete type for F in MyApp<F>. However, despite trying, I am unable to (correctly) specify a concrete type for this closure.

I can't figure out how to do this. I thought Boxing the closure would work by allowing me to pass the closure as a concrete type, and indeed it does when I do this in main(), but not MyApp::new(). I am hoping there is a way to do this in stable rust, as I would really like to implement a structure which contains a hyper Server.

Here is my struct:

struct MyApp<F> {
    hyper_server: Server<MyBoxedClosure<F>, hyper::Body>,
}

And here is the full code that works -- it sets the MyApp.hyper_server field in main():

extern crate hyper;
extern crate futures;
use hyper::Error;
use hyper::server::{Http, Server, NewService, Service, Request, Response};
use hyper::header::ContentLength;

pub struct HelloWorld;

const PHRASE: &'static str = "Hello, World!";

impl Service for HelloWorld {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, _req: Request) -> Self::Future {
        futures::future::ok(
            Response::new()
                .with_header(ContentLength(PHRASE.len() as u64))
                .with_body(PHRASE),
        )
    }
}

pub struct MyBoxedClosure<F> {
    value: Box<F>,
}

impl<F> NewService for MyBoxedClosure<F>
where
    F: Fn() -> std::result::Result<HelloWorld, std::io::Error>,
{
    type Request = Request;
    type Response = Response;
    type Error = Error;
    type Instance = HelloWorld;

    fn new_service(&self) -> std::result::Result<Self::Instance, std::io::Error> {
        self.value.new_service()
    }
}

struct MyApp<F> {
    hyper_server: Server<MyBoxedClosure<F>, hyper::Body>,
}

fn main() {
    let mbc = MyBoxedClosure { value: Box::new(|| Ok(HelloWorld)) };
    let addr = "127.0.0.1:3000".parse().unwrap();
    let hyper_server = Http::new().bind(&addr, mbc).unwrap();
    let my_app = MyApp { hyper_server: hyper_server };

    println!("Hello, world!");
}

If I create a MyApp::new() function and call that from the main() instead, I can't figure out how to avoid a compiler error.

impl<F> MyApp<F>
where
    F: Fn() -> std::result::Result<HelloWorld, std::io::Error> + Send + Sync,
{
    fn new() -> MyApp<F> {
        let mbc = MyBoxedClosure { value: Box::new(|| Ok(HelloWorld)) };
        let addr = "127.0.0.1:3000".parse().unwrap();
        let hyper_server = Http::new().bind(&addr, mbc).unwrap();
        MyApp { hyper_server: hyper_server }
    }
}

fn main() {
    let _my_app = MyApp::new();
    println!("Hello, world!");
}

The compiler error is this:

error[E0308]: mismatched types
  --> src/main.rs:56:9
   |
56 |         MyApp { hyper_server: hyper_server }
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found closure
   |
   = note: expected type `MyApp<F>`
              found type `MyApp<[closure@src/main.rs:53:52: 53:69]>`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Andrew Straw
  • 1,138
  • 12
  • 15
  • You create generic function that should return any type user want `fn new() -> MyApp`, but you return concrete type instead of `F` – fghj Jul 23 '17 at 09:58
  • @E_net4 Your suggested duplicate does not deal with closures. I don't think it is a duplicate. – Andrew Straw Jul 23 '17 at 12:13
  • 1
    @AndrewStraw closure or not is not important. Import that you tell `fn new() -> MyApp` I return any type you want, and then you return conrete type. Note that your signature allow too call like this `let a = MyApp::::new()`, while your `new` obviouse return not `MyApp` – fghj Jul 23 '17 at 12:16
  • @AndrewStraw As mentioned by user103479, the closure is not the root of the problem here. Parameter types are defined by the caller, not the callee. If you want the function to always return `MyApp`, then the return type of that method must be fixed. – E_net4 Jul 23 '17 at 12:18
  • I have updated my attempt to implement MyApp:new() with a concrete type. Indeed with something other than a closure, I would expect this would fix the issue. However, in this case, the compilation still fails with the message I listed. This is why I think there is a specific issue with closures and why I do not think the other questions you listed are duplicates. – Andrew Straw Jul 23 '17 at 12:27
  • 1
    Right. Now it's a duplicate of [Returning a closure from a function](https://stackoverflow.com/q/25445761/1233251). – E_net4 Jul 23 '17 at 12:34
  • I have read that one about 20 times but still cannot get my example to work. Here is [a link to the problem on the playground](https://play.rust-lang.org/?gist=0b0d96958d4438e10bbc0b025f7682c7&version=nightly). – Andrew Straw Jul 23 '17 at 12:37
  • 1
    @AndrewStraw You should redo your code, the most simple way is remove `F` completly make `MyBoxedClosure` concrete type with `Box` something as field. – fghj Jul 23 '17 at 14:01
  • 1
    [Here's one solution](https://play.integer32.com/?gist=549c3d879dcdb6beb114466cad7d2413&version=stable). As @user1034749 mentions, replacing the type parameter with a boxed trait object is currently the best way to return a closure. – Shepmaster Jul 23 '17 at 15:00
  • Wonderful, thank you. Now if one of you will answer the question I will accept it. :) – Andrew Straw Jul 23 '17 at 15:07
  • Not good idea to answer, because of if anyone answer this question marked as duplicate @Shepmaster ban him :) – fghj Jul 23 '17 at 15:35
  • @user1034749 once it's a duplicate you *can't* answer. I also don't have the power to ban anyone, and I can't think of a single case over the last ~3 years I'd have wanted to. I will certainly chide people or up/downvote to try and uphold quality on Stack Overflow, but that's the same power that anyone who can comment or vote holds. – Shepmaster Jul 23 '17 at 15:37
  • Well, thank you all for the help. I must say that I don't see this as "marked as an exact duplicate of an existing question" because closures are different than primitive types. The one "exact duplicate" dealing with closures has the specific problem "missing lifetime specifier". Surely all of them are useful, but reading them several times each still wasn't enough for me to solve my problem. – Andrew Straw Jul 23 '17 at 18:47

0 Answers0