How to save `Foo<F>` as a field in a `struct` where `F` is a dynamically sized type?

For example, if F is a Fn trait: playground

There is no way we could write something like this as the size is unknown at the compile time:

struct RW {
    func: Func<Fn(Task) -> Future<Output = std::result::Result<Done, RWError>>>,
    sized: Sized<i32>,
}

How to work around it?

Edit: playground link

1 Like

To share your playground, click Share in the upper-right and then copy the Permalink. (Your current link just goes to the base page, which loads up whatever was in the editor last time for each individual visitor.)

I'm sorry. It's fixed.

In general, you put unsized things in a Box. For trait objects in particular, that's generally spelled Box<dyn Trait>, or as needed, Box<dyn Trait + Send + Sync> or the like. For Futures on top of that, you typically want a Pin<Box<dyn Future + Send>>.

So altogether here, you could do something like

type DoSomething = Pin<Box<
    dyn Future<Output = std::result::Result<Done, RWError>> + Send
>>;

struct RW {
    func: Func<Box<dyn Fn(Task) -> DoSomething>>,
    sized: Sized<i32>,
}

If you want to leave fn do_something as-is, you'll need to wrap it up in something (e.g. a closure) that boxes its return value.

    fn new() -> RW {
        let inner: Box<dyn Fn(_) -> _> = Box::new(|task| {
            let fut: DoSomething = Box::pin(do_something(task));
            fut
        });
        let func = Func::new(inner);
        let sized = Sized::new(42);
        RW { func, sized }
    }

(The type ascription here is to coerce to dyn objects during the process of constructing the RW.)

Depending on what exactly you need to do, you may have to tweak this, but hopefully it helps.

Playground.

2 Likes
let inner: Box<dyn Fn(_) -> _> = Box::new(|task| {
      let fut: DoSomething = Box::pin(do_something(task));
      fut
});

Wow! This is such a nice way to get -> impl Future "pin-boxed".

I do get that we need to Box unsized things, but never knew that we could simply specify the type F as Box<dyn Fn(Task) -> DoSomething> where F is bounded by Fn(T) -> Fut. It is strange to me:

struct RW {
    func: Func<Box<dyn Fn(Task) -> DoSomething>>, // How?
    // -- snip --
}

I've tried something like this: playground. The gist is this line: impl Woof for Box<dyn Woof> {}.

So return to the previous example that we mentioned, can I say that Box<dyn Fn> implements Fn under the hood?

Yes. Box impls Fn. Doc

2 Likes

Oh! Thanks.