diff options
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/args/func.md | 4 | ||||
| -rw-r--r-- | doc/args/invoke.md | 8 | ||||
| -rw-r--r-- | doc/args/select_arm.md | 7 | ||||
| -rw-r--r-- | doc/func.md | 12 | ||||
| -rw-r--r-- | doc/invoke.md | 17 | ||||
| -rw-r--r-- | doc/lib.md | 115 | ||||
| -rw-r--r-- | doc/select.md | 22 | ||||
| -rw-r--r-- | doc/usage/func.rs | 4 | ||||
| -rw-r--r-- | doc/usage/func_async_expand.rs | 3 | ||||
| -rw-r--r-- | doc/usage/func_async_expand.rs.lock | 3 | ||||
| -rw-r--r-- | doc/usage/func_expand.rs | 3 | ||||
| -rw-r--r-- | doc/usage/func_expand.rs.lock | 3 | ||||
| -rw-r--r-- | doc/usage/invoke.rs | 10 | ||||
| -rw-r--r-- | doc/usage/invoke_async_expand.rs | 6 | ||||
| -rw-r--r-- | doc/usage/invoke_async_expand.rs.lock | 6 | ||||
| -rw-r--r-- | doc/usage/invoke_expand.rs | 6 | ||||
| -rw-r--r-- | doc/usage/invoke_expand.rs.lock | 6 | ||||
| -rw-r--r-- | doc/usage/select.rs | 3 | ||||
| -rw-r--r-- | doc/usage/select_async_expand.rs | 5 | ||||
| -rw-r--r-- | doc/usage/select_async_expand.rs.lock | 5 | ||||
| -rw-r--r-- | doc/usage/select_expand.rs | 5 | ||||
| -rw-r--r-- | doc/usage/select_expand.rs.lock | 5 |
22 files changed, 258 insertions, 0 deletions
diff --git a/doc/args/func.md b/doc/args/func.md new file mode 100644 index 0000000..7d718a2 --- /dev/null +++ b/doc/args/func.md @@ -0,0 +1,4 @@ +Arguments parsed from the `#[func]` attribute. + +If the attribute is empty (`#[func]`), defaults to feature name `"async"`. +When a string literal is provided (`#[func("tokio_rt")]`), that value is used. diff --git a/doc/args/invoke.md b/doc/args/invoke.md new file mode 100644 index 0000000..74a1823 --- /dev/null +++ b/doc/args/invoke.md @@ -0,0 +1,8 @@ +Arguments parsed by the `invoke!` macro. + +Two forms: + +| Variant | Form | Behavior | +| ---------- | ------------------------- | ---------------------------------- | +| `Default` | `invoke!(expr)` | Feature name defaults to `"async"` | +| `Explicit` | `invoke!("feat" => expr)` | Uses the given feature name | diff --git a/doc/args/select_arm.md b/doc/args/select_arm.md new file mode 100644 index 0000000..c371d22 --- /dev/null +++ b/doc/args/select_arm.md @@ -0,0 +1,7 @@ +A single arm inside the `select!` macro. + +| Variant | Example | Meaning | +| ---------- | ----------------- | ----------------------------------------------------- | +| `Explicit` | `"async" => expr` | Arm guarded by `feature = "async"` | +| `Not` | `! => expr` | Arm guarded by `not(feature = <other_arm's_feature>)` | +| `Implicit` | `expr` | Feature determined by `.await` detection | diff --git a/doc/func.md b/doc/func.md new file mode 100644 index 0000000..86925d7 --- /dev/null +++ b/doc/func.md @@ -0,0 +1,12 @@ +Attribute macro that generates both a sync and an async version of a function, +gated by a Cargo feature flag. + +The function is written as a regular (non-async) `fn`. The macro duplicates it +internally into two implementations: + +- When the feature is **disabled**: the original `fn` is used as-is. +- When the feature is **enabled**: the function is promoted to `async fn`. + +By default the feature name is `"async"`. A different name can be supplied as +an attribute argument, for example `#[func("tokio_rt")]` to gate on the feature +`"tokio_rt"` instead. diff --git a/doc/invoke.md b/doc/invoke.md new file mode 100644 index 0000000..5784fba --- /dev/null +++ b/doc/invoke.md @@ -0,0 +1,17 @@ +Procedural macro that wraps a call expression, adding `.await` when the async +feature is enabled, and leaving it as a plain call otherwise. + +This macro is designed to be used **inside a `#[func]`-annotated function**. +`#[func]` ensures that the enclosing function is either sync or async depending +on the feature flag. `invoke!` mirrors that same gating on the call site: + +- Feature disabled, enclosing fn is sync → `invoke!(callee(args))` expands to + `callee(args)` — a plain synchronous call. +- Feature enabled, enclosing fn is async → `invoke!(callee(args))` expands to + `callee(args).await` — an awaited asynchronous call. + +Both the callee and the caller should be produced by `#[func]` so that their +sync/async nature changes in lockstep. + +An explicit feature name can be provided with the `=>` syntax. This is useful +when different features control different parts of the pipeline. diff --git a/doc/lib.md b/doc/lib.md new file mode 100644 index 0000000..88715a5 --- /dev/null +++ b/doc/lib.md @@ -0,0 +1,115 @@ +# might_be_async + +A proc-macro crate that generates both synchronous and asynchronous versions of +functions, gated by a Cargo feature flag. + +## Provided macros + +### `#[func]` — Attribute macro + +Generates both synchronous and asynchronous versions of a function, gated by a Cargo feature flag. When the feature is off, the function is a plain `fn`; when on, it becomes an `async fn`. + +Accepts an optional string argument specifying the feature name (defaults to `"async"`). + +```rust +// Uses default feature name "async" +#[might_be_async::func] +fn compute(x: i32) -> i32 { x } + +// Custom feature name +#[might_be_async::func("foo_async")] +fn fetch(url: &str) -> String { "url".into() } +``` + +### `invoke!` — Proc macro + +Wraps a function call, automatically adding `.await` when the feature is enabled. This lets you call `#[func]`-annotated functions without worrying about whether they are sync or async at the call site. + +Accepts an optional feature name before `=>` (defaults to `"async"`). + +```rust +use might_be_async::invoke; +# use std::env::args; +# #[might_be_async::func] +# fn entry() { +# let url = String::default(); + +// Uses default feature name "async" +invoke!(do_stuff(args())); + +// Custom feature name +invoke!("foo_async" => fetch_data(url)); +# } +# #[might_be_async::func] +# fn fetch_data(url: String) {} +# #[might_be_async::func] +# fn do_stuff(url: std::env::Args) {} +``` + +### `select!` — Proc macro + +Chooses between two expressions at compile time based on whether the feature flag is active. The first branch (marked with `"async" =>`) is taken when the feature is enabled; the second branch (marked with `! =>`) is taken otherwise. + +Supports three arm syntaxes: + +```rust +use might_be_async::select; +# #[might_be_async::func("foo_async")] +# fn entry() { + +// Explicit feature name arm and a negation arm +select!("foo_async" => { async_expr().await } else ! => { sync_expr() }); + +// Two explicit feature names (second can use ! prefix) +select!("foo_sync" => expr_a() else "foo_async" => expr_b().await); + +// Implicit arms — auto-detects .await to decide async vs sync +select!({ expr_with_await().await } else { expr_without_await() }); + +# } +# async fn expr_with_await () {} +# fn expr_without_await () {} +# async fn async_expr () {} +# fn sync_expr () {} +# async fn expr_b () {} +# fn expr_a () {} +``` + +## Complete example + +The three macros are designed to work together. `#[func]` keeps a set of +functions in sync: when the feature is off they are all plain `fn`, and when +it is on they are all `async fn`. `invoke!` calls between them automatically +add or omit `.await`, and `select!` picks the correct branch at compile time. + +```rust +use might_be_async::{func, invoke, select}; + +/// A simple computation, gated by the feature flag. +#[func] +fn double(x: i32) -> i32 { + x * 2 +} + +/// Calls `double` through `invoke!` — the call is plain or awaited +/// depending on whether the feature is active. +#[func] +fn add_then_double(a: i32, b: i32) -> i32 { + let sum = a + b; + invoke!(double(sum)) +} + +/// Uses `select!` to return a different value in each mode. +#[func] +fn pick(flag: bool) -> i32 { + if flag { + select!("foo_async" => 100 else ! => 200) + } else { + 0 + } +} + +assert_eq!(add_then_double(3, 4), 14); +assert_eq!(pick(true), 200); +assert_eq!(pick(false), 0); +``` diff --git a/doc/select.md b/doc/select.md new file mode 100644 index 0000000..d2330bd --- /dev/null +++ b/doc/select.md @@ -0,0 +1,22 @@ +Procedural macro that chooses between two expressions based on whether the +async feature is enabled, producing a value. + +## Explicit mode + +Each arm is labelled with a feature name. When the named feature is enabled +that arm is selected; otherwise the other arm is used. Since only one feature +is ever active at a time, the arm labelled `"sync"` effectively acts as an else +branch. + +The `!` token inverts the sense — it selects the arm when the corresponding +feature is **not** enabled. + +## Implicit mode + +Feature names are omitted; the macro inspects the token stream to decide which +expression is async. Whichever arm contains a `.await` call is treated as the +async branch. + +When neither arm contains `.await`, the first expression is assigned to the +async branch and the second to sync. The two branches trade places during +expansion so the correct one is active in each mode. diff --git a/doc/usage/func.rs b/doc/usage/func.rs new file mode 100644 index 0000000..f407019 --- /dev/null +++ b/doc/usage/func.rs @@ -0,0 +1,4 @@ +#[func] +pub fn greet(name: &str) -> String { + "Hello, {name}!".to_string() +} diff --git a/doc/usage/func_async_expand.rs b/doc/usage/func_async_expand.rs new file mode 100644 index 0000000..ac52411 --- /dev/null +++ b/doc/usage/func_async_expand.rs @@ -0,0 +1,3 @@ +pub async fn greet(name: &str) -> String { + "Hello, {name}!".to_string() +} diff --git a/doc/usage/func_async_expand.rs.lock b/doc/usage/func_async_expand.rs.lock new file mode 100644 index 0000000..ac52411 --- /dev/null +++ b/doc/usage/func_async_expand.rs.lock @@ -0,0 +1,3 @@ +pub async fn greet(name: &str) -> String { + "Hello, {name}!".to_string() +} diff --git a/doc/usage/func_expand.rs b/doc/usage/func_expand.rs new file mode 100644 index 0000000..70dee21 --- /dev/null +++ b/doc/usage/func_expand.rs @@ -0,0 +1,3 @@ +pub fn greet(name: &str) -> String { + "Hello, {name}!".to_string() +} diff --git a/doc/usage/func_expand.rs.lock b/doc/usage/func_expand.rs.lock new file mode 100644 index 0000000..70dee21 --- /dev/null +++ b/doc/usage/func_expand.rs.lock @@ -0,0 +1,3 @@ +pub fn greet(name: &str) -> String { + "Hello, {name}!".to_string() +} diff --git a/doc/usage/invoke.rs b/doc/usage/invoke.rs new file mode 100644 index 0000000..0ae90d2 --- /dev/null +++ b/doc/usage/invoke.rs @@ -0,0 +1,10 @@ +#[func] +fn compute(x: i32) -> i32 { + x * 2 +} + +#[func] +fn example() -> i32 { + // invoke! macro should be used with #[func] + invoke!(compute(5)) +} diff --git a/doc/usage/invoke_async_expand.rs b/doc/usage/invoke_async_expand.rs new file mode 100644 index 0000000..4b8d93f --- /dev/null +++ b/doc/usage/invoke_async_expand.rs @@ -0,0 +1,6 @@ +async fn compute(x: i32) -> i32 { + x * 2 +} +async fn example() -> i32 { + { { compute(5).await } } +} diff --git a/doc/usage/invoke_async_expand.rs.lock b/doc/usage/invoke_async_expand.rs.lock new file mode 100644 index 0000000..4b8d93f --- /dev/null +++ b/doc/usage/invoke_async_expand.rs.lock @@ -0,0 +1,6 @@ +async fn compute(x: i32) -> i32 { + x * 2 +} +async fn example() -> i32 { + { { compute(5).await } } +} diff --git a/doc/usage/invoke_expand.rs b/doc/usage/invoke_expand.rs new file mode 100644 index 0000000..3274d77 --- /dev/null +++ b/doc/usage/invoke_expand.rs @@ -0,0 +1,6 @@ +fn compute(x: i32) -> i32 { + x * 2 +} +fn example() -> i32 { + { { compute(5) } } +} diff --git a/doc/usage/invoke_expand.rs.lock b/doc/usage/invoke_expand.rs.lock new file mode 100644 index 0000000..3274d77 --- /dev/null +++ b/doc/usage/invoke_expand.rs.lock @@ -0,0 +1,6 @@ +fn compute(x: i32) -> i32 { + x * 2 +} +fn example() -> i32 { + { { compute(5) } } +} diff --git a/doc/usage/select.rs b/doc/usage/select.rs new file mode 100644 index 0000000..8cffcf8 --- /dev/null +++ b/doc/usage/select.rs @@ -0,0 +1,3 @@ +fn example() { + select! [{ 100 } else { 200 }]; +} diff --git a/doc/usage/select_async_expand.rs b/doc/usage/select_async_expand.rs new file mode 100644 index 0000000..b2553f3 --- /dev/null +++ b/doc/usage/select_async_expand.rs @@ -0,0 +1,5 @@ +fn example() { + { + { { 100 } } + }; +} diff --git a/doc/usage/select_async_expand.rs.lock b/doc/usage/select_async_expand.rs.lock new file mode 100644 index 0000000..b2553f3 --- /dev/null +++ b/doc/usage/select_async_expand.rs.lock @@ -0,0 +1,5 @@ +fn example() { + { + { { 100 } } + }; +} diff --git a/doc/usage/select_expand.rs b/doc/usage/select_expand.rs new file mode 100644 index 0000000..8caed8e --- /dev/null +++ b/doc/usage/select_expand.rs @@ -0,0 +1,5 @@ +fn example() { + { + { { 200 } } + }; +} diff --git a/doc/usage/select_expand.rs.lock b/doc/usage/select_expand.rs.lock new file mode 100644 index 0000000..8caed8e --- /dev/null +++ b/doc/usage/select_expand.rs.lock @@ -0,0 +1,5 @@ +fn example() { + { + { { 200 } } + }; +} |
