product_os_async_executor/lib.rs
1//! # Product OS : Async Executor
2//!
3//! Product OS : Async Executor provides a set of tools to handle async execution generically
4//! so that the desired async library (e.g. tokio, smol, async-std) can be chosen at compile time.
5//!
6//! ## Features
7//!
8//! - **Generic Executor Traits**: Define common interfaces for working with different async runtimes
9//! - **Runtime Support**: Out-of-the-box support for Tokio, Smol, and Async-std
10//! - **Timer Support**: One-time and interval timers that work across runtimes
11//! - **Async I/O Traits**: `AsyncRead` and `AsyncWrite` traits for cross-runtime I/O
12//! - **No-std Support**: Works in `no_std` environments with alloc
13//!
14//! ## Examples
15//!
16//! ### Using with Tokio
17//!
18//! ```rust,no_run
19//! # #[cfg(feature = "exec_tokio")]
20//! # {
21//! use product_os_async_executor::{Executor, ExecutorPerform, TokioExecutor};
22//!
23//! #[tokio::main]
24//! async fn main() {
25//! // Create an executor context
26//! let executor = TokioExecutor::context().await.unwrap();
27//!
28//! // Spawn a task
29//! let result = TokioExecutor::spawn_in_context(async {
30//! 42
31//! }).await;
32//!
33//! assert!(result.is_ok());
34//! }
35//! # }
36//! ```
37//!
38//! ### Using Timers
39//!
40//! ```rust,no_run
41//! # #[cfg(feature = "exec_tokio")]
42//! # {
43//! use product_os_async_executor::{Timer, TokioExecutor};
44//!
45//! #[tokio::main]
46//! async fn main() {
47//! let mut timer = TokioExecutor::interval(100).await;
48//! let _ = timer.tick().await; // Waits ~100ms
49//! }
50//! # }
51//! ```
52//!
53//! ## Feature Flags
54//!
55//! - `exec_tokio`: Enable Tokio executor support
56//! - `exec_smol`: Enable Smol executor support
57//! - `exec_async_std`: Enable Async-std executor support (deprecated)
58//! - `exec_embassy`: Enable Embassy executor support (embedded)
59//! - `moment`: Enable time abstraction utilities
60//! - `hyper_executor`: Enable Hyper executor integration
61//!
62#![no_std]
63#![warn(missing_docs)]
64#![warn(clippy::all)]
65#![warn(clippy::pedantic)]
66#![warn(clippy::nursery)]
67#![allow(clippy::module_name_repetitions)]
68#![allow(clippy::must_use_candidate)]
69#![allow(async_fn_in_trait)]
70
71extern crate alloc;
72
73#[cfg(feature = "exec_tokio")]
74mod tokio;
75#[cfg(feature = "exec_tokio")]
76pub use tokio::TokioExecutor;
77
78#[cfg(feature = "exec_smol")]
79mod smol;
80#[cfg(feature = "exec_smol")]
81pub use smol::SmolExecutor;
82
83#[cfg(feature = "exec_async_std")]
84mod async_std;
85#[cfg(feature = "exec_async_std")]
86#[allow(deprecated)]
87pub use async_std::AsyncStdExecutor;
88
89#[cfg(feature = "exec_embassy")]
90mod embassy;
91#[cfg(feature = "exec_embassy")]
92pub use embassy::EmbassyExecutor;
93
94/// Async read/write traits for cross-runtime I/O operations.
95///
96/// This module provides `AsyncRead` and `AsyncWrite` traits that work across
97/// different async runtimes, along with utilities for buffered I/O.
98pub mod read_write;
99
100/// Sleep trait for cross-runtime sleeping.
101///
102/// This module defines the `Sleep` trait which provides a runtime-agnostic
103/// interface for sleeping. It is intended to be implemented by downstream
104/// crates for their specific runtime.
105pub mod sleep;
106
107/// Time abstraction utilities for testable time operations.
108///
109/// The `Moment` struct allows you to abstract time operations, making it easier
110/// to test code that depends on the current time.
111pub mod moment;
112
113use alloc::boxed::Box;
114use alloc::sync::Arc;
115use core::future::Future;
116use core::pin::Pin;
117
118// Specific chrono re-exports for common types
119pub use chrono::Duration as ChronoDuration;
120pub use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
121
122/// Deprecated blanket re-export of the chrono crate.
123///
124/// Import chrono types directly from `chrono` or use the specific re-exports
125/// from this crate's root (e.g. `DateTime`, `Utc`, `ChronoDuration`).
126#[deprecated(
127 since = "0.0.19",
128 note = "Import chrono types directly from the `chrono` crate or use the specific re-exports (DateTime, Utc, ChronoDuration, etc.) from this crate's root."
129)]
130pub mod chrono_compat {
131 pub use chrono::*;
132}
133
134pub use read_write::IoSlice;
135
136/// Type alias for boxed error types that are Send + Sync.
137///
138/// This is used throughout the crate for error handling in async contexts.
139pub type BoxError = alloc::boxed::Box<dyn core::error::Error + Send + Sync>;
140
141/// Error type for spawn failures.
142///
143/// Returned when an executor is unable to spawn a task.
144#[derive(Debug)]
145pub struct SpawnError {
146 _private: (),
147}
148
149impl SpawnError {
150 /// Creates a new `SpawnError`.
151 pub const fn new() -> Self {
152 Self { _private: () }
153 }
154}
155
156impl Default for SpawnError {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162impl core::fmt::Display for SpawnError {
163 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164 write!(f, "failed to spawn task")
165 }
166}
167
168impl core::error::Error for SpawnError {}
169
170/// Trait for managing executor contexts across different async runtimes.
171///
172/// This trait provides a unified interface for creating, configuring, and accessing
173/// executor contexts regardless of the underlying async runtime (Tokio, Smol, etc.).
174///
175/// # Type Parameters
176///
177/// * `X` - The executor handle type specific to the runtime (e.g., `tokio::runtime::Handle`)
178///
179/// # Examples
180///
181/// ```rust,no_run
182/// # #[cfg(feature = "exec_tokio")]
183/// # {
184/// use product_os_async_executor::{Executor, TokioExecutor};
185///
186/// #[tokio::main]
187/// async fn main() {
188/// let executor = TokioExecutor::context().await.unwrap();
189/// executor.enter_context().await;
190/// }
191/// # }
192/// ```
193pub trait Executor<X>: Send + Sync {
194 /// Creates a new executor context asynchronously.
195 ///
196 /// # Errors
197 ///
198 /// Returns an error if the executor context cannot be created.
199 fn context() -> impl Future<Output = Result<Self, SpawnError>> + Send
200 where
201 Self: Sized;
202
203 /// Sets the executor context to the provided executor.
204 fn set_context(&mut self, executor: X) -> impl Future<Output = ()> + Send;
205
206 /// Enters the executor context.
207 ///
208 /// Note: For some runtimes (e.g. Tokio), the context guard is dropped immediately,
209 /// so this is primarily useful for runtimes that have global context state.
210 fn enter_context(&self) -> impl Future<Output = ()> + Send;
211
212 /// Gets a reference to the underlying executor.
213 fn get_executor<'a>(&'a self) -> impl Future<Output = &'a X> + Send
214 where
215 X: 'a;
216
217 /// Creates a new executor context synchronously.
218 ///
219 /// # Errors
220 ///
221 /// Returns an error if the executor context cannot be created.
222 fn context_sync() -> Result<Self, SpawnError>
223 where
224 Self: Sized;
225
226 /// Sets the executor context synchronously.
227 fn set_context_sync(&mut self, executor: X);
228
229 /// Enters the executor context synchronously.
230 ///
231 /// Note: For some runtimes (e.g. Tokio), the context guard is dropped immediately,
232 /// so this is primarily useful for runtimes that have global context state.
233 fn enter_context_sync(&self);
234
235 /// Gets a reference to the underlying executor synchronously.
236 fn get_executor_sync(&self) -> &X;
237}
238
239/// Trait for spawning and managing async tasks.
240///
241/// This trait provides methods for spawning tasks on an executor and blocking
242/// on futures. It complements the `Executor` trait by focusing on task execution.
243///
244/// # Type Parameters
245///
246/// * `X` - The executor handle type
247///
248/// # Examples
249///
250/// ```rust,no_run
251/// # #[cfg(feature = "exec_tokio")]
252/// # {
253/// use product_os_async_executor::{ExecutorPerform, TokioExecutor};
254///
255/// #[tokio::main]
256/// async fn main() {
257/// let task = TokioExecutor::spawn_in_context(async {
258/// println!("Hello from spawned task!");
259/// 42
260/// }).await;
261///
262/// assert!(task.is_ok());
263/// }
264/// # }
265/// ```
266pub trait ExecutorPerform<X>: Send + Sync {
267 /// Spawns a task in the current context asynchronously.
268 ///
269 /// # Errors
270 ///
271 /// Returns an error if the task cannot be spawned.
272 fn spawn_in_context<F>(
273 future: F,
274 ) -> impl Future<Output = Result<Arc<dyn Task<F::Output, Output = F::Output>>, SpawnError>> + Send
275 where
276 F: Future + Send + 'static,
277 F::Output: Send + 'static;
278
279 /// Spawns a task from an executor asynchronously.
280 ///
281 /// # Errors
282 ///
283 /// Returns an error if the task cannot be spawned.
284 fn spawn_from_executor<E, F>(
285 executor: &E,
286 future: F,
287 ) -> impl Future<Output = Result<Arc<dyn Task<F::Output, Output = F::Output>>, SpawnError>> + Send
288 where
289 E: Executor<X>,
290 F: Future + Send + 'static,
291 F::Output: Send + 'static;
292
293 /// Blocks on a future using the executor.
294 ///
295 /// Blocks the current thread until the future completes.
296 fn block_from_executor<E, F>(executor: &E, future: F) -> impl Future<Output = F::Output> + Send
297 where
298 E: Executor<X>,
299 F: Future + Send + 'static,
300 F::Output: Send + 'static;
301
302 /// Spawns a task in the current context synchronously.
303 ///
304 /// # Errors
305 ///
306 /// Returns an error if the task cannot be spawned.
307 fn spawn_in_context_sync<F>(
308 future: F,
309 ) -> Result<Arc<dyn Task<F::Output, Output = F::Output>>, SpawnError>
310 where
311 F: Future + Send + 'static,
312 F::Output: Send + 'static;
313
314 /// Spawns a task from an executor synchronously.
315 ///
316 /// # Errors
317 ///
318 /// Returns an error if the task cannot be spawned.
319 fn spawn_from_executor_sync<E, F>(
320 executor: &E,
321 future: F,
322 ) -> Result<Arc<dyn Task<F::Output, Output = F::Output>>, SpawnError>
323 where
324 E: Executor<X>,
325 F: Future + Send + 'static,
326 F::Output: Send + 'static;
327
328 /// Blocks on a future using the executor synchronously.
329 ///
330 /// Blocks the current thread until the future completes.
331 fn block_from_executor_sync<E, F>(executor: &E, future: F) -> F::Output
332 where
333 E: Executor<X>,
334 F: Future + Send + 'static,
335 F::Output: Send + 'static;
336}
337
338/// Trait for timer functionality across async runtimes.
339///
340/// Provides a unified interface for one-shot and interval timers that work
341/// with any supported async runtime.
342///
343/// # Examples
344///
345/// ```rust,no_run
346/// # #[cfg(feature = "exec_tokio")]
347/// # {
348/// use product_os_async_executor::{Timer, TokioExecutor};
349///
350/// #[tokio::main]
351/// async fn main() {
352/// // Create an interval timer that fires every 100ms
353/// let mut timer = TokioExecutor::interval(100).await;
354///
355/// // Wait for the first tick
356/// let elapsed = timer.tick().await;
357/// println!("Elapsed: {}ms", elapsed);
358/// }
359/// # }
360/// ```
361pub trait Timer: Send + Sync {
362 /// Creates a one-shot timer that fires after the specified duration.
363 fn once(duration_millis: u32) -> impl Future<Output = Self> + Send;
364
365 /// Creates an interval timer that fires repeatedly at the specified interval.
366 fn interval(duration_millis: u32) -> impl Future<Output = Self> + Send;
367
368 /// Cancels the timer.
369 fn cancel(&mut self) -> impl Future<Output = ()> + Send;
370
371 /// Creates a one-shot timer synchronously.
372 fn once_sync(duration_millis: u32) -> Self;
373
374 /// Creates an interval timer synchronously.
375 fn interval_sync(duration_millis: u32) -> Self;
376
377 /// Cancels the timer synchronously.
378 fn cancel_sync(&mut self);
379
380 /// Waits for the next tick of the timer and returns elapsed milliseconds.
381 fn tick(&mut self) -> impl Future<Output = u32> + Send;
382}
383
384/// Trait representing an async task that can be awaited.
385///
386/// This trait combines the `Future` trait with methods for managing task lifecycle.
387///
388/// # Type Parameters
389///
390/// * `Out` - The output type of the task
391pub trait Task<Out>: Future
392where
393 Out: Send + 'static,
394{
395 /// Consumes the task and returns its output.
396 fn output(self) -> Pin<Box<dyn Future<Output = Out> + Send>>;
397
398 /// Detaches the task, allowing it to run independently.
399 fn detach(self);
400
401 /// Drops the task, cancelling it if not detached.
402 fn drop(self);
403}