name_it/
lib.rs

1//! So, you have a nice `async fn` and you want to store a future it returns in
2//! a struct. There's no need for boxing or dynamic dispatch: you statically
3//! know the type. You just need to `#[name_it]`.
4//!
5//! ```rust
6//! # use name_it::name_it;
7//! # use futures::executor::block_on;
8//! # async fn do_something_very_async() {}
9//! #[name_it(Test)]
10//! async fn add(x: i32, y: i32) -> i32 {
11//!     do_something_very_async().await;
12//!     x + y
13//! }
14//!
15//! # fn main() {
16//! let foo: Test = add(2, 3);
17//! assert_eq!(block_on(foo), 5);
18//! # }
19//! ```
20#![doc = include_str!("../readme-parts/main.md")]
21#![no_std]
22// lint me harder
23#![forbid(non_ascii_idents)]
24#![deny(
25    future_incompatible,
26    keyword_idents,
27    elided_lifetimes_in_paths,
28    meta_variable_misuse,
29    noop_method_call,
30    pointer_structural_match,
31    unused_lifetimes,
32    unused_qualifications,
33    unsafe_op_in_unsafe_fn,
34    clippy::undocumented_unsafe_blocks,
35    clippy::wildcard_dependencies,
36    clippy::debug_assert_with_mut_call,
37    clippy::empty_line_after_outer_attr,
38    clippy::panic,
39    clippy::unwrap_used,
40    clippy::expect_used,
41    clippy::redundant_field_names,
42    clippy::rest_pat_in_fully_bound_structs,
43    clippy::unneeded_field_pattern,
44    clippy::useless_let_if_seq,
45    clippy::default_union_representation
46)]
47#![warn(clippy::pedantic)]
48// not that hard:
49#![allow(
50    // ideally all the functions must be optimized to nothing, which requires always inlining
51    clippy::inline_always,
52    // we don't actually export functions, so it's not needed
53    clippy::must_use_candidate,
54)]
55
56use core::{
57    future::Future,
58    marker::PhantomPinned,
59    mem::{ManuallyDrop, MaybeUninit},
60    pin::Pin,
61    task::{Context, Poll},
62};
63
64/// A way to name the return type of an async function. See [crate docs](crate)
65/// for more info.
66pub use name_it_macros::name_it;
67
68// Manual formatting looks better here
69#[rustfmt::skip]
70#[doc(hidden)]
71pub mod markers;
72
73// SAFETY: can only be implemented on functions returning `Self::Fut`
74#[doc(hidden)]
75pub unsafe trait FutParams {
76    type Fut: Future<Output = Self::Output>;
77    type Output;
78}
79
80#[doc(hidden)]
81pub use elain as _elain;
82
83#[doc(hidden)]
84// This function is never called, it's only a placeholder
85#[allow(clippy::panic)]
86pub fn any<T>(_: &str) -> T {
87    panic!()
88}
89
90#[doc(hidden)]
91#[macro_export]
92macro_rules! _produce_any {
93    ($f:ident $($xs:pat),*$(,)?) => {
94        $f(
95            $($crate::any(stringify!($xs))),*
96        )
97    }
98}
99
100#[doc(hidden)]
101#[macro_export]
102macro_rules! _name_it_inner {
103    ($v:vis type $name:ident = $func:ident($($underscores:tt)*) -> $ret:ty$(;)?) => {
104        #[repr(C)]
105        $v struct $name<'fut>
106        where
107            $crate::_elain::Align<{$crate::align_of_fut(&($func as fn($($underscores)*) -> _))}>: $crate::_elain::Alignment,
108        {
109            bytes: [::core::mem::MaybeUninit<u8>; $crate::size_of_fut(&($func as fn($($underscores)*) -> _))],
110            _alignment: $crate::_elain::Align<{$crate::align_of_fut(&($func as fn($($underscores)*) -> _))}>,
111            // FIXME: invariant is probably too strict
112            _lifetime: ::core::marker::PhantomData<&'fut mut &'fut mut ()>,
113            _markers: $crate::markers!($crate::_produce_any!($func $($underscores)*)),
114        }
115
116        impl<'fut> $name<'fut> {
117            #[doc(hidden)]
118            $v unsafe fn new(bytes: [::core::mem::MaybeUninit<u8>; $crate::size_of_fut(&($func as fn($($underscores)*) -> _))]) -> Self {
119                Self {
120                    bytes,
121                    _alignment: $crate::_elain::Align::NEW,
122                    _lifetime: ::core::marker::PhantomData,
123                    _markers: $crate::markers::Markers::new(),
124                }
125            }
126        }
127
128        impl<'fut> ::core::future::Future for $name<'fut> {
129            type Output = $ret;
130
131            fn poll(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) -> ::core::task::Poll<$ret> {
132                // SAFETY:
133                // 1. `::poll()` is safe since we're not lying about the type
134                // 2. `transmute()` is safe since the representation is the same
135                unsafe {
136                    $crate::poll(
137                        ::core::mem::transmute::<
138                            _, ::core::pin::Pin<&mut [::core::mem::MaybeUninit<u8>; $crate::size_of_fut(&($func as fn($($underscores)*) -> _))]>
139                        >(self),
140                        cx, $func as fn($($underscores)*) -> _
141                    )
142                }
143            }
144        }
145
146        impl<'fut> ::core::ops::Drop for $name<'fut> {
147            fn drop(&mut self) {
148                // SAFETY: this is the only `::dispose()` call and we're not lying about the type
149                unsafe {
150                    $crate::dispose(&mut self.bytes, ($func as fn($($underscores)*) -> _));
151                }
152            }
153        }
154    };
155}
156
157/// Wrapper type for named futures.
158///
159/// Type of your future will be something like
160/// ```rust,ignore
161/// type YourName<'fut> = Named</* implementation detail */>;
162/// ```
163#[repr(transparent)]
164pub struct Named<T> {
165    // Oh, we read this field, just not as you expected, poor rustc
166    #[allow(dead_code)]
167    inner: T,
168    _pinned: PhantomPinned,
169}
170
171impl<T> Named<T> {
172    #[doc(hidden)]
173    pub fn new(inner: T) -> Self {
174        Self {
175            inner,
176            _pinned: PhantomPinned,
177        }
178    }
179}
180
181impl<T> Future for Named<T>
182where
183    T: Future,
184{
185    type Output = T::Output;
186
187    #[inline]
188    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
189        // SAFETY: the representation is the same
190        unsafe { core::mem::transmute::<_, Pin<&mut T>>(self) }.poll(cx)
191    }
192}
193
194#[repr(C)]
195union Transmute<From, To> {
196    from: ManuallyDrop<From>,
197    to: ManuallyDrop<To>,
198}
199
200#[inline]
201#[doc(hidden)]
202pub unsafe fn transmute_generic<From, To>(val: From) -> To {
203    ManuallyDrop::into_inner(
204        // SAFETY: caller-guaranteed
205        unsafe {
206            Transmute::<From, To> {
207                from: ManuallyDrop::new(val),
208            }
209            .to
210        },
211    )
212}
213
214#[inline]
215#[doc(hidden)]
216pub unsafe fn poll<F: FutParams, const N: usize>(
217    this: Pin<&mut [MaybeUninit<u8>; N]>,
218    cx: &mut Context<'_>,
219    _: F,
220) -> Poll<F::Output> {
221    // SAFETY: `transmute_generic()` is safe because caller promised us that's the
222    // type inside
223    let fut = unsafe { transmute_generic::<Pin<&mut _>, Pin<&mut F::Fut>>(this) };
224    fut.poll(cx)
225}
226
227#[inline]
228#[doc(hidden)]
229pub unsafe fn dispose<F: FutParams, const N: usize>(this: &mut [MaybeUninit<u8>; N], _: F) {
230    // SAFETY: caller promised us that's the type inside
231    let fut = unsafe { transmute_generic::<&mut _, &mut MaybeUninit<F::Fut>>(this) };
232    // SAFETY: we're only calling this one time, in our `Drop`, and never use this
233    // after
234    unsafe { fut.assume_init_drop() };
235}
236
237#[doc(hidden)]
238pub const fn size_of_fut<F: FutParams>(_: &F) -> usize {
239    core::mem::size_of::<F::Fut>()
240}
241
242#[doc(hidden)]
243pub const fn align_of_fut<F: FutParams>(_: &F) -> usize {
244    core::mem::align_of::<F::Fut>()
245}
246
247macro_rules! impl_fut_params {
248    ($($t:ident $($ts:ident)*)?) => {
249        // SAFETY: we're implementing this for a function returning `Fut`
250        unsafe impl<$($t, $($ts,)*)? R, Fut> FutParams for fn($($t, $($ts,)*)?) -> Fut
251        where
252            Fut: Future<Output = R>
253        {
254            type Fut = Fut;
255            type Output = R;
256        }
257
258        $(impl_fut_params!($($ts)*);)?
259    };
260}
261
262impl_fut_params!(
263    T00 T01 T02 T03 T04 T05 T06 T07 T08 T09 T10 T11 T12 T13 T14 T15
264    T16 T17 T18 T19 T20 T21 T22 T23 T24 T25 T26 T27 T28 T29 T30 T31
265);