(feat) make crate #![no_std] compatible
(docs) add LICENSE file
(docs) some documentation & readme updates
This crate allows you to allocate a future inside of an allocator and pass it
around as if it were a trait object. (i.e. a Box<dyn Future>
) This crate is
inspired by stackfuture, but instead of storing the future on the
stack it stores the future on an arbitrary heap using the (unstable) Allocator
trait.
We also jettison a lot of the concerns about compile time generic sizes, as
well as allocation requirements: since the Allocator-crate will get the
layout of F
and handle alignment for us. It also allows dynamic allocation,
so we don't really care how large F
is. (It should fail similarly to if you
tried to heap-allocate a future and ran out of memory, i.e. panic...)
I'm not super-sure this is sound. This is non-trivial to do, without unsafe, due
to pinned allocated boxes requiring a 'static
lifetime.
That being said the only place we create a Pin
is in a context where we
were already pinned. Listen if rustc
is happy, I'm happy. I just made this
crate so I can store futures in a non-global allocator on an embedded system.
(Where the rules are made up, and everything I say goes.)
The allocator API has a lot of fallible allocation methods, I plan to support these to allow runtime handling of failed allocations, but currently have no reason to since my own allocator does not bubble up that information.
Probably write some tests. However most of the tests I can think of are "compile-fail" style tests, so I need to research how to make that sort of test-harness.
Add this to your Cargo.toml
like so:
[dependencies]
scope-future = "0.1"
Then use it as follows:
// inside #[tokio::main], for example ...
// create an allocator w/ your favorite crate
let mut arena = VmArena::with_capacity(1 * 4096);
// create some futures which store their continuations in our arena!
let a = ScopeFuture::wrap_in(async { ... }, &arena);
let b = ScopeFuture::wrap_in(async { ... }, &arena);
let c = ScopeFuture::wrap_in(async { ... }, &arena);
// We join all the futures, finishing their borrow of the arena
let (a, b, c) = futures::join!(a,b,c);
println!("({},{},{})", a, b, c);
// You can't call `#reset` until `a/b/c` either gets dropped or awaited.
// If you move this before `future::join!(...)` it won't compile, nifty :-)
VmArena::reset(&mut arena);