Skip to main content

embassy_executor/
lib.rs

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