Skip to main content

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}