ferroui_reactiveui_controls/
reactive_command_adapter.rs1use ferroui_base::input::ICommand;
12use ferroui_base::{AnyValue, BoxedValue};
13use ferroui_reactiveui::CommandParameter;
14use ferroui_system::IDisposable;
15use std::any::Any;
16use std::fmt;
17use std::rc::Rc;
18
19pub struct ReactiveCommandAdapter {
25 command: Rc<dyn ferroui_reactiveui::ICommand>,
26}
27
28impl fmt::Debug for ReactiveCommandAdapter {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("ReactiveCommandAdapter").field("command", &(Rc::as_ptr(&self.command) as *const ())).finish()
31 }
32}
33
34impl ReactiveCommandAdapter {
35 pub fn new(command: Rc<dyn ferroui_reactiveui::ICommand>) -> Rc<Self> {
37 Rc::new(Self { command })
38 }
39
40 pub fn command_of(command: Rc<dyn ferroui_reactiveui::ICommand>) -> Rc<dyn ICommand> {
42 Self::new(command)
43 }
44
45 pub fn command(&self) -> &Rc<dyn ferroui_reactiveui::ICommand> {
47 &self.command
48 }
49
50 pub fn wraps(&self, command: &Rc<dyn ferroui_reactiveui::ICommand>) -> bool {
52 std::ptr::addr_eq(Rc::as_ptr(&self.command), Rc::as_ptr(command))
53 }
54}
55
56impl ICommand for ReactiveCommandAdapter {
57 fn can_execute(&self, parameter: Option<&BoxedValue>) -> bool {
58 self.command.can_execute(parameter.map(parameter_as_any))
59 }
60
61 fn execute(&self, parameter: Option<&BoxedValue>) {
62 self.command.execute(parameter.map(parameter_as_any));
63 }
64
65 fn can_execute_changed(&self, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
66 self.command.can_execute_changed(handler)
67 }
68}
69
70#[derive(Clone)]
73pub struct ReactiveCommandParameter(pub Rc<dyn Any>);
74
75impl PartialEq for ReactiveCommandParameter {
76 fn eq(&self, other: &Self) -> bool {
77 std::ptr::addr_eq(Rc::as_ptr(&self.0), Rc::as_ptr(&other.0))
78 }
79}
80
81impl fmt::Debug for ReactiveCommandParameter {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 f.debug_tuple("ReactiveCommandParameter").field(&(Rc::as_ptr(&self.0) as *const ())).finish()
84 }
85}
86
87pub fn parameter_as_any(parameter: &BoxedValue) -> &dyn Any {
90 let value: &dyn Any = (**parameter).as_any();
91 match value.downcast_ref::<ReactiveCommandParameter>() {
92 Some(wrapped) => &*wrapped.0,
93 None => value,
94 }
95}
96
97pub fn boxed_parameter(parameter: &CommandParameter) -> Option<BoxedValue> {
105 let parameter = parameter.as_ref()?;
106 let value: &dyn Any = &**parameter;
107 if let Some(boxed) = value.downcast_ref::<BoxedValue>() {
108 return Some(boxed.clone());
109 }
110 if let Some(object) = value.downcast_ref::<ferroui_base::Ref<ferroui_base::FerroObject>>() {
111 return Some(Rc::new(object.clone()) as BoxedValue);
112 }
113 Some(box_primitive(value).unwrap_or_else(|| Rc::new(ReactiveCommandParameter(parameter.clone())) as BoxedValue))
114}
115
116fn box_primitive(value: &dyn Any) -> Option<BoxedValue> {
118 fn boxed<T: Clone + PartialEq + 'static>(value: &dyn Any) -> Option<BoxedValue> {
119 value.downcast_ref::<T>().map(|value| Rc::new(value.clone()) as Rc<dyn AnyValue>)
120 }
121 boxed::<String>(value)
122 .or_else(|| boxed::<&'static str>(value))
123 .or_else(|| boxed::<bool>(value))
124 .or_else(|| boxed::<char>(value))
125 .or_else(|| boxed::<i8>(value))
126 .or_else(|| boxed::<i16>(value))
127 .or_else(|| boxed::<i32>(value))
128 .or_else(|| boxed::<i64>(value))
129 .or_else(|| boxed::<isize>(value))
130 .or_else(|| boxed::<u8>(value))
131 .or_else(|| boxed::<u16>(value))
132 .or_else(|| boxed::<u32>(value))
133 .or_else(|| boxed::<u64>(value))
134 .or_else(|| boxed::<usize>(value))
135 .or_else(|| boxed::<f32>(value))
136 .or_else(|| boxed::<f64>(value))
137}