feather_tui/callback.rs
1use crate::error::{FtuiResult, FtuiError};
2use std::any::Any;
3
4/// This macro generates a function that take a reference to a `Box<dyn Any>`
5/// as an argument and return nothing. The function body (`$body`) is the code
6/// that will be execute when the callback is trigger.
7///
8/// # Usage
9/// Use for defining functions required to create a `Callback` object,
10///
11/// # Parameters
12/// - `func_name`: An identifier (`ident`) representing the generated function name.
13/// - `arg_name`: An identifier (`ident`) representing the function argument name.
14/// - `body`: A block (`block`) containing the function implementation.
15///
16/// # Example
17/// ```rust
18/// // A callback function that accept a u32 an print it out.
19/// cbk_new_callback_func!(print_num, arg, {
20/// println!("{}", cbk::cast_arg::<u32>(arg)?);
21/// Ok(())
22/// });
23/// ```
24#[macro_export]
25macro_rules! cbk_new_callback_func {
26 ($func_name:ident, $arg_name:ident, $body:block) => {
27 fn $func_name(
28 $arg_name: &Option<Box<dyn std::any::Any>>
29 ) -> feather_tui::error::FtuiResult<()> $body
30 };
31}
32
33/// Casts the argument of a callback function to the specified type.
34///
35/// # Parameters
36/// - `arg`: The argument of the callback function.
37///
38/// # Returns
39/// - `Ok(&T)`: The casted argument..
40/// - `Err(FtuiError)`: Returns an error.
41///
42/// # Notes
43/// - This function should only be use in a callback function.
44///
45/// # Example
46/// ```rust
47/// // A callback function that accept a u32 an print it out.
48/// cbk_new_callback_func!(print_num, arg, {
49/// println!("{}", cbk::cast_arg::<u32>(arg)?);
50/// Ok(())
51/// });
52///
53/// Callback::new(print_num, 5u32).call()?; // print 5
54/// Callback::new(print_num, 6u32).call()?; // print 6
55///
56/// Callback::new(print_num, "String").call()?; // Error (Wrong type)
57/// Callback::no_arg(print_num).call()?; // Error (No argument)
58/// ```
59pub fn cast_arg<T>(arg: &Option<Box<dyn Any>>) -> FtuiResult<&T>
60where
61 T: 'static,
62{
63 arg.as_ref()
64 .ok_or(FtuiError::CallbackCastArgNoArgument)?
65 .downcast_ref::<T>()
66 .ok_or(FtuiError::CallbackCastArgWrongType)
67}
68
69/// A generic callback handler for executing functions with stored arguments.
70/// `Callback` allows you to associate a function with an optional argument and
71/// invoke it later.
72///
73/// # Usage
74/// `Callback` is use for creating a `Option` component. The callback will be
75/// trigger when the `Option` component is selected.
76pub struct Callback {
77 func: fn(&Option<Box<dyn Any>>) -> FtuiResult<()>,
78 arg: Option<Box<dyn Any>>,
79}
80
81impl Callback {
82 /// Constructs a new `Callback` with an associated argument.
83 ///
84 /// # Parameters
85 /// - `func`: A callback function created using the `cbk_new_callback_func!` macro.
86 /// - `arg`: The argument value to associate with the `Callback` (`T: 'static`).
87 ///
88 /// # Example
89 /// ```rust
90 /// // Define a callback function using the macro.
91 /// cbk_new_callback_func!(callback_function, arg, {
92 /// ...
93 /// });
94 ///
95 /// // Create a `Callback` with an associated `u32` value.
96 /// let _ = Callback::new(callback_function, 5u32);
97 /// ```
98 pub fn new<T>(
99 func: fn(&Option<Box<dyn Any>>) -> FtuiResult<()>, arg: T
100 ) -> Self
101 where
102 T: 'static,
103 {
104 Callback {
105 func,
106 arg: Some(Box::new(arg)),
107 }
108 }
109
110 /// Constructs a new `Callback` without an associated argument.
111 ///
112 /// # Parameters
113 /// - `func`: A callback function created using the `cbk_new_callback_func!` macro.
114 ///
115 /// # Example
116 /// ```rust
117 /// // Define a callback function using the macro.
118 /// cbk_new_callback_func!(callback_function, arg, {
119 /// ...
120 /// });
121 ///
122 /// // Create a `Callback` without a associated argument.
123 /// let _ = Callback::no_arg(callback_function);
124 /// ```
125 pub fn no_arg(func: fn(&Option<Box<dyn Any>>) -> FtuiResult<()>) -> Self {
126 Callback {
127 func,
128 arg: None,
129 }
130 }
131
132 /// Invoke the `Callback`. Typically used for testing purposes.
133 ///
134 /// # Returns
135 /// - `Ok(())`: Returns nothing.
136 /// - `Err(FtuiError)`: Returns an error.
137 ///
138 /// # Example
139 /// ```rust
140 /// // Define a callback function that accepts a `u32` and prints it.
141 /// cbk_new_callback_func!(print_num, arg, {
142 /// println!("{}", tui::cbk::cast_arg::<u32>(arg)?);
143 /// Ok(())
144 /// });
145 ///
146 /// // Create a `Callback` with an argument of 5 and invoke it.
147 /// Callback::new(print_num, 5u32).call()?; // Prints: 5
148 /// ```
149 pub fn call(&self) -> FtuiResult<()> {
150 (self.func)(&self.arg)?;
151 Ok(())
152 }
153
154 /// Updates the argument associated with this `Callback`.
155 ///
156 /// # Parameters
157 /// - `arg`: The new argument value to associate with the `Callback` (`T' static`).
158 ///
159 /// # Example
160 /// ```rust
161 /// // Define a callback function that accepts a `u32` and prints it.
162 /// cbk_new_callback_func!(print_num, arg, {
163 /// println!("{}", tui::cbk::cast_arg::<u32>(arg)?);
164 /// Ok(())
165 /// });
166 ///
167 /// // Create a `Callback` with an initial argument.
168 /// let mut callback = Callback::new(print_num, 5u32);
169 ///
170 /// callback.call()?; // Prints: 5
171 ///
172 /// // Update the argument to a new value.
173 /// callback.update_arg(6u32);
174 ///
175 /// callback.call()?; // Prints: 6
176 /// ```
177 pub fn update_arg<T>(&mut self, arg: T)
178 where
179 T: 'static
180 {
181 self.arg = Some(Box::new(arg));
182 }
183
184 /// Remove the argument associated with the `Callback`.
185 pub fn remove_arg(&mut self) {
186 self.arg = None;
187 }
188}