19 releases
0.1.77 | Jan 3, 2024 |
---|---|
0.1.75 | Dec 28, 2023 |
0.1.74 | Oct 15, 2023 |
0.1.72 | Jul 24, 2023 |
0.1.58 | Oct 19, 2022 |
#37 in #heap-memory
56KB
1K
SLoC
async-trait-fn
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
orunboxed_simple
attribute is ofimpl Future<..>
instead ofBox<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
~225–660KB
~16K SLoC