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#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
9
10pub(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)] pub use platform::*;
52
53pub mod raw;
54
55mod spawner;
56pub use spawner::*;
57
58mod metadata;
59pub use metadata::*;
60
61#[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 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#[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}