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#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
8
9pub(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)] pub 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#[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 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#[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}