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}