Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bumpalo's Box does not seem to work with dyn Future #82

Open
rw opened this issue Aug 15, 2020 · 4 comments
Open

Bumpalo's Box does not seem to work with dyn Future #82

rw opened this issue Aug 15, 2020 · 4 comments

Comments

@rw
Copy link

rw commented Aug 15, 2020

To reduce memory allocations, I'm trying to use bumpalo to create my own Boxed futures type.

I'm basing this off of an idiom present in the futures crate:

type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>;

https://docs.rs/futures/0.3.5/futures/future/type.BoxFuture.html

When I try this with bumpalo::boxed::Box, however, it seems that I can't convert an impl Future into a dyn Future the same way that I can with std::boxed::Box.

Here is some example code demonstrating the issue (I wish the playground had bumpalo!):

use std::future::Future;
use std::pin::Pin;

/// This compiles:
fn f(
    fut: impl Future<Output = ()> + Send + 'static,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
    Box::pin(fut)
}

// This does not compile:
// fn g<'a>(
//     b: &'a bumpalo::Bump,
//     fut: impl Future<Output = ()> + Send + 'static,
// ) -> Pin<bumpalo::boxed::Box<'a, dyn Future<Output = ()> + Send + 'static>> {
//     bumpalo::boxed::Box::pin_in(fut, &b)
// }

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=80eeec8261dc28169cfc968525ed7e43

Is there something I'm missing with how to use this library? Thank you!

@fitzgen
Copy link
Owner

fitzgen commented Aug 17, 2020

I think that the standard library Box is special cased by the language here.

You should be able to create a &mut dyn Future from a &mut MyFuture that was allocated in a bump.

And if we had a public, unsafe constructor for bumpalo::boxed::Box that took a &mut then you could do

  • allocate a MyFuture in the bump, resulting in a &mut MyFuture
  • convert &mut MyFuture to &mut dyn Future
  • unsafely construct a bumpalo::boxed::Box from the &mut dyn Future

You would probably want to wrap that up in a method (unfortunately, I don't think the type system can express this generically, so we can't do it in this crate).

I think an unsafe constructor is reasonable to support, so if you want to open a PR, I can review+merge it.

@rw
Copy link
Author

rw commented Aug 29, 2020

@fitzgen Would the function look like this?

impl<'a, T: ?Sized> Box<'a, T> {
    #[inline]
    pub unsafe fn from_mut(x: &mut T) -> Self {
        Box(x)
    }

or

impl<'a, T: ?Sized> Box<'a, T> {
    #[inline]
    pub unsafe fn from_mut(x: &mut T) -> Self {
        Box(&mut *x)
    }

@fitzgen
Copy link
Owner

fitzgen commented Sep 1, 2020

It would look like the first, but additionally the parameter would use the 'a lifetime: x: &'a mut T

@ColonelThirtyTwo
Copy link

ColonelThirtyTwo commented Oct 22, 2020

std::boxed::Box implements CoerceUnsized which is a nightly-only trait for doing this. You can fake it with unsafe { BumpaloBox::from_raw(BumpaloBox::into_raw(node) as *mut dyn Whatever) }, or by the above additional function...

However it doesn't work too well. The fact that Box is just a wrapper for a &'a mut T causes a lot of issues with trait object invariance. You need to use raw pointers like the real Box to make it function properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants