tui_dispatch_core/
action.rs

1//! Action trait for type-safe state mutations
2
3use std::fmt::Debug;
4use std::hash::Hash;
5
6/// Marker trait for actions that can be dispatched to the store
7///
8/// Actions represent intents to change state. They should be:
9/// - Clone: Actions may be logged, replayed, or sent to multiple handlers
10/// - Debug: For debugging and logging
11/// - Send + 'static: For async dispatch across threads
12///
13/// Use `#[derive(Action)]` from `tui-dispatch-macros` to auto-implement this trait.
14pub trait Action: Clone + Debug + Send + 'static {
15    /// Get the action name for logging and filtering
16    fn name(&self) -> &'static str;
17}
18
19/// Extension trait for actions with category support
20///
21/// This trait is auto-implemented when using `#[derive(Action)]` with
22/// `#[action(infer_categories)]`. It provides methods to query an action's
23/// category for routing and filtering.
24///
25/// # Example
26///
27/// ```ignore
28/// use tui_dispatch::ActionCategory;
29///
30/// #[derive(Action, Clone, Debug)]
31/// #[action(infer_categories)]
32/// enum MyAction {
33///     SearchStart,
34///     SearchClear,
35///     ConnectionFormOpen,
36/// }
37///
38/// let action = MyAction::SearchStart;
39/// assert_eq!(action.category(), Some("search"));
40/// assert!(matches!(action.category_enum(), MyActionCategory::Search));
41/// ```
42pub trait ActionCategory: Action {
43    /// The category enum type generated by the derive macro
44    type Category: Copy + Eq + Hash + Debug;
45
46    /// Get the action's category as a string (if categorized)
47    fn category(&self) -> Option<&'static str>;
48
49    /// Get the action's category as an enum value
50    fn category_enum(&self) -> Self::Category;
51}
52
53/// Trait for getting action parameters without the variant name.
54///
55/// Auto-implemented by `#[derive(Action)]`. Returns just the field values
56/// as a string, suitable for display in action logs where the action name
57/// is already shown separately.
58///
59/// # Example
60///
61/// ```ignore
62/// #[derive(Action, Clone, Debug)]
63/// enum MyAction {
64///     SetFilter { query: String, limit: usize },
65///     Tick,
66/// }
67///
68/// let action = MyAction::SetFilter { query: "foo".into(), limit: 10 };
69/// assert_eq!(action.name(), "SetFilter");
70/// assert_eq!(action.params(), r#"{query: \"foo\", limit: 10}"#);
71///
72/// let tick = MyAction::Tick;
73/// assert_eq!(tick.params(), "");
74/// ```
75pub trait ActionParams: Action {
76    /// Get just the action parameters as a string (no variant name)
77    fn params(&self) -> String;
78
79    /// Get a multi-line, detailed representation of the parameters.
80    fn params_pretty(&self) -> String {
81        self.params()
82    }
83}
84
85/// Trait for actions that provide a summary representation for logging
86///
87/// The default implementation uses the Debug representation. Override
88/// `summary()` to provide concise summaries for actions with large payloads
89/// (e.g., showing byte counts instead of full data).
90///
91/// # Example
92///
93/// ```ignore
94/// impl ActionSummary for MyAction {
95///     fn summary(&self) -> String {
96///         match self {
97///             MyAction::DidLoadData { data } => {
98///                 format!("DidLoadData {{ bytes: {} }}", data.len())
99///             }
100///             _ => format!("{:?}", self)
101///         }
102///     }
103/// }
104/// ```
105#[deprecated(since = "0.3.0", note = "use ActionParams::params() instead")]
106pub trait ActionSummary: Action {
107    /// Get a summary representation of this action for logging
108    ///
109    /// Should return a concise string, ideally one line, suitable for
110    /// display in a scrolling action log. For actions with large data payloads,
111    /// show size/count summaries instead of full content.
112    ///
113    /// Default implementation uses `Debug` formatting.
114    fn summary(&self) -> String {
115        format!("{:?}", self)
116    }
117}