aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros')
-rw-r--r--mingling_macros/src/lib.rs109
1 files changed, 105 insertions, 4 deletions
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index 51c5b63..213c397 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -324,7 +324,7 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// #[chain]
/// fn my_step(prev: InputType) -> NextProcess {
/// // transform `prev`...
-/// OutputType::new(result).to_render()
+/// OutputType::new(result)
/// }
///
/// // Explicit program name:
@@ -334,6 +334,72 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// }
/// ```
///
+/// # Resource Injection
+///
+/// The `#[chain]` macro supports automatic injection of global resources
+/// via the 2nd to Nth parameters. You can read resources immutably with
+/// `&T` or mutate them with `&mut T`.
+///
+/// ## Immutable Resource (`&T`)
+///
+/// When you write `&SomeResource` as a parameter, the macro automatically
+/// resolves it from the global resource store:
+///
+/// ```rust,ignore
+/// #[chain]
+/// fn process(prev: HelloEntry, age: &Age, name: &Name) -> NextProcess {
+/// // `age` and `name` are automatically injected
+/// println!("Age: {}, Name: {}", age, name);
+/// NextStep::default()
+/// }
+/// ```
+///
+/// This expands to:
+///
+/// ```rust,ignore
+/// let __age_binding = ::mingling::this::<ThisProgram>().res_or_default::<Age>();
+/// let age: &Age = __age_binding.as_ref();
+/// let __name_binding = ::mingling::this::<ThisProgram>().res_or_default::<Name>();
+/// let name: &Name = __name_binding.as_ref();
+/// ```
+///
+/// ## Mutable Resource (`&mut T`)
+///
+/// When you write `&mut SomeResource` as a parameter, the macro wraps the
+/// function body in nested `__modify_res_and_return_any` calls:
+///
+/// ```rust,ignore
+/// #[chain]
+/// fn process(prev: HelloEntry, count: &mut InvocationCount, name: &Name) -> NextProcess {
+/// count.0 += 1;
+/// println!("Invocation #{} for {}", count.0, name);
+/// NextStep::default()
+/// }
+/// ```
+///
+/// This expands to:
+///
+/// ```rust,ignore
+/// let __name_binding = ::mingling::this::<ThisProgram>().res_or_default::<Name>();
+/// let name: &Name = __name_binding.as_ref();
+///
+/// ::mingling::this::<ThisProgram>().__modify_res_and_return_any(|count: &mut InvocationCount| {
+/// count.0 += 1;
+/// println!("Invocation #{} for {}", count.0, name);
+/// NextStep::default()
+/// }).into()
+/// ```
+///
+/// Multiple `&mut` parameters are supported with proper nesting.
+///
+/// ## Restrictions
+///
+/// - The first parameter (previous type) must be taken **by move**, not by reference.
+/// - Resource injection parameters **must** be references (`&T` or `&mut T`),
+/// owned values are not allowed.
+/// - When the `async` feature is enabled, `&mut T` cannot be used in async
+/// chain functions (only `&T` is supported for async).
+///
/// # Sync Example
///
/// ```rust,ignore
@@ -344,7 +410,26 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// #[chain]
/// fn greet(prev: HelloEntry) -> NextProcess {
/// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string());
-/// MyOutput::new(name).to_render()
+/// MyOutput::new(name)
+/// }
+/// ```
+///
+/// # Sync Example with Resource Injection
+///
+/// ```rust,ignore
+/// use mingling::macros::{chain, pack, gen_program, r_println};
+///
+/// #[derive(Default, Clone)]
+/// struct UserName(String);
+///
+/// pack!(Greeting = String);
+/// pack!(DisplayCount = ());
+///
+/// #[chain]
+/// fn greet(prev: HelloEntry, user_name: &UserName, count: &mut u64) -> NextProcess {
+/// r_println!("User: {:?}", user_name);
+/// *count += 1;
+/// Greeting::new(format!("Hello, {}!", user_name.0))
/// }
/// ```
///
@@ -359,13 +444,29 @@ pub fn r_println(input: TokenStream) -> TokenStream {
/// async fn greet(prev: HelloEntry) -> NextProcess {
/// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string());
/// some_async_fn(&name).await;
-/// MyOutput::new(name).to_render()
+/// MyOutput::new(name)
+/// }
+/// ```
+///
+/// # Async Example with Immutable Resource Injection
+///
+/// ```rust,ignore
+/// use mingling::macros::{chain, pack, gen_program};
+///
+/// pack!(MyOutput = String);
+///
+/// #[chain]
+/// async fn greet(prev: HelloEntry, prefix: &Prefix) -> NextProcess {
+/// let name = prev.first().cloned().unwrap_or_else(|| "World".to_string());
+/// some_async_fn(&name).await;
+/// MyOutput::new(format!("{}{}", prefix.0, name))
/// }
/// ```
///
/// # Requirements
///
-/// - The function must have exactly **one** parameter (the previous type in the chain).
+/// - The function must have at least **one** parameter (the previous type in the chain).
+/// - The first parameter must be taken **by move**.
/// - The function must return `NextProcess` (the type alias generated by `gen_program!`, which equals `ChainProcess<ProgramName>`).
/// - With the `async` feature, async functions are supported; without it, async functions are rejected.
#[proc_macro_attribute]