0

I have the following implementation of the actix_web FromRequest trait:

impl ::actix_web::FromRequest for Box<dyn SessionRepository> {
    type Error = ::actix_web::Error;
    type Future =
        ::futures::future::MapOk<::futures::future::Ready<Result<Self, Self::Error>>, ???>;
    type Config = ();

    fn from_request(
        req: &::actix_web::HttpRequest,
        payload: &mut actix_web::dev::Payload,
    ) -> Self::Future {
        RealSessionRepository::from_request(&req, payload).map_ok(|dep| Box::new(dep))
    }
}

As the return type is an FnOnce, I cannot figure out how to actually set the return type. According to the error message it should be FnOnce<(std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>,)>, however that tells me that fnOnce is not valid because it's not a known size at compile time.

RealSessionRepository::from_request returns a future, also being an implementation of the FromRequest trait.

Inserting the FnOnce definition like this:

impl ::actix_web::FromRequest for Box<dyn SessionRepository> {
    type Error = ::actix_web::Error;
    type Future = ::futures::future::MapOk<
        ::futures::future::Ready<Result<Self, Self::Error>>,
        FnOnce(RealSessionRepository) -> Box<(dyn SessionRepository + 'static)>,
    >;
    type Config = ();

    fn from_request(
        req: &::actix_web::HttpRequest,
        payload: &mut actix_web::dev::Payload,
    ) -> Self::Future {
        RealSessionRepository::from_request(&req, payload).map_ok(|dep| Box::new(dep))
    }
}

gives the following set of error messages:

error[E0277]: the size for values of type `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)` cannot be known at compilation time
  --> api-server\src\db\sessions.rs:32:6
   |
32 | impl ::actix_web::FromRequest for Box<dyn SessionRepository> {
   |      ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::future::try_future::map_ok::MapOk<futures_util::future::ready::Ready<std::result::Result<std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>, actix_web::Error>>, (dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)>`

error[E0277]: expected a `std::ops::FnOnce<(std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>,)>` closure, found `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
  --> api-server\src\db\sessions.rs:32:6
   |
32 | impl ::actix_web::FromRequest for Box<dyn SessionRepository> {
   |      ^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>,)>` closure, found `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
   |
   = help: the trait `std::ops::FnOnce<(std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>,)>` is not implemented for `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
   = note: required because of the requirements on the impl of `core::future::future::Future` for `futures_util::future::try_future::map_ok::MapOk<futures_util::future::ready::Ready<std::result::Result<std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)>, actix_web::Error>>, (dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)>`

error[E0277]: the size for values of type `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)` cannot be known at compilation time
  --> api-server\src\db\sessions.rs:34:5
   |
34 | /     type Future = ::futures::future::MapOk<
35 | |         ::futures::future::Ready<Result<Self, Self::Error>>,
36 | |         FnOnce(RealSessionRepository) -> Box<(dyn SessionRepository + 'static)>,
37 | |     >;
   | |______^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `futures_util::future::try_future::map_ok::MapOk`

error[E0277]: the size for values of type `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)` cannot be known at compilation time
  --> api-server\src\db\sessions.rs:40:5
   |
40 | /     fn from_request(
41 | |         req: &::actix_web::HttpRequest,
42 | |         payload: &mut actix_web::dev::Payload,
43 | |     ) -> Self::Future {
44 | |         RealSessionRepository::from_request(&req, payload).map_ok(|dep| Box::new(dep))
45 | |     }
   | |_____^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce(db::sessions::RealSessionRepository) -> std::boxed::Box<(dyn db::sessions::SessionRepository + 'static)> + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: required by `futures_util::future::try_future::map_ok::MapOk`

MRE is available at: https://github.com/zlepper/actix_web_mre since it requires actix, which is not available on the rust playground.

This is specially about how to handle this when i want a dynamic trait reference, in an associated type, which I do not own, and thus can't do a lot about changing. More specifically, how would i do it with an FnOnce, where the actual implementation is only generated at compile time (I would think).

I know I can shorten the type definitions slightly so they are not fully qualified, however this is something I would like to generate using a macro, so as far as I know it is better to use the full types.

Is there a better way to type out the return future? The current definition is quite hairy..

Rasmus Hansen
  • 1,502
  • 1
  • 17
  • 28
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Jan 03 '20 at 16:10
  • It looks like your question might be answered by the answers of [How do I return an instance of a trait from a method?](https://stackoverflow.com/q/30661046/155423); [Why can impl trait not be used to return multiple / conditional types?](https://stackoverflow.com/q/52001592/155423); [Is it possible to use `impl Trait` as a function's return type in a trait definition?](https://stackoverflow.com/q/39482131/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jan 03 '20 at 16:16
  • MRE created at https://github.com/zlepper/actix_web_mre – Rasmus Hansen Jan 03 '20 at 16:21
  • [To make Stack Overflow a useful resource for future visitors beyond the context of your repository](https://meta.stackoverflow.com/q/380194/155423), please [edit] your question to add a [MRE] in the question itself, in addition to the link to your repository. – Shepmaster Jan 03 '20 at 16:23
  • Please calm down with all that. I'm working on that, i can only type so fast :) – Rasmus Hansen Jan 03 '20 at 16:25

1 Answers1

1

FnOnce is a trait and as such doesn't have a known size at compile time. However we can wrap it in a Box, which has a known size, to make it compile:

impl ::actix_web::FromRequest for Box<dyn SessionRepository> {
    type Error = ::actix_web::Error;
    type Future = ::futures::future::MapOk<
        ::futures::future::Ready<Result<RealSessionRepository, Self::Error>>,
        Box<dyn FnOnce(RealSessionRepository) -> Box<(dyn SessionRepository)>>,
    >;
    type Config = ();

    fn from_request(
        req: &::actix_web::HttpRequest,
        payload: &mut actix_web::dev::Payload,
    ) -> Self::Future {
        RealSessionRepository::from_request(&req, payload).map_ok(Box::new(|dep| Box::new(dep)))
    }
}
Rasmus Hansen
  • 1,502
  • 1
  • 17
  • 28
Fazer
  • 32
  • 5