A wrapper around Rust futures that stores the future in space provided by the caller.

Overview

StackFuture

crates.io docs.rs

This crate defines a StackFuture wrapper around futures that stores the wrapped future in space provided by the caller. This can be used to emulate dynamic async traits without requiring heap allocation. Below is an example of how use StackFuture:

use stackfuture::*;

trait PseudoAsyncTrait {
    fn do_something(&self) -> StackFuture<'static, (), { 512 }>;
}

impl PseudoAsyncTrait for i32 {
    fn do_something(&self) -> StackFuture<'static, (), { 512 }> {
        StackFuture::from(async {
            // function body goes here
        })
    }
}

async fn use_dyn_async_trait(x: &dyn PseudoAsyncTrait) {
    x.do_something().await;
}

async fn call_with_dyn_async_trait() {
    use_dyn_async_trait(&42).await;
}

This is most useful for cases where async functions in dyn Trait objects are needed but storing them in a Box is not feasible. Such cases include embedded programming where allocation is not available, or in tight inner loops where the performance overhead for allocation is unacceptable. Note that doing this involves tradeoffs. In the case of StackFuture, you must set a compile-time limit on the maximum size of future that will be supported. If you need to support async functions in dyn Trait objects but these constraints do not apply to you, you may be better served by the async-trait crate.

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

Comments
  • Respect stacked borrows when polling

    Respect stacked borrows when polling

    Polling the wrapped future previously had several reborrow operations, such as in the use of map_unchecked_mut and in the implementation of as_mut_ptr. This caused issues when running under miri in the stress_drop_sender test.

    This change re-implements these problematic cases to avoid reborrows, either through using Pin::get_unchecked_mut or transmuting pointers rather than borrowing and casting.

    Fixes https://github.com/microsoft/stackfuture/issues/9

    opened by eholk 5
  • Make StackFuture::from fail statically if the future doesn't fit

    Make StackFuture::from fail statically if the future doesn't fit

    Thanks to @jstarks for the suggestion of how to do this!

    This also bumps the version in Cargo.toml to 0.3.0 since it's a breaking change now that StackFuture::from will fail to compile in cases where it would have panicked at runtime.

    opened by eholk 2
  • ci: Add check and clippy

    ci: Add check and clippy

    Signed-off-by: Xuanwo [email protected]

    This PR adds fmt, check and clippy for CI. I also added rust-toolchain.toml and rustfmt.toml to make our contributors' lives easier.

    Fix #4

    opened by Xuanwo 1
  • `.map_unchecked_mut()` is unsound for self-referential types

    `.map_unchecked_mut()` is unsound for self-referential types

    Hi! I’ve recently created a similar crate, but without dynamic dispatch and with automatic size calculation and Send/Sync inference, and found a problem with using .map_unchecked_mut() in .poll().

    This line:

    https://github.com/microsoft/stackfuture/blob/ae58939/src/lib.rs#L207

    causes a retag of the whole byte array, invalidating all internal references inside of a future. To prevent this, you should directly transmute Pin<&mut MaybeUninit[u8; _]> instead of mapping.

    This is a simple testcase that fails under Miri (adapted from futures-rs test suite):

    use futures::{
        channel::mpsc,
        executor::block_on,
        sink::SinkExt as _,
        stream::{Stream, StreamExt as _},
    };
    use stackfuture::StackFuture;
    use std::thread;
    
    #[test]
    fn stress_drop_sender() {
        const ITER: usize = if cfg!(miri) { 100 } else { 10000 };
    
        fn list() -> impl Stream<Item = i32> {
            let (tx, rx) = mpsc::channel(1);
            thread::spawn(move || {
                block_on(send_one_two_three(tx));
            });
            rx
        }
    
        for _ in 0..ITER {
            let v: Vec<_> = block_on(list().collect());
            assert_eq!(v, vec![1, 2, 3]);
        }
    }
    
    fn send_one_two_three(mut tx: mpsc::Sender<i32>) -> StackFuture<'static, (), 512> {
        StackFuture::from(async move {
            for i in 1..=3 {
                tx.send(i).await.unwrap();
            }
        })
    }
    
    opened by GoldsteinE 1
  • Add `IntoStackFutureError`

    Add `IntoStackFutureError`

    This is perhaps an over-designed error type, but it provides enough information to figure out why the conversion failed, which can help the programmer fix it.

    This PR also includes #20, so review that first and I'll merge that one and rebase this one before merging it.

    It would be nice to add a impl std::error::Error for IntoStackFutureError, but for now we are a no_std crate and I wasn't sure adding a no_std feature would be worth it just for that impl. I think the plan is for the Error trait to become part of core someday, so we could just wait until then.

    opened by eholk 0
  • Add from_or_boxed constructor

    Add from_or_boxed constructor

    This gives us a way to support any size future with a small value optimization. The from_or_boxed constructor attempts to store the wrapped future in StackFuture's reserved space, but if it cannot then it store the future in a box and wrap the box instead.

    Note that doing this requires adding an "alloc" feature so this crate can continue to be used in pure no_std environments.

    This also changes the panic behavior of try_from to not panic on alignment errors. To make it easier to determine why something went wrong, we make the has_*_for* functions public. We also adjust the panic messages in StackFuture::from to make it clear which conditions failed.

    Finally, we introduce a testing matrix for GitHub actions to make sure we run tests both with and without allocation.

    opened by eholk 0
  • Add a way to resize StackFutures

    Add a way to resize StackFutures

    It'd be helpful to have a way to shrink (or less commonly, grow) a StackFuture. For example, sometimes you have an object that implements a trait and needs to forward calls to another object that implements the same trait. Right now that's impossible with StackFuture without boxing the child future because otherwise you'd have to have a future contain a future that's the same size as itself. That said, there will usually be some extra space so we might be able to dynamically shrink a StackFuture.

    The signature would probably be something like:

    fn resize<const NEW_SIZE: usize>(self) -> Result<StackFuture<T, NEW_SIZE>, Self>;
    

    Then using this would look something like:

    impl Foo for MyObject {
        fn bar(&self) -> StackFuture<(), 1000> {
            match self.sub_object.bar().resize::<{500}>() {
                Ok(f) => f.await,
                Err(original) => Box::pin(original).await,
            }
        }
    }
    

    The idea here is we'd try to fit the future into a smaller container, but if it doesn't fit then the resize returns the original future and we can either decide to pay the allocation cost (as we did in this example) or give up.

    opened by eholk 5
  • Add proc macro for converting async traits to return StackFutures

    Add proc macro for converting async traits to return StackFutures

    The idea here is to make a macro similar to the #[async_trait] one from the async trait crate. Using it would look something like this:

    #[stackfuture::async_trait(4096)]
    trait Foo {
        async fn bar(&self) -> i32;
    }
    

    The macro would then expand to something like (along with whatever lifetime annotations are needed:

    trait Foo {
        fn bar(&self) -> StackFuture<i32, { 4096 }>`;
    }
    

    We'd do a similar thing for impls as well.

    enhancement 
    opened by eholk 1
Releases(v0.3.0)
  • v0.3.0(Nov 17, 2022)

    What's Changed

    • Update badges by @eholk in https://github.com/microsoft/stackfuture/pull/18
    • Add comment explaining why we don't impl From for Stackfuture by @eholk in https://github.com/microsoft/stackfuture/pull/19
    • Make StackFuture::from fail statically if the future doesn't fit by @eholk in https://github.com/microsoft/stackfuture/pull/20
    • Add IntoStackFutureError by @eholk in https://github.com/microsoft/stackfuture/pull/21

    Full Changelog: https://github.com/microsoft/stackfuture/compare/v0.2.0...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Sep 7, 2022)

    What's Changed

    • Add try_from constructor by @eholk in https://github.com/microsoft/stackfuture/pull/16
    • Add from_or_boxed constructor by @eholk in https://github.com/microsoft/stackfuture/pull/17

    Full Changelog: https://github.com/microsoft/stackfuture/compare/v0.1.1...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Aug 16, 2022)

  • v0.1.0(Aug 10, 2022)

    We are pleased to announce the first release of StackFuture. StackFuture is a wrapper around futures that allows you to store them in space provided by the caller. It can be used to emulate async functions in dynamic trait objects without requiring heap allocation. In some circumstances, this can provide a significant performance improvement.

    What's Changed

    • Initial code export by @eholk in https://github.com/microsoft/stackfuture/pull/1
    • Enable basic Rust CI support by @eholk in https://github.com/microsoft/stackfuture/pull/2
    • Add miri CI job by @eholk in https://github.com/microsoft/stackfuture/pull/3
    • Add description and repository fields to Cargo.toml by @eholk in https://github.com/microsoft/stackfuture/pull/7

    New Contributors

    • @eholk made their first contribution in https://github.com/microsoft/stackfuture/pull/1

    Full Changelog: https://github.com/microsoft/stackfuture/commits/v0.1.0

    Source code(tar.gz)
    Source code(zip)
Owner
Microsoft
Open source projects and samples from Microsoft
Microsoft
c-library wrapper around the rust pdb crate

pdbcrust: pdbcrust is a c-library wrapper around the rust pdb crate. The API only exports a minimum subset of the pdb crate functionality. The project

Ulf Frisk 7 Feb 23, 2023
Messing around with delimited continuations, fibers, and algebraic effects

A Simple Virtual Machine with Effects Each thread of execution in this VM is called a Fiber. A Fiber is unique, can be sent between threads, but can n

Isaac Clayton 8 Jun 23, 2022
A simplistic functional programming language based around Lisp syntax.

Orchid A simplistic functional programming language based around Lisp syntax. Short taste # function to return the larger list (fn larger-list (as bs)

rem 3 May 7, 2022
Rust wrapper for `os-release`

os-release-rs Rust wrapper for /etc/os-release file. Installation Add this to your Cargo.toml: [dependencies] os-release-rs = "0.1.0" Usage use os_rel

0xMRTT 2 Nov 11, 2022
Safe MMDeploy Rust wrapper.

Introduction Safe MMDeploy Rust wrapper. News (2022.9.29) This repo has been added into the OpenMMLab ecosystem. (2022.9.27) This repo has been added

Mengyang Liu 14 Dec 15, 2022
Rust wrapper for the LeapC Ultraleap (Leap Motion) hand tracking device API.

LeapRS LeapRS is a safe wrapper for LeapC, the Leap Motion C API. It uses the generated binding provided by leap-sys. This is an API for accessing Lea

Pierre Lulé 4 Oct 10, 2022
This is for aquestalk1 rust wrapper.

aquestalk-rs This is for aquestalk1 rust wrapper. 読み上げに使用する際 aquestalkを使ってDiscord読み上げbotなどを作成する場合aquestalkに問い合わせして、サーバー用ライセンスの購入が必須です。 Installation [d

KuronekoServer 2 Nov 16, 2022
A asynchronous implementation of the invidious innertube aka youtubei API wrapper

A asynchronous implementation of the invidious innertube aka youtubei API wrapper. Using tokio,reqwest, serde and serde_json

11Tuvork28 11 Dec 22, 2022
A rocksdb.rs wrapper bringing stack and queue functionalities

RocksDB_sq (Stack & Queue) A Rust crate that adds stack and queue functionality to RocksDB. This crate provide a wrapper around a RocksDB database and

Nathan GD 5 May 16, 2023
A shit dAPI wrapper.

Shit dAPI wrapper A Blazingly Fast (??????) discord API wrapper so shit it makes your bot say shit uncontrollably. usage: clone this repo and change t

Enoki 5 Jun 12, 2022
Leetcode Solutions in Rust, Advent of Code Solutions in Rust and more

RUST GYM Rust Solutions Leetcode Solutions in Rust AdventOfCode Solutions in Rust This project demostrates how to create Data Structures and to implem

Larry Fantasy 635 Jan 3, 2023
Simple autoclicker written in Rust, to learn the Rust language.

RClicker is an autoclicker written in Rust, written to learn more about the Rust programming language. RClicker was was written by me to learn more ab

null 7 Nov 15, 2022
Rust programs written entirely in Rust

mustang Programs written entirely in Rust Mustang is a system for building programs built entirely in Rust, meaning they do not depend on any part of

Dan Gohman 561 Dec 26, 2022
Rust 核心库和标准库的源码级中文翻译,可作为 IDE 工具的智能提示 (Rust core library and standard library translation. can be used as IntelliSense for IDE tools)

Rust 标准库中文版 这是翻译 Rust 库 的地方, 相关源代码来自于 https://github.com/rust-lang/rust。 如果您不会说英语,那么拥有使用中文的文档至关重要,即使您会说英语,使用母语也仍然能让您感到愉快。Rust 标准库是高质量的,不管是新手还是老手,都可以从中

wtklbm 493 Jan 4, 2023
A library for extracting #[no_mangle] pub extern "C" functions (https://docs.rust-embedded.org/book/interoperability/rust-with-c.html#no_mangle)

A library for extracting #[no_mangle] pub extern "C" functions In order to expose a function with C binary interface for interoperability with other p

Dmitrii - Demenev 0 Feb 17, 2022
clone of grep cli written in Rust. From Chapter 12 of the Rust Programming Language book

minigrep is a clone of the grep cli in rust Minigrep will find a query string in a file. To test it out, clone the project and run cargo run body poem

Raunak Singh 1 Dec 14, 2021
Rust-blog - Educational blog posts for Rust beginners

pretzelhammer's Rust blog ?? I write educational content for Rust beginners and Rust advanced beginners. My posts are listed below in reverse chronolo

kirill 5.2k Jan 1, 2023
The ray tracer challenge in rust - Repository to follow my development of "The Raytracer Challenge" book by Jamis Buck in the language Rust

The Ray Tracer Challenge This repository contains all the code written, while step by implementing Ray Tracer, based on the book "The Ray Tracer Chall

Jakob Westhoff 54 Dec 25, 2022
Learn-rust-the-hard-way - "Learn C The Hard Way" by Zed Shaw Converted to Rust

Learn Rust The Hard Way This is an implementation of Zed Shaw's Learn X The Hard Way for the Rust Programming Language. Installing Rust TODO: Instruct

Ryan Levick 309 Dec 8, 2022