aboutsummaryrefslogtreecommitdiff
path: root/doc/lib.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/lib.md')
-rw-r--r--doc/lib.md115
1 files changed, 115 insertions, 0 deletions
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);
+```