#async

macro no-std async-trait-fn

A fork of async-trait with some useful options

8 releases

new 0.1.64 Jan 31, 2023
0.1.63 Jan 23, 2023
0.1.60 Dec 18, 2022
0.1.58 Oct 19, 2022
0.1.57 Aug 18, 2022

#114 in Asynchronous

Download history 10275/week @ 2022-10-12 12228/week @ 2022-10-19 10686/week @ 2022-10-26 8637/week @ 2022-11-02 5342/week @ 2022-11-09 4191/week @ 2022-11-16 5920/week @ 2022-11-23 5022/week @ 2022-11-30 6961/week @ 2022-12-07 4428/week @ 2022-12-14 5178/week @ 2022-12-21 4528/week @ 2022-12-28 6578/week @ 2023-01-04 5633/week @ 2023-01-11 4363/week @ 2023-01-18 4618/week @ 2023-01-25

22,031 downloads per month

MIT/Apache

54KB
1K SLoC

async-trait-fn

Cargo Crates.io

This is a fork of the widely acclaimed async-trait crate. This crate adds two experimental attributes to async-trait that can be applied to asynchronous trait methods and associated functions to avoid heap memory allocation.

  • The return type of an asynchronous trait method or associated function with the unboxed or unboxed_simple attribute is of impl Future<..> instead of Box<dyn Future<..>>.
  • Those attributes have a lot of limitations when used in a large software product due to known bugs in Rust generic associated types: e.g., 95719 and 90696.

Note that, the main author of async-trait did not want to add such options, therefore this fork will not be merged into the upstream.

See async-trait for more details about async-trait.

Examples

unboxed turns an asynchronous trait method or associated function into a synchronous one returning an impl Future<..> by adding a generic associated type for the method or associated function.

use async_trait_fn::{async_trait, unboxed_simple};

#[async_trait]
pub trait SelfToUsize {
    #[unboxed]
    async fn get(&self) -> usize;
}

#[async_trait]
impl SelfToUsize for u32 {
    #[unboxed]
    async fn get(&self) -> usize {
        *self as usize
    }
}

The compiler generates the following code.

pub trait SelfToUsize {
    fn get<'life0, 'async_trait>(&'life0 self) -> Self::RetTypeOfGet<'life0, 'async_trait>
    where
        'life0: 'async_trait,
        Self: 'async_trait;
    type RetTypeOfGet<'life0, 'async_trait>: ::core::future::Future<Output = usize>
        + ::core::marker::Send
        + 'async_trait
    where
        'life0: 'async_trait,
        Self: 'async_trait,
        Self: 'life0;
}

impl SelfToUsize for u32 {
    fn get<'life0, 'async_trait>(&'life0 self) -> Self::RetTypeOfGet<'life0, 'async_trait>
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        async move {
            if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<usize> {
                return __ret;
            }
            let __self = self;
            let __ret: usize = { *__self as usize };
            #[allow(unreachable_code)]
            __ret
        }
    }
    type RetTypeOfGet<'life0, 'async_trait> = impl ::core::future::Future<Output = usize>
        + ::core::marker::Send
        + 'async_trait
    where
        'life0: 'async_trait,
        Self: 'async_trait,
        Self: 'life0 ;
}

unboxed_simple is identical to unboxed except that it substitutes all the lifetime bounds and parameters with a single, fixed lifetime: 'async_trait. When code around an unboxed attribute does not compile, unboxed_simple might help.

use async_trait_fn::{async_trait, unboxed_simple};

#[async_trait]
pub trait AddOther {
    #[unboxed_simple]
    async fn add<'s, 'o>(&'a self, other: &'o usize) -> usize;
}

#[async_trait]
impl AddOther for u32 {
    #[unboxed_simple]
    async fn add<'s, 'o>(&'a self, other: &'o usize) -> usize {
        (*self as usize) + *other
    }
}

The above code expands to the following code; all the lifetime parameters are replaced with 'async_trait.

pub trait AddOther {
    fn add<'async_trait>(
        &'async_trait self,
        other: &'async_trait usize,
    ) -> Self::RetTypeOfAdd<'async_trait>
    where
        Self: 'async_trait;
    type RetTypeOfAdd<'async_trait>: ::core::future::Future<Output = usize>
        + ::core::marker::Send
        + 'async_trait
    where
        Self: 'async_trait,
        Self: 'async_trait;
}

impl AddOther for u32 {
    fn add<'async_trait>(
        &'async_trait self,
        other: &'async_trait usize,
    ) -> Self::RetTypeOfAdd<'async_trait>
    where
        Self: 'async_trait,
    {
        async move {
            if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<usize> {
                return __ret;
            }
            let __self = self;
            let other = other;
            let __ret: usize = { (*__self as usize) + *other };
            #[allow(unreachable_code)]
            __ret
        }
    }
    type RetTypeOfAdd<'async_trait> = impl ::core::future::Future<Output = usize>
        + ::core::marker::Send
        + 'async_trait
    where
        Self: 'async_trait,
        Self: 'async_trait;
}

Dependencies

~195–590KB
~14K SLoC