diff --git a/Cargo.lock b/Cargo.lock index accadecc..7d55a430 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,6 @@ dependencies = [ "smol", "static_assertions", "thread_aware", - "tick", "tokio", ] diff --git a/crates/anyspawn/Cargo.toml b/crates/anyspawn/Cargo.toml index 9395b99c..743d1878 100644 --- a/crates/anyspawn/Cargo.toml +++ b/crates/anyspawn/Cargo.toml @@ -28,12 +28,11 @@ allowed_external_types = [ all-features = true [features] -default = ["tokio", "custom"] +default = [] tokio = ["dep:tokio"] -custom = ["dep:futures-channel"] [dependencies] -futures-channel = { workspace = true, features = ["alloc"], optional = true } +futures-channel = { workspace = true, features = ["alloc"] } thread_aware = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt"], optional = true } @@ -44,17 +43,28 @@ insta.workspace = true opentelemetry = { workspace = true, features = ["futures"] } smol = "2" static_assertions.workspace = true -tick = { workspace = true, features = ["tokio"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync"] } +[[test]] +name = "spawner" +required-features = ["tokio"] + +[[test]] +name = "handle" +required-features = ["tokio"] + +[[test]] +name = "builder" +required-features = ["tokio"] + [[bench]] name = "spawner" harness = false -required-features = ["tokio", "custom"] +required-features = ["tokio"] [[example]] name = "custom" -required-features = ["tokio", "custom"] +required-features = ["tokio"] [[example]] name = "tokio" @@ -62,11 +72,11 @@ required-features = ["tokio"] [[example]] name = "otel_context" -required-features = ["tokio", "custom"] +required-features = ["tokio"] [[example]] name = "thread_aware" -required-features = ["tokio", "custom"] +required-features = ["tokio"] [lints] workspace = true diff --git a/crates/anyspawn/README.md b/crates/anyspawn/README.md index 7cb4c6a7..d85f2f17 100644 --- a/crates/anyspawn/README.md +++ b/crates/anyspawn/README.md @@ -59,9 +59,8 @@ details and examples. ## Features -* `tokio` (default): Enables the [`Spawner::new_tokio`][__link4] and +* `tokio`: Enables the [`Spawner::new_tokio`][__link4] and [`Spawner::new_tokio_with_handle`][__link5] constructors -* `custom`: Enables [`Spawner::new_custom`][__link6] and [`CustomSpawnerBuilder`][__link7]
@@ -69,12 +68,10 @@ details and examples. This crate was developed as part of The Oxidizer Project. Browse this crate's source code. - [__cargo_doc2readme_dependencies_info]: ggGkYW0CYXSEGy4k8ldDFPOhG2VNeXtD5nnKG6EPY6OfW5wBG8g18NOFNdxpYXKEG9wiT4mviSlSG7bkeqiO1sYsG8AqKBp2b7sGG8q0eDukfWyeYWSCgmhhbnlzcGF3bmUwLjIuMIJsdGhyZWFkX2F3YXJlZTAuNi4y + [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjJhdIQbLiTyV0MU86EbZU15e0PmecoboQ9jo59bnAEbyDXw04U13GlhYvRhcoQb2kzPFSWDwP0bFmeuSlBPmOYbJhoG25idR60bDe4xDajaP_lhZIKCaGFueXNwYXduZTAuMi4wgmx0aHJlYWRfYXdhcmVlMC42LjI [__link0]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=Spawner [__link1]: https://docs.rs/thread_aware/0.6.2/thread_aware/?search=ThreadAware [__link2]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=Spawner::new_thread_aware [__link3]: Spawner#thread-aware-support [__link4]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=Spawner::new_tokio [__link5]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=Spawner::new_tokio_with_handle - [__link6]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=Spawner::new_custom - [__link7]: https://docs.rs/anyspawn/0.2.0/anyspawn/?search=CustomSpawnerBuilder diff --git a/crates/anyspawn/src/builder.rs b/crates/anyspawn/src/builder.rs index a18a6027..3cda1466 100644 --- a/crates/anyspawn/src/builder.rs +++ b/crates/anyspawn/src/builder.rs @@ -28,10 +28,11 @@ use crate::custom::BoxedFuture; /// # Examples /// /// ```rust -/// use anyspawn::{BoxedFuture, CustomSpawnerBuilder}; -/// +/// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { +/// use anyspawn::{BoxedFuture, CustomSpawnerBuilder}; +/// /// let spawner = CustomSpawnerBuilder::tokio() /// .layer(|fut: BoxedFuture, spawn: &dyn Fn(BoxedFuture)| { /// spawn(Box::pin(async move { @@ -45,6 +46,8 @@ use crate::custom::BoxedFuture; /// let result = spawner.spawn(async { 42 }).await; /// assert_eq!(result, 42); /// # } +/// # #[cfg(not(feature = "tokio"))] +/// # fn main() {} /// ``` pub struct CustomSpawnerBuilder { spawn_fn: S, @@ -73,7 +76,7 @@ impl CustomSpawnerBuilder<()> { /// # } /// ``` #[cfg(feature = "tokio")] - #[cfg_attr(docsrs, doc(cfg(all(feature = "tokio", feature = "custom"))))] + #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] #[must_use] pub fn tokio() -> CustomSpawnerBuilder { CustomSpawnerBuilder { @@ -107,7 +110,7 @@ impl CustomSpawnerBuilder<()> { /// # } /// ``` #[cfg(feature = "tokio")] - #[cfg_attr(docsrs, doc(cfg(all(feature = "tokio", feature = "custom"))))] + #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] #[must_use] pub fn tokio_with_handle(handle: ::tokio::runtime::Handle) -> CustomSpawnerBuilder { CustomSpawnerBuilder { @@ -184,10 +187,11 @@ where /// # Examples /// /// ```rust - /// use anyspawn::{BoxedFuture, CustomSpawnerBuilder}; - /// + /// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { + /// use anyspawn::{BoxedFuture, CustomSpawnerBuilder}; + /// /// let spawner = CustomSpawnerBuilder::tokio() /// .layer(|fut: BoxedFuture, spawn: &dyn Fn(BoxedFuture)| { /// spawn(Box::pin(async move { @@ -198,6 +202,8 @@ where /// .build(); /// # let _ = spawner; /// # } + /// # #[cfg(not(feature = "tokio"))] + /// # fn main() {} /// ``` pub fn layer(self, layer_fn: L) -> CustomSpawnerBuilder where diff --git a/crates/anyspawn/src/handle.rs b/crates/anyspawn/src/handle.rs index b8a37e15..e20c28ac 100644 --- a/crates/anyspawn/src/handle.rs +++ b/crates/anyspawn/src/handle.rs @@ -7,7 +7,6 @@ use std::fmt::Debug; use std::pin::Pin; use std::task::{Context, Poll}; -#[cfg(feature = "custom")] use futures_channel::oneshot; /// A handle to a spawned task that can be awaited to retrieve its result. @@ -23,7 +22,6 @@ pub struct JoinHandle(pub(crate) JoinHandleInner); pub(crate) enum JoinHandleInner { #[cfg(feature = "tokio")] Tokio(::tokio::task::JoinHandle), - #[cfg(feature = "custom")] Custom(oneshot::Receiver), } @@ -34,7 +32,6 @@ impl Future for JoinHandle { match &mut self.get_mut().0 { #[cfg(feature = "tokio")] JoinHandleInner::Tokio(jh) => Pin::new(jh).poll(cx).map(|res| res.expect("spawned task panicked")), - #[cfg(feature = "custom")] JoinHandleInner::Custom(rx) => Pin::new(rx).poll(cx).map(|res| res.expect("spawned task panicked")), } } diff --git a/crates/anyspawn/src/lib.rs b/crates/anyspawn/src/lib.rs index a0049c10..36885e68 100644 --- a/crates/anyspawn/src/lib.rs +++ b/crates/anyspawn/src/lib.rs @@ -21,19 +21,22 @@ //! ## Using Tokio //! //! ```rust -//! use anyspawn::Spawner; -//! +//! # #[cfg(feature = "tokio")] //! # #[tokio::main] //! # async fn main() { +//! use anyspawn::Spawner; +//! //! let spawner = Spawner::new_tokio(); //! let result = spawner.spawn(async { 1 + 1 }).await; //! assert_eq!(result, 2); //! # } +//! # #[cfg(not(feature = "tokio"))] +//! # fn main() {} //! ``` //! //! ## Custom Runtime //! -//! ```rust,ignore +//! ```rust //! use anyspawn::Spawner; //! //! let spawner = Spawner::new_custom("threadpool", |fut| { @@ -54,27 +57,18 @@ //! //! # Features //! -//! - `tokio` (default): Enables the [`Spawner::new_tokio`] and +//! - `tokio`: Enables the [`Spawner::new_tokio`] and //! [`Spawner::new_tokio_with_handle`] constructors -//! - `custom`: Enables [`Spawner::new_custom`] and [`CustomSpawnerBuilder`] #![doc(html_logo_url = "https://media.githubusercontent.com/media/microsoft/oxidizer/refs/heads/main/crates/anyspawn/logo.png")] #![doc(html_favicon_url = "https://media.githubusercontent.com/media/microsoft/oxidizer/refs/heads/main/crates/anyspawn/favicon.ico")] -#[cfg(feature = "custom")] mod builder; -#[cfg(feature = "custom")] mod custom; -#[cfg(any(feature = "tokio", feature = "custom"))] mod handle; -#[cfg(any(feature = "tokio", feature = "custom"))] mod spawner; -#[cfg(feature = "custom")] pub use builder::CustomSpawnerBuilder; -#[cfg(feature = "custom")] pub use custom::BoxedFuture; -#[cfg(any(feature = "tokio", feature = "custom"))] pub use handle::JoinHandle; -#[cfg(any(feature = "tokio", feature = "custom"))] pub use spawner::Spawner; diff --git a/crates/anyspawn/src/spawner.rs b/crates/anyspawn/src/spawner.rs index 8539b0ea..4178cfd2 100644 --- a/crates/anyspawn/src/spawner.rs +++ b/crates/anyspawn/src/spawner.rs @@ -4,15 +4,12 @@ //! [`Spawner`] for plugging in runtime implementations. use std::fmt::{self, Debug}; -#[cfg(feature = "custom")] use std::sync::Arc; use thread_aware::{PerCore, ThreadAware}; -#[cfg(feature = "custom")] use crate::custom::{BoxedFuture, CustomSpawner}; use crate::handle::JoinHandle; -#[cfg(any(feature = "tokio", feature = "custom"))] use crate::handle::JoinHandleInner; /// Runtime-agnostic task spawner. @@ -27,22 +24,24 @@ use crate::handle::JoinHandleInner; /// Using Tokio: /// /// ```rust -/// use anyspawn::Spawner; -/// +/// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { +/// use anyspawn::Spawner; +/// /// let spawner = Spawner::new_tokio(); /// let handle = spawner.spawn(async { /// println!("Task running!"); /// }); /// handle.await; // Wait for task to complete -/// /// # } +/// # #[cfg(not(feature = "tokio"))] +/// # fn main() {} /// ``` /// /// ## Custom Runtime /// -/// ```rust,ignore +/// ```rust /// use anyspawn::Spawner; /// /// let spawner = Spawner::new_custom("threadpool", |fut| { @@ -60,14 +59,17 @@ use crate::handle::JoinHandleInner; /// Await the [`JoinHandle`](crate::JoinHandle) to retrieve a value from the task: /// /// ```rust -/// use anyspawn::Spawner; -/// +/// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { +/// use anyspawn::Spawner; +/// /// let spawner = Spawner::new_tokio(); /// let value = spawner.spawn(async { 1 + 1 }).await; /// assert_eq!(value, 2); /// # } +/// # #[cfg(not(feature = "tokio"))] +/// # fn main() {} /// ``` /// /// ## Handling Errors @@ -75,10 +77,11 @@ use crate::handle::JoinHandleInner; /// Return a `Result` from the task to propagate errors: /// /// ```rust -/// use anyspawn::Spawner; -/// +/// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { +/// use anyspawn::Spawner; +/// /// let spawner = Spawner::new_tokio(); /// /// let result = spawner @@ -96,6 +99,8 @@ use crate::handle::JoinHandleInner; /// Err(e) => eprintln!("Task failed: {e}"), /// } /// # } +/// # #[cfg(not(feature = "tokio"))] +/// # fn main() {} /// ``` /// /// # Thread-Aware Support @@ -123,7 +128,6 @@ pub struct Spawner(SpawnerKind); enum SpawnerKind { #[cfg(feature = "tokio")] Tokio(#[thread_aware(skip)] Option<::tokio::runtime::Handle>), - #[cfg(feature = "custom")] Custom(CustomSpawner), ThreadAware(thread_aware::Arc), } @@ -198,8 +202,6 @@ impl Spawner { /// std::thread::spawn(move || futures::executor::block_on(fut)); /// }); /// ``` - #[cfg(feature = "custom")] - #[cfg_attr(docsrs, doc(cfg(feature = "custom")))] pub fn new_custom(name: &'static str, f: F) -> Self where F: Fn(BoxedFuture) + Send + Sync + 'static, @@ -226,6 +228,9 @@ impl Spawner { /// # Examples /// /// ```rust + /// # #[cfg(feature = "tokio")] + /// # #[tokio::main] + /// # async fn main() { /// use anyspawn::Spawner; /// # use thread_aware::ThreadAware; /// # use thread_aware::affinity::{MemoryAffinity, PinnedAffinity}; @@ -238,8 +243,6 @@ impl Spawner { /// # } /// # } /// - /// # #[tokio::main] - /// # async fn main() { /// let scheduler = Scheduler::default(); /// /// // Each core gets its own Spawner whose Scheduler carries the @@ -257,6 +260,8 @@ impl Spawner { /// let result = spawner.spawn(async { 1 + 1 }).await; /// assert_eq!(result, 2); /// # } + /// # #[cfg(not(feature = "tokio"))] + /// # fn main() {} /// ``` pub fn new_thread_aware(data: D, factory: fn(D) -> Self) -> Self where @@ -278,10 +283,11 @@ impl Spawner { /// # Examples /// /// ```rust - /// use anyspawn::Spawner; - /// + /// # #[cfg(feature = "tokio")] /// # #[tokio::main] /// # async fn main() { + /// use anyspawn::Spawner; + /// /// let spawner = Spawner::new_tokio(); /// /// // Await to get the result @@ -291,6 +297,8 @@ impl Spawner { /// // Or fire-and-forget by dropping the handle /// let _ = spawner.spawn(async { println!("background task") }); /// # } + /// # #[cfg(not(feature = "tokio"))] + /// # fn main() {} /// ``` pub fn spawn(&self, work: impl Future + Send + 'static) -> JoinHandle { match &self.0 { @@ -302,7 +310,6 @@ impl Spawner { }; JoinHandle(JoinHandleInner::Tokio(jh)) } - #[cfg(feature = "custom")] SpawnerKind::Custom(c) => JoinHandle(JoinHandleInner::Custom(c.call(work))), SpawnerKind::ThreadAware(ta) => ta.spawn(work), } @@ -316,7 +323,6 @@ impl Debug for Spawner { SpawnerKind::Tokio(None) => f.debug_tuple("Spawner").field(&"tokio").finish(), #[cfg(feature = "tokio")] SpawnerKind::Tokio(Some(_)) => f.debug_tuple("Spawner").field(&"tokio(handle)").finish(), - #[cfg(feature = "custom")] SpawnerKind::Custom(c) => f.debug_tuple("Spawner").field(c).finish(), SpawnerKind::ThreadAware(_) => f.debug_tuple("Spawner").field(&"thread_aware").finish(), } diff --git a/crates/anyspawn/tests/builder.rs b/crates/anyspawn/tests/builder.rs index f2b6eb46..34a2ad27 100644 --- a/crates/anyspawn/tests/builder.rs +++ b/crates/anyspawn/tests/builder.rs @@ -2,7 +2,6 @@ // Licensed under the MIT License. #![allow(missing_docs, reason = "test code")] -#![cfg(all(feature = "tokio", feature = "custom"))] #![cfg(not(miri))] // miri doesn't work well with `insta` snapshots //! Tests for `CustomSpawnerBuilder` naming and debug output. diff --git a/crates/anyspawn/tests/handle.rs b/crates/anyspawn/tests/handle.rs index 291d030e..f05bc42d 100644 --- a/crates/anyspawn/tests/handle.rs +++ b/crates/anyspawn/tests/handle.rs @@ -2,14 +2,12 @@ // Licensed under the MIT License. #![allow(missing_docs, reason = "test code")] -#![cfg(any(feature = "tokio", feature = "custom"))] //! Tests for `JoinHandle` implementations. use anyspawn::Spawner; #[cfg_attr(miri, ignore)] -#[cfg(feature = "tokio")] #[tokio::test] async fn join_handle_debug() { let spawner = Spawner::new_tokio(); diff --git a/crates/anyspawn/tests/relocation.rs b/crates/anyspawn/tests/relocation.rs index 54d4a5da..ae379c46 100644 --- a/crates/anyspawn/tests/relocation.rs +++ b/crates/anyspawn/tests/relocation.rs @@ -2,7 +2,6 @@ // Licensed under the MIT License. #![allow(missing_docs, reason = "test code")] -#![cfg(feature = "custom")] #![cfg(not(miri))] // miri does not support OS threads and CPU affinity helpers //! Tests for [`Spawner`] relocation behavior with [`ThreadAware`]. diff --git a/crates/anyspawn/tests/spawner.rs b/crates/anyspawn/tests/spawner.rs index d2cefdce..50647312 100644 --- a/crates/anyspawn/tests/spawner.rs +++ b/crates/anyspawn/tests/spawner.rs @@ -2,7 +2,6 @@ // Licensed under the MIT License. #![allow(missing_docs, reason = "test code")] -#![cfg(any(feature = "tokio", feature = "custom"))] #![cfg(not(miri))] // miri doesn't work well with `insta` snapshots //! Tests for `Spawner` implementations. @@ -11,7 +10,6 @@ use anyspawn::Spawner; static_assertions::assert_impl_all!(Spawner: Send, Sync); -#[cfg(feature = "tokio")] #[tokio::test] async fn tokio_spawn_and_await() { let spawner = Spawner::new_tokio(); @@ -19,7 +17,6 @@ async fn tokio_spawn_and_await() { assert_eq!(result, 42); } -#[cfg(feature = "tokio")] #[tokio::test] async fn tokio_spawn_fire_and_forget() { let spawner = Spawner::new_tokio(); @@ -34,7 +31,6 @@ async fn tokio_spawn_fire_and_forget() { assert_eq!(rx.await.unwrap(), 42); } -#[cfg(feature = "tokio")] #[test] fn tokio_with_handle_spawn_and_await() { let rt = tokio::runtime::Runtime::new().unwrap(); @@ -45,7 +41,6 @@ fn tokio_with_handle_spawn_and_await() { assert_eq!(result, 42); } -#[cfg(feature = "tokio")] #[test] fn tokio_with_handle_spawner_debug() { let rt = tokio::runtime::Runtime::new().unwrap(); @@ -54,7 +49,6 @@ fn tokio_with_handle_spawner_debug() { assert_eq!(debug_str, r#"Spawner("tokio(handle)")"#); } -#[cfg(feature = "custom")] #[test] fn custom_spawn_and_await() { let spawner = Spawner::new_custom("threadpool", |fut| { @@ -65,7 +59,6 @@ fn custom_spawn_and_await() { assert_eq!(result, 42); } -#[cfg(feature = "custom")] #[tokio::test] async fn custom_spawn_fire_and_forget() { let spawner = Spawner::new_custom("threadpool", |fut| { @@ -83,7 +76,6 @@ async fn custom_spawn_fire_and_forget() { assert_eq!(rx.recv().unwrap(), 42); } -#[cfg(feature = "custom")] #[test] fn custom_spawner_debug() { let spawner = Spawner::new_custom("noop", |_| {}); @@ -91,7 +83,6 @@ fn custom_spawner_debug() { assert!(debug_str.contains("noop")); } -#[cfg(feature = "custom")] #[test] fn thread_aware_spawner_debug() { let spawner = Spawner::new_thread_aware((), |()| Spawner::new_custom("inner", |_| {}));