0
lazy_static::lazy_static! {
    static ref file_data: String = fs::read_to_string("static/login.html").expect("unable to read from static/login.html");
}

#[tokio::main]
async fn main() {
    // code omitted
    let login = warp::path("login").map(move || warp::reply::html(file_data));
    // code omitted
}

Compile error:

error[E0277]: the trait bound `hyper::body::body::Body: std::convert::From<file_data>` is not satisfied
   --> src/main.rs:45:49
    |
45  |     let login = warp::path("login").map(move || warp::reply::html(file_data));
    |                                                 ^^^^^^^^^^^^^^^^^ the trait `std::convert::From<file_data>` is not implemented for `hyper::body::body::Body`
    | 
   ::: /home/ichi/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.2.3/src/reply.rs:170:11
    |
170 |     Body: From<T>,
    |           ------- required by this bound in `warp::reply::html`
    |
    = help: the following implementations were found:
              <hyper::body::body::Body as std::convert::From<&'static [u8]>>
              <hyper::body::body::Body as std::convert::From<&'static str>>
              <hyper::body::body::Body as std::convert::From<bytes::bytes::Bytes>>
              <hyper::body::body::Body as std::convert::From<std::borrow::Cow<'static, [u8]>>>
            and 4 others

I am trying to pass a String to a closure. According to the documentation, From<String> is implemented for hyper::body::Body and file_data is of type String. So why am I getting this error?

너를 속였다
  • 899
  • 11
  • 26

2 Answers2

2

The issue here is that lazy_static creates a wrapper type that references your data, and hyper doesn't know how to handle it. You could use file_data.clone() to clone the referenced data and construct a body from that, but in this case there's actually a simpler method. Since your string has a fixed value and Body implements From<&'static str>, you don't actually need a heap-allocated String or lazy_static at all: You can use the following code which just uses a constant string slice that can be used directly.

const FILE_DATA: &str = "test";

#[tokio::main]
async fn main() {
    // code omitted
    let login = warp::path("login").map(move || warp::reply::html(FILE_DATA));
    // code omitted
}
apetranzilla
  • 5,331
  • 27
  • 34
2

From lazy_static

For a given static ref NAME: TYPE = EXPR;, the macro generates a unique type that implements Deref<TYPE> and stores it in a static with name NAME. (Attributes end up attaching to this type.)

That is, the type of the variable is not TYPE!

This is why you see the error

the trait `std::convert::From<file_data>` is not implemented for `hyper::body::body::Body`
                              ^^^^^^^^^

You'd probably have better luck explicitly de-referencing or cloning the global variable: warp::reply::html(&*file_data) or warp::reply::html(file_data.clone()).

mcarton
  • 27,633
  • 5
  • 85
  • 95
  • 1
    Using `*` to dereference the value wouldn't help here because you can't move from a `lazy_static` and `String` isn't `Copy`. – apetranzilla Jul 11 '20 at 17:51
  • It might also be worth clarifying the difference between `&*` and `.clone()` - i.e. passing a reference to static data vs copying it into a new value. `.as_str()` may also be a more clear and idiomatic equivalent to `&*`. – apetranzilla Jul 11 '20 at 18:00