From 106990f2fd3bcb59544b3d673dc4321f30098ea4 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Sat, 7 Dec 2024 22:06:10 +0100 Subject: [PATCH] Support async-generic feature flags in cgp-async (#37) * Add cargo feature flags for cgp-async * Propagate default features for cgp-async * Add full feature to cgp and cgp-core * Fix cgp-error-eyre when default-features = false * Add changelog --- .github/workflows/tests.yml | 5 ++++ CHANGELOG.md | 21 +++++++++++++++- Cargo.lock | 4 +-- crates/cgp-async-macro/src/impl_async.rs | 2 +- crates/cgp-async/Cargo.toml | 14 +++++++++++ crates/cgp-async/src/lib.rs | 32 +++++------------------- crates/cgp-async/src/traits/async.rs | 31 +++++++++++++++++++++++ crates/cgp-async/src/traits/mod.rs | 9 +++++++ crates/cgp-async/src/traits/send.rs | 8 ++++++ crates/cgp-async/src/traits/static.rs | 11 ++++++++ crates/cgp-async/src/traits/sync.rs | 8 ++++++ crates/cgp-component/Cargo.toml | 1 - crates/cgp-component/src/traits/mod.rs | 1 - crates/cgp-component/src/traits/sync.rs | 1 - crates/cgp-core/Cargo.toml | 6 ++++- crates/cgp-core/src/prelude.rs | 2 +- crates/cgp-error-eyre/Cargo.toml | 2 +- crates/cgp-error-eyre/src/lib.rs | 7 ++---- crates/cgp-error-std/Cargo.toml | 2 +- crates/cgp-error/Cargo.toml | 2 +- crates/cgp-inner/Cargo.toml | 1 - crates/cgp-inner/src/lib.rs | 5 ++-- crates/cgp-run/Cargo.toml | 2 +- crates/cgp-run/src/lib.rs | 4 +-- crates/cgp/Cargo.toml | 7 +++++- 25 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 crates/cgp-async/src/traits/async.rs create mode 100644 crates/cgp-async/src/traits/mod.rs create mode 100644 crates/cgp-async/src/traits/send.rs create mode 100644 crates/cgp-async/src/traits/static.rs create mode 100644 crates/cgp-async/src/traits/sync.rs delete mode 100644 crates/cgp-component/src/traits/sync.rs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8683bbb..ec4b149 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,6 +46,11 @@ jobs: name: clippy-all-features token: ${{ secrets.GITHUB_TOKEN }} args: --all-features --all-targets -- -D warnings + - uses: actions-rs/clippy-check@v1 + with: + name: clippy-no-default-features + token: ${{ secrets.GITHUB_TOKEN }} + args: --no-default-features --all-targets -- -D warnings test: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d06d54..c8f71d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,26 @@ ## Pre-Release -- Introduce new cgp-field constructs [#36](https://github.com/contextgeneric/cgp/pull/36) +- Support async-generic feature flags in cgp-async - [#37](https://github.com/contextgeneric/cgp/pull/37) + - Introduce the following feature flags to `cgp-async`: + - `async` + - `send` + - `sync` + - `static` + - `full` - default feature with all enabled + - Introduce the following traits in `cgp-async`: + - `MaybeSend` - alias to `Send` when the `send` feature is enabled, otherwise nothing. + - `MaybeSync` - alias to `Sync` when the `sync` feature is enabled, otherwise nothing. + - `MaybeStatic` - alias to `'static` when the `static` feature is enabled, otherwise nothing. + - Update the `Async` trait from `Sized + Send + Sync + 'static` to `MaybeSend + MaybeSync + MaybeStatic`. + - The `Sized` constraint is removed from `Async` to allow use inside `dyn` traits. + - Update the `#[async_trait]` macro to desugar async functions to return `impl Future`. + - Use of `#[async_trait]` now requires import of `cgp::prelude::*` to allow `MaybeSend` to be auto imported. + - `cgp-async` now re-exports `cgp_sync::strip_async` if the `async` feature is not enabled. + - i.e. async functions are desugared into sync functions if the `async` feature is disabled. + - Crates such as `cgp` and `cgp-core` offers the `full` feature, which can be disabled to disable the indirect default features in `cgp-async`. + +- Introduce new cgp-field constructs - [#36](https://github.com/contextgeneric/cgp/pull/36) - Introduce the product type constructs `Cons` and `Nil`. - Introduce the sum type constructs `Either` and `Void`. - Introduce the `Field` type for tagged field value. diff --git a/Cargo.lock b/Cargo.lock index 3c34d3b..a4c1ae4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,7 @@ version = 3 name = "cgp" version = "0.1.0" dependencies = [ + "cgp-async", "cgp-core", "cgp-extra", ] @@ -15,6 +16,7 @@ name = "cgp-async" version = "0.1.0" dependencies = [ "cgp-async-macro", + "cgp-sync", ] [[package]] @@ -30,7 +32,6 @@ dependencies = [ name = "cgp-component" version = "0.1.0" dependencies = [ - "cgp-async", "cgp-component-macro", ] @@ -128,7 +129,6 @@ dependencies = [ name = "cgp-inner" version = "0.1.0" dependencies = [ - "cgp-async", "cgp-component", ] diff --git a/crates/cgp-async-macro/src/impl_async.rs b/crates/cgp-async-macro/src/impl_async.rs index e78cc9a..0749843 100644 --- a/crates/cgp-async-macro/src/impl_async.rs +++ b/crates/cgp-async-macro/src/impl_async.rs @@ -15,7 +15,7 @@ pub fn impl_async(item: TokenStream) -> TokenStream { }; let impl_return: ReturnType = parse_quote! { - -> impl ::core::future::Future + Send + -> impl ::core::future::Future + MaybeSend }; trait_fn.sig.output = impl_return; diff --git a/crates/cgp-async/Cargo.toml b/crates/cgp-async/Cargo.toml index 8495abe..4d0f7b4 100644 --- a/crates/cgp-async/Cargo.toml +++ b/crates/cgp-async/Cargo.toml @@ -11,5 +11,19 @@ description = """ Async-generic primitives to support both sync/async in context-generic programming """ +[features] +default = [ "full" ] +full = [ + "async", + "send", + "sync", + "static", +] +async = [] +send = [ "async" ] +sync = [ "async" ] +static = [ "async" ] + [dependencies] cgp-async-macro = { version = "0.1.0" } +cgp-sync = { version = "0.1.0" } \ No newline at end of file diff --git a/crates/cgp-async/src/lib.rs b/crates/cgp-async/src/lib.rs index 0ad7136..16718dd 100644 --- a/crates/cgp-async/src/lib.rs +++ b/crates/cgp-async/src/lib.rs @@ -1,29 +1,9 @@ -pub use cgp_async_macro::native_async as async_trait; - -/** - This is defined as a convenient constraint alias to - `Sized + Send + Sync + 'static`. +pub mod traits; - This constraint is commonly required to be present in almost all associated - types. The `Sized` constraint is commonly required for associated types to be - used as generic parameters. The `Send + Sync + 'static` constraints are - important for the use of async functions inside traits. +pub use traits::{Async, MaybeSend, MaybeStatic, MaybeSync}; - Because Rust do not currently natively support the use of async functions - in traits, we use the [`async_trait`] crate to desugar async functions - inside traits into functions returning - `Pin>`. Due to the additional `Send` and lifetime - trait bounds inside the returned boxed future, almost all values that are - used inside the async functions are required to have types that implement - `Send` and `Sync`. - - It is also common to require the associated types to have the `'static` - lifetime for them to be used inside async functions, because Rust would - otherwise infer a more restrictive lifetime that does not outlive the - async functions. The `'static` lifetime constraint here really means - that the types implementing `Async` must not contain any lifetime - parameter. -*/ -pub trait Async: Send + Sync + 'static {} +#[cfg(feature = "async")] +pub use cgp_async_macro::native_async as async_trait; -impl Async for A where A: Send + Sync + 'static {} +#[cfg(not(feature = "async"))] +pub use cgp_sync::async_trait; diff --git a/crates/cgp-async/src/traits/async.rs b/crates/cgp-async/src/traits/async.rs new file mode 100644 index 0000000..695f7d2 --- /dev/null +++ b/crates/cgp-async/src/traits/async.rs @@ -0,0 +1,31 @@ +use crate::traits::r#static::MaybeStatic; +use crate::traits::send::MaybeSend; +use crate::traits::sync::MaybeSync; + +/** + This is defined as a convenient constraint alias to + `Sized + Send + Sync + 'static`. + + This constraint is commonly required to be present in almost all associated + types. The `Sized` constraint is commonly required for associated types to be + used as generic parameters. The `Send + Sync + 'static` constraints are + important for the use of async functions inside traits. + + Because Rust do not currently natively support the use of async functions + in traits, we use the [`async_trait`] crate to desugar async functions + inside traits into functions returning + `Pin>`. Due to the additional `Send` and lifetime + trait bounds inside the returned boxed future, almost all values that are + used inside the async functions are required to have types that implement + `Send` and `Sync`. + + It is also common to require the associated types to have the `'static` + lifetime for them to be used inside async functions, because Rust would + otherwise infer a more restrictive lifetime that does not outlive the + async functions. The `'static` lifetime constraint here really means + that the types implementing `Async` must not contain any lifetime + parameter. +*/ +pub trait Async: MaybeSend + MaybeSync + MaybeStatic {} + +impl Async for A where A: MaybeSend + MaybeSync + MaybeStatic {} diff --git a/crates/cgp-async/src/traits/mod.rs b/crates/cgp-async/src/traits/mod.rs new file mode 100644 index 0000000..d918d01 --- /dev/null +++ b/crates/cgp-async/src/traits/mod.rs @@ -0,0 +1,9 @@ +pub mod r#async; +pub mod send; +pub mod r#static; +pub mod sync; + +pub use r#async::Async; +pub use r#static::MaybeStatic; +pub use send::MaybeSend; +pub use sync::MaybeSync; diff --git a/crates/cgp-async/src/traits/send.rs b/crates/cgp-async/src/traits/send.rs new file mode 100644 index 0000000..922a3d8 --- /dev/null +++ b/crates/cgp-async/src/traits/send.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "send")] +pub use core::marker::Send as MaybeSend; + +#[cfg(not(feature = "send"))] +pub trait MaybeSend {} + +#[cfg(not(feature = "send"))] +impl MaybeSend for T {} diff --git a/crates/cgp-async/src/traits/static.rs b/crates/cgp-async/src/traits/static.rs new file mode 100644 index 0000000..093b971 --- /dev/null +++ b/crates/cgp-async/src/traits/static.rs @@ -0,0 +1,11 @@ +#[cfg(feature = "static")] +pub trait MaybeStatic: 'static {} + +#[cfg(feature = "static")] +impl MaybeStatic for T {} + +#[cfg(not(feature = "static"))] +pub trait MaybeStatic {} + +#[cfg(not(feature = "static"))] +impl MaybeStatic for T {} diff --git a/crates/cgp-async/src/traits/sync.rs b/crates/cgp-async/src/traits/sync.rs new file mode 100644 index 0000000..c66870a --- /dev/null +++ b/crates/cgp-async/src/traits/sync.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "sync")] +pub use core::marker::Sync as MaybeSync; + +#[cfg(not(feature = "sync"))] +pub trait MaybeSync {} + +#[cfg(not(feature = "sync"))] +impl MaybeSync for T {} diff --git a/crates/cgp-component/Cargo.toml b/crates/cgp-component/Cargo.toml index a72678d..cb363a7 100644 --- a/crates/cgp-component/Cargo.toml +++ b/crates/cgp-component/Cargo.toml @@ -12,5 +12,4 @@ description = """ """ [dependencies] -cgp-async = { version = "0.1.0" } cgp-component-macro = { version = "0.1.0" } diff --git a/crates/cgp-component/src/traits/mod.rs b/crates/cgp-component/src/traits/mod.rs index 2f2052d..c610346 100644 --- a/crates/cgp-component/src/traits/mod.rs +++ b/crates/cgp-component/src/traits/mod.rs @@ -1,6 +1,5 @@ pub mod delegate_component; pub mod has_components; -pub mod sync; pub use delegate_component::DelegateComponent; pub use has_components::HasComponents; diff --git a/crates/cgp-component/src/traits/sync.rs b/crates/cgp-component/src/traits/sync.rs deleted file mode 100644 index fa8f555..0000000 --- a/crates/cgp-component/src/traits/sync.rs +++ /dev/null @@ -1 +0,0 @@ -pub use cgp_async::Async; diff --git a/crates/cgp-core/Cargo.toml b/crates/cgp-core/Cargo.toml index dd658e7..89112f6 100644 --- a/crates/cgp-core/Cargo.toml +++ b/crates/cgp-core/Cargo.toml @@ -11,8 +11,12 @@ description = """ Context-generic programming core traits """ +[features] +default = [ "full" ] +full = [ "cgp-async/full" ] + [dependencies] -cgp-async = { version = "0.1.0" } +cgp-async = { version = "0.1.0", default-features = false } cgp-component = { version = "0.1.0" } cgp-type = { version = "0.1.0" } cgp-error = { version = "0.1.0" } diff --git a/crates/cgp-core/src/prelude.rs b/crates/cgp-core/src/prelude.rs index f526796..9a30c0f 100644 --- a/crates/cgp-core/src/prelude.rs +++ b/crates/cgp-core/src/prelude.rs @@ -1,4 +1,4 @@ -pub use cgp_async::{async_trait, Async}; +pub use cgp_async::{async_trait, Async, MaybeSend, MaybeStatic, MaybeSync}; pub use cgp_component::{ define_components, delegate_components, derive_component, DelegateComponent, HasComponents, }; diff --git a/crates/cgp-error-eyre/Cargo.toml b/crates/cgp-error-eyre/Cargo.toml index 040aca6..0cd20bd 100644 --- a/crates/cgp-error-eyre/Cargo.toml +++ b/crates/cgp-error-eyre/Cargo.toml @@ -12,5 +12,5 @@ description = """ """ [dependencies] -cgp-core = { version = "0.1.0" } +cgp-core = { version = "0.1.0", default-features = false } eyre = { version = "0.6.11" } \ No newline at end of file diff --git a/crates/cgp-error-eyre/src/lib.rs b/crates/cgp-error-eyre/src/lib.rs index 844ab00..757767f 100644 --- a/crates/cgp-error-eyre/src/lib.rs +++ b/crates/cgp-error-eyre/src/lib.rs @@ -7,10 +7,7 @@ use eyre::{eyre, Report}; pub struct ProvideEyreError; -impl ProvideErrorType for ProvideEyreError -where - Context: Async, -{ +impl ProvideErrorType for ProvideEyreError { type Error = Report; } @@ -19,7 +16,7 @@ pub struct RaiseStdError; impl ErrorRaiser for RaiseStdError where Context: HasErrorType, - E: StdError + Async, + E: StdError + Send + Sync + 'static, { fn raise_error(e: E) -> Report { e.into() diff --git a/crates/cgp-error-std/Cargo.toml b/crates/cgp-error-std/Cargo.toml index ef314c5..53af9c4 100644 --- a/crates/cgp-error-std/Cargo.toml +++ b/crates/cgp-error-std/Cargo.toml @@ -12,4 +12,4 @@ description = """ """ [dependencies] -cgp-core = { version = "0.1.0" } \ No newline at end of file +cgp-core = { version = "0.1.0", default-features = false } \ No newline at end of file diff --git a/crates/cgp-error/Cargo.toml b/crates/cgp-error/Cargo.toml index 98b7f57..5328c5b 100644 --- a/crates/cgp-error/Cargo.toml +++ b/crates/cgp-error/Cargo.toml @@ -12,6 +12,6 @@ description = """ """ [dependencies] -cgp-async = { version = "0.1.0" } +cgp-async = { version = "0.1.0", default-features = false } cgp-component = { version = "0.1.0" } cgp-type = { version = "0.1.0" } diff --git a/crates/cgp-inner/Cargo.toml b/crates/cgp-inner/Cargo.toml index 3ecf2c4..f2e74fc 100644 --- a/crates/cgp-inner/Cargo.toml +++ b/crates/cgp-inner/Cargo.toml @@ -12,5 +12,4 @@ description = """ """ [dependencies] -cgp-async = { version = "0.1.0" } cgp-component = { version = "0.1.0" } \ No newline at end of file diff --git a/crates/cgp-inner/src/lib.rs b/crates/cgp-inner/src/lib.rs index 5cabca2..c0efac5 100644 --- a/crates/cgp-inner/src/lib.rs +++ b/crates/cgp-inner/src/lib.rs @@ -2,12 +2,11 @@ extern crate alloc; -use cgp_async::Async; use cgp_component::{derive_component, DelegateComponent, HasComponents}; #[derive_component(InnerComponent, ProvideInner)] -pub trait HasInner: Async { - type Inner: Async; +pub trait HasInner { + type Inner; fn inner(&self) -> &Self::Inner; } diff --git a/crates/cgp-run/Cargo.toml b/crates/cgp-run/Cargo.toml index 1015710..5430f11 100644 --- a/crates/cgp-run/Cargo.toml +++ b/crates/cgp-run/Cargo.toml @@ -12,6 +12,6 @@ description = """ """ [dependencies] -cgp-async = { version = "0.1.0" } +cgp-async = { version = "0.1.0", default-features = false } cgp-error = { version = "0.1.0" } cgp-component = { version = "0.1.0" } \ No newline at end of file diff --git a/crates/cgp-run/src/lib.rs b/crates/cgp-run/src/lib.rs index cca42f9..c89e8d9 100644 --- a/crates/cgp-run/src/lib.rs +++ b/crates/cgp-run/src/lib.rs @@ -5,8 +5,8 @@ extern crate alloc; #[allow(unused_imports)] use alloc::boxed::Box; -use cgp_async::{async_trait, Async}; -use cgp_component::{derive_component, DelegateComponent, HasComponents}; +use cgp_async::*; +use cgp_component::*; use cgp_error::HasErrorType; #[derive_component(RunnerComponent, Runner)] diff --git a/crates/cgp/Cargo.toml b/crates/cgp/Cargo.toml index 9fdd60b..be90897 100644 --- a/crates/cgp/Cargo.toml +++ b/crates/cgp/Cargo.toml @@ -11,6 +11,11 @@ description = """ Context-generic programming meta crate """ +[features] +default = [ "full" ] +full = [ "cgp-async/full" ] + [dependencies] -cgp-core = { version = "0.1.0" } +cgp-async = { version = "0.1.0", default-features = false } +cgp-core = { version = "0.1.0", default-features = false } cgp-extra = { version = "0.1.0" } \ No newline at end of file