nickel-org / nickel.rs

An expressjs inspired web framework for Rust

Home Page:http://nickel-org.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using `Nickel::with_data` with ZST causes strange behavior with `Router`

pwoolcoc opened this issue · comments

I was trying to go through the nickel-mustache example where a ZST is passed to indicate the default layout, and ended up finding some strange behavior in nickel when trying to use a Router with Nickel::with_data. If you use Nickel::new() or Nickel::with_data(()), you can mount a Router under a prefix without a problem. But, if you use with_data with any other data type, even a zero-sized type, you get the error shown below the code example. It seems that Router is not correctly implementing Fn and FnOnce in this case, but I'm unsure of how to fix it. Do I need to implement those traits for struct Data, in the example below? What would actually be in those impls?

I would appreciate some guidance on this.

#[macro_use]
extern crate nickel;

use nickel::{Nickel, HttpRouter, Mountable};

#[allow(dead_code)]
struct Data;

fn main() {
    let mut server = Nickel::with_data(Data);
    // But if you comment ^ and uncomment v, then it works
    // let mut server = Nickel::with_data(());

    server.mount("/a/", explicit_router());

    server.listen("127.0.0.1:6767");
}

fn explicit_router() -> nickel::Router {
    let mut router = nickel::Router::new();
    router.get("/b", middleware! { |_req | "hello, world!" });
    router
}

// examples/with_data.rs:11:12: 11:17 error: the trait bound `for<'r, 'mw, 'conn> nickel::Router: std::ops::Fn<(&'r mut nickel::Request<'mw, 'conn, Data>, nickel::Response<'mw, Data>)>` is not satisfied [E0277]
// examples/with_data.rs:11     server.mount("/a", explicit_router());
//                                     ^~~~~
// examples/with_data.rs:11:12: 11:17 help: run `rustc --explain E0277` to see a detailed explanation
// examples/with_data.rs:11:12: 11:17 note: required because of the requirements on the impl of `nickel::Middleware<Data>` for `nickel::Router`
// examples/with_data.rs:11:12: 11:17 error: the trait bound `for<'r, 'mw, 'conn> nickel::Router: std::ops::FnOnce<(&'r mut nickel::Request<'mw, 'conn, Data>, nickel::Response<'mw, Data>)>` is not satisfied [E0277]
// examples/with_data.rs:11     server.mount("/a", explicit_router());
//                                     ^~~~~
// examples/with_data.rs:11:12: 11:17 help: run `rustc --explain E0277` to see a detailed explanation
// examples/with_data.rs:11:12: 11:17 note: required because of the requirements on the impl of `nickel::Middleware<Data>` for `nickel::Router`

I think the following should work:

fn explicit_router() -> nickel::Router<Data> {
    let mut router = nickel::Router::new();
    router.get("/b", middleware! { |_req | "hello, world!" });
    router
}
// alternatively you could do `fn explicit_router<D>() -> nickel::Router<D> {}` but that could
// be overly generic for application code.

Router has a default typeparam of D = (), the error message kind of hints at this but it's really unclear if you don't know what's going on. It might be good to adjust some of the samples to show something like this a bit clearer! Perhaps removing the default typeparam might be something to consider for the next breaking changes release?

@Ryman thanks a lot, that did the trick. Sorry for the spurious bug!