1use dyn_clone::DynClone;
4use std::any::Any;
5
6#[derive(Clone, Debug)]
17pub struct Val {
18 pub(crate) val: Box<dyn Message>,
19 pub type_name: String,
20}
21
22impl PartialEq for Val {
23 fn eq(&self, other: &Self) -> bool {
24 self.val.msg_equals(other)
25 }
26}
27
28impl Val {
29 pub fn new<T: Message + 'static>(val: T) -> Self {
30 Val {
31 val: Box::new(val),
32 type_name: std::any::type_name::<T>().to_string(),
33 }
34 }
35
36 pub(crate) fn set_pending(&mut self) {
37 *self = Self::default();
38 }
39
40 pub(crate) fn is_pending(&self) -> bool {
41 self.val.msg_as_any_ref().is::<Unit>()
42 }
43
44 pub fn as_any(&self) -> Box<dyn Any> {
45 self.val.clone().msg_as_any()
46 }
47
48 pub fn as_any_ref(&self) -> &dyn Any {
49 self.val.msg_as_any_ref()
50 }
51}
52
53impl Default for Val {
54 fn default() -> Self {
55 Val::new(Unit)
56 }
57}
58
59#[derive(Clone, PartialEq, Debug)]
68struct Unit;
69
70impl std::fmt::Display for Unit {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "()")
73 }
74}
75
76macro_rules! sign_msg_core {
77 () => {
78 fn msg_as_any(self: Box<Self>) -> Box<dyn Any>;
82 fn msg_as_any_ref(&self) -> &dyn Any;
83 fn msg_equals(&self, other: &crate::Val) -> bool;
84 };
85}
86
87#[cfg(not(any(feature = "print_vals", feature = "print_vals_custom")))]
93pub trait Message: Send + DynClone {
94 sign_msg_core!();
95}
96
97#[cfg(feature = "print_vals")]
98pub trait Message: Send + DynClone + std::fmt::Debug {
99 sign_msg_core!();
100 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result;
101}
102
103#[cfg(feature = "print_vals_custom")]
104pub trait Message: Send + DynClone + std::fmt::Display {
105 sign_msg_core!();
106 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result;
107}
108
109macro_rules! impl_msg_core {
110 () => {
111 fn msg_as_any(self: Box<Self>) -> Box<dyn Any> {
112 self
113 }
114
115 fn msg_as_any_ref(&self) -> &dyn Any {
116 self
117 }
118
119 fn msg_equals(&self, other: &crate::Val) -> bool {
120 match other.as_any_ref().downcast_ref::<T>() {
121 Some(a) => self == a,
122 None => false,
123 }
124 }
125 };
126}
127
128#[cfg(not(any(feature = "print_vals", feature = "print_vals_custom")))]
129impl<T: Send + PartialEq + DynClone + std::fmt::Debug + 'static> Message for T {
130 impl_msg_core!();
131}
132
133#[cfg(feature = "print_vals")]
134impl<T: Send + PartialEq + DynClone + std::fmt::Debug + 'static> Message for T {
135 impl_msg_core!();
136
137 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
138 write!(
139 f,
140 "{:?}",
141 self.msg_as_any_ref().downcast_ref::<T>().unwrap()
142 )
143 }
144}
145
146#[cfg(feature = "print_vals_custom")]
147impl<T: Send + PartialEq + DynClone + std::fmt::Display + 'static> Message for T {
148 impl_msg_core!();
149
150 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
151 write!(f, "{}", self.msg_as_any_ref().downcast_ref::<T>().unwrap())
152 }
153}
154
155#[cfg(all(feature = "print_vals", feature = "print_vals_custom"))]
156compile_error!("features `must/print_vals` and `must/print_vals_custom` are mutually exclusive");
157
158dyn_clone::clone_trait_object!(Message);
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_unit_display() {
166 let unit = Unit;
167 assert_eq!(format!("{}", unit), "()");
168 }
169
170 #[test]
171 fn test_val_partial_eq() {
172 let val1 = Val::new(42);
173 let val2 = Val::new(42);
174 let val3 = Val::new(43);
175
176 assert!(val1 == val2);
177 assert!(!(val1 == val3));
178 }
179
180 #[test]
181 fn test_val_partial_eq_different_types() {
182 let val1 = Val::new(42);
183 let val2 = Val::new("hello");
184
185 assert!(!(val1 == val2));
186 }
187
188 #[test]
189 fn test_val_partial_eq_null() {
190 let val1: Val = Val::default();
191 let val2: Val = Val::default();
192
193 assert!(val1 == val2);
194 }
195}