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#""foo", 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
80/// Trait for actions that provide a summary representation for logging
81///
82/// The default implementation uses the Debug representation. Override
83/// `summary()` to provide concise summaries for actions with large payloads
84/// (e.g., showing byte counts instead of full data).
85///
86/// # Example
87///
88/// ```ignore
89/// impl ActionSummary for MyAction {
90/// fn summary(&self) -> String {
91/// match self {
92/// MyAction::DidLoadData { data } => {
93/// format!("DidLoadData {{ bytes: {} }}", data.len())
94/// }
95/// _ => format!("{:?}", self)
96/// }
97/// }
98/// }
99/// ```
100#[deprecated(since = "0.3.0", note = "use ActionParams::params() instead")]
101pub trait ActionSummary: Action {
102 /// Get a summary representation of this action for logging
103 ///
104 /// Should return a concise string, ideally one line, suitable for
105 /// display in a scrolling action log. For actions with large data payloads,
106 /// show size/count summaries instead of full content.
107 ///
108 /// Default implementation uses `Debug` formatting.
109 fn summary(&self) -> String {
110 format!("{:?}", self)
111 }
112}