reducer_compose

Macro reducer_compose 

Source
macro_rules! reducer_compose {
    ($state:expr, $action:expr, { $($arms:tt)+ }) => { ... };
    ($state:expr, $action:expr, $context:expr, { $($arms:tt)+ }) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) category $category:expr => $handler:expr, $($rest:tt)+) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) context $context_value:expr => $handler:expr, $($rest:tt)+) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) _ => $handler:expr, $($rest:tt)+) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) $pattern:pat $(if $guard:expr)? => $handler:expr, $($rest:tt)+) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) category $category:expr => $handler:expr $(,)?) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) context $context_value:expr => $handler:expr $(,)?) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) _ => $handler:expr $(,)?) => { ... };
    (@accum $state:ident, $action:ident, $context:ident; ($($out:tt)*) $pattern:pat $(if $guard:expr)? => $handler:expr $(,)?) => { ... };
}
Expand description

Compose a reducer by routing actions to focused handlers.

§When to Use

For most reducers, a flat match is simpler and clearer. Use this macro when:

  • Your reducer exceeds ~500 lines and splitting improves organization
  • You have context-aware routing (e.g., vim normal vs command mode)
  • Handlers live in separate modules and you want clean composition

§Syntax

reducer_compose!(state, action, {
    // Arms are tried in order, first match wins
    category "name" => handler,      // Route by action category
    Action::Specific => handler,     // Route by pattern match
    _ => fallback_handler,           // Catch-all (required last)
})

// With context (e.g., for modal/mode-aware routing):
reducer_compose!(state, action, context, {
    context Mode::Command => handle_command,  // Route by context value
    category "nav" => handle_nav,
    _ => handle_default,
})

§Arm Types

category "name" => handler - Routes actions where ActionCategory::category(&action) == Some("name"). Requires #[action(infer_categories)] on your action enum.

context Value => handler - Routes when the context expression equals Value. Only available in the 4-argument form.

Pattern => handler - Standard pattern match (e.g., Action::Quit, Action::Input(_)).

_ => handler - Catch-all fallback. Must be last.

§Handler Signature

All handlers must have the same signature:

fn handler(state: &mut S, action: A) -> R

Where R is typically bool or DispatchResult<E>.

§Category Inference

With #[action(infer_categories)], categories are inferred from action names by taking the prefix before the verb:

ActionVerbCategory
NavScrollUpScroll"nav"
SearchQuerySubmitSubmit"search_query"
WeatherDidLoadLoad"weather_did"
Quit(none)None

For predictable categories, use explicit #[category = "name"] attributes.

§Example

fn reducer(state: &mut AppState, action: Action, mode: Mode) -> bool {
    reducer_compose!(state, action, mode, {
        // Command mode gets priority
        context Mode::Command => handle_command,
        // Then route by category
        category "nav" => handle_navigation,
        category "search" => handle_search,
        // Specific actions
        Action::Quit => |_, _| false,
        // Everything else
        _ => handle_ui,
    })
}

fn handle_navigation(state: &mut AppState, action: Action) -> bool {
    match action {
        Action::NavUp => { state.cursor -= 1; true }
        Action::NavDown => { state.cursor += 1; true }
        _ => false,
    }
}