embassy_executor/
lib.rs

1#![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)]
2#![allow(clippy::new_without_default)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6//! ## Feature flags
7#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
9// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt;
11
12pub use embassy_executor_macros::task;
13
14macro_rules! check_at_most_one {
15    (@amo [$($feats:literal)*] [] [$($res:tt)*]) => {
16        #[cfg(any($($res)*))]
17        compile_error!(concat!("At most one of these features can be enabled at the same time:", $(" `", $feats, "`",)*));
18    };
19    (@amo $feats:tt [$curr:literal $($rest:literal)*] [$($res:tt)*]) => {
20        check_at_most_one!(@amo $feats [$($rest)*] [$($res)* $(all(feature=$curr, feature=$rest),)*]);
21    };
22    ($($f:literal),*$(,)?) => {
23        check_at_most_one!(@amo [$($f)*] [$($f)*] []);
24    };
25}
26check_at_most_one!(
27    "arch-avr",
28    "arch-cortex-m",
29    "arch-cortex-ar",
30    "arch-riscv32",
31    "arch-std",
32    "arch-wasm",
33    "arch-spin",
34);
35
36#[cfg(feature = "_arch")]
37#[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")]
38#[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")]
39#[cfg_attr(feature = "arch-cortex-ar", path = "arch/cortex_ar.rs")]
40#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")]
41#[cfg_attr(feature = "arch-std", path = "arch/std.rs")]
42#[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")]
43#[cfg_attr(feature = "arch-spin", path = "arch/spin.rs")]
44mod arch;
45
46#[cfg(feature = "_arch")]
47#[allow(unused_imports)] // don't warn if the module is empty.
48pub use arch::*;
49#[cfg(not(feature = "_arch"))]
50pub use embassy_executor_macros::main_unspecified as main;
51
52pub mod raw;
53
54mod spawner;
55pub use spawner::*;
56
57/// Implementation details for embassy macros.
58/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
59#[doc(hidden)]
60#[cfg(not(feature = "nightly"))]
61pub mod _export {
62    use core::cell::UnsafeCell;
63    use core::future::Future;
64    use core::mem::MaybeUninit;
65
66    use crate::raw::TaskPool;
67
68    trait TaskReturnValue {}
69    impl TaskReturnValue for () {}
70    impl TaskReturnValue for Never {}
71
72    #[diagnostic::on_unimplemented(
73        message = "task futures must resolve to `()` or `!`",
74        note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
75    )]
76    #[allow(private_bounds)]
77    pub trait TaskFn<Args>: Copy {
78        type Fut: Future<Output: TaskReturnValue> + 'static;
79    }
80
81    macro_rules! task_fn_impl {
82        ($($Tn:ident),*) => {
83            impl<F, Fut, $($Tn,)*> TaskFn<($($Tn,)*)> for F
84            where
85                F: Copy + FnOnce($($Tn,)*) -> Fut,
86                Fut: Future<Output: TaskReturnValue> + 'static,
87            {
88                type Fut = Fut;
89            }
90        };
91    }
92
93    task_fn_impl!();
94    task_fn_impl!(T0);
95    task_fn_impl!(T0, T1);
96    task_fn_impl!(T0, T1, T2);
97    task_fn_impl!(T0, T1, T2, T3);
98    task_fn_impl!(T0, T1, T2, T3, T4);
99    task_fn_impl!(T0, T1, T2, T3, T4, T5);
100    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6);
101    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7);
102    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
103    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
104    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
105    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
106    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
107    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
108    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
109    task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
110
111    #[allow(private_bounds)]
112    #[repr(C)]
113    pub struct TaskPoolHolder<const SIZE: usize, const ALIGN: usize>
114    where
115        Align<ALIGN>: Alignment,
116    {
117        data: UnsafeCell<[MaybeUninit<u8>; SIZE]>,
118        align: Align<ALIGN>,
119    }
120
121    unsafe impl<const SIZE: usize, const ALIGN: usize> Send for TaskPoolHolder<SIZE, ALIGN> where Align<ALIGN>: Alignment {}
122    unsafe impl<const SIZE: usize, const ALIGN: usize> Sync for TaskPoolHolder<SIZE, ALIGN> where Align<ALIGN>: Alignment {}
123
124    #[allow(private_bounds)]
125    impl<const SIZE: usize, const ALIGN: usize> TaskPoolHolder<SIZE, ALIGN>
126    where
127        Align<ALIGN>: Alignment,
128    {
129        pub const fn get(&self) -> *const u8 {
130            self.data.get().cast()
131        }
132    }
133
134    pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
135    where
136        F: TaskFn<Args, Fut = Fut>,
137        Fut: Future + 'static,
138    {
139        size_of::<TaskPool<Fut, POOL_SIZE>>()
140    }
141
142    pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
143    where
144        F: TaskFn<Args, Fut = Fut>,
145        Fut: Future + 'static,
146    {
147        align_of::<TaskPool<Fut, POOL_SIZE>>()
148    }
149
150    pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
151    where
152        F: TaskFn<Args, Fut = Fut>,
153        Fut: Future + 'static,
154    {
155        TaskPool::new()
156    }
157
158    #[allow(private_bounds)]
159    #[repr(transparent)]
160    pub struct Align<const N: usize>([<Self as Alignment>::Archetype; 0])
161    where
162        Self: Alignment;
163
164    trait Alignment {
165        /// A zero-sized type of particular alignment.
166        type Archetype: Copy + Eq + PartialEq + Send + Sync + Unpin;
167    }
168
169    macro_rules! aligns {
170        ($($AlignX:ident: $n:literal,)*) => {
171            $(
172                #[derive(Copy, Clone, Eq, PartialEq)]
173                #[repr(align($n))]
174                struct $AlignX {}
175                impl Alignment for Align<$n> {
176                    type Archetype = $AlignX;
177                }
178            )*
179        };
180    }
181
182    aligns!(
183        Align1:         1,
184        Align2:         2,
185        Align4:         4,
186        Align8:         8,
187        Align16:        16,
188        Align32:        32,
189        Align64:        64,
190        Align128:       128,
191        Align256:       256,
192        Align512:       512,
193        Align1024:      1024,
194        Align2048:      2048,
195        Align4096:      4096,
196        Align8192:      8192,
197        Align16384:     16384,
198    );
199    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
200    aligns!(
201        Align32768:     32768,
202        Align65536:     65536,
203        Align131072:    131072,
204        Align262144:    262144,
205        Align524288:    524288,
206        Align1048576:   1048576,
207        Align2097152:   2097152,
208        Align4194304:   4194304,
209        Align8388608:   8388608,
210        Align16777216:  16777216,
211        Align33554432:  33554432,
212        Align67108864:  67108864,
213        Align134217728: 134217728,
214        Align268435456: 268435456,
215        Align536870912: 536870912,
216    );
217
218    #[allow(dead_code)]
219    pub trait HasOutput {
220        type Output;
221    }
222
223    impl<O> HasOutput for fn() -> O {
224        type Output = O;
225    }
226
227    #[allow(dead_code)]
228    pub type Never = <fn() -> ! as HasOutput>::Output;
229}
230
231/// Implementation details for embassy macros.
232/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
233#[doc(hidden)]
234#[cfg(feature = "nightly")]
235pub mod _export {
236    #[diagnostic::on_unimplemented(
237        message = "task futures must resolve to `()` or `!`",
238        note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
239    )]
240    pub trait TaskReturnValue {}
241    impl TaskReturnValue for () {}
242    impl TaskReturnValue for Never {}
243
244    #[allow(dead_code)]
245    pub trait HasOutput {
246        type Output;
247    }
248
249    impl<O> HasOutput for fn() -> O {
250        type Output = O;
251    }
252
253    #[allow(dead_code)]
254    pub type Never = <fn() -> ! as HasOutput>::Output;
255}