use std::any::Any;
use std::fmt;
pub struct Message(Box<dyn Any + Send>);
impl Message {
pub fn new<M: Any + Send + 'static>(msg: M) -> Self {
Self(Box::new(msg))
}
pub fn downcast<M: Any + Send + 'static>(self) -> Option<M> {
self.0.downcast::<M>().ok().map(|b| *b)
}
pub fn downcast_ref<M: Any + Send + 'static>(&self) -> Option<&M> {
self.0.downcast_ref::<M>()
}
pub fn is<M: Any + Send + 'static>(&self) -> bool {
self.0.is::<M>()
}
}
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Message").finish_non_exhaustive()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QuitMsg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InterruptMsg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SuspendMsg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResumeMsg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowSizeMsg {
pub width: u16,
pub height: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FocusMsg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlurMsg;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SetWindowTitleMsg(pub String);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct RequestWindowSizeMsg;
pub struct BatchMsg(pub Vec<super::Cmd>);
pub struct SequenceMsg(pub Vec<super::Cmd>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct PrintLineMsg(pub String);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_downcast() {
struct TestMsg(i32);
let msg = Message::new(TestMsg(42));
assert!(msg.is::<TestMsg>());
let inner = msg.downcast::<TestMsg>().unwrap();
assert_eq!(inner.0, 42);
}
#[test]
fn test_message_downcast_wrong_type() {
struct TestMsg1;
struct TestMsg2;
let msg = Message::new(TestMsg1);
assert!(!msg.is::<TestMsg2>());
assert!(msg.downcast::<TestMsg2>().is_none());
}
#[test]
fn test_quit_msg() {
let msg = Message::new(QuitMsg);
assert!(msg.is::<QuitMsg>());
}
#[test]
fn test_window_size_msg() {
let msg = WindowSizeMsg {
width: 80,
height: 24,
};
assert_eq!(msg.width, 80);
assert_eq!(msg.height, 24);
}
#[test]
fn test_message_downcast_ref_success() {
struct TestMsg(i32);
let msg = Message::new(TestMsg(42));
let inner_ref = msg.downcast_ref::<TestMsg>().unwrap();
assert_eq!(inner_ref.0, 42);
let inner_ref2 = msg.downcast_ref::<TestMsg>().unwrap();
assert_eq!(inner_ref2.0, 42);
}
#[test]
fn test_message_downcast_ref_wrong_type() {
struct TestMsg1(#[expect(dead_code)] i32);
struct TestMsg2;
let msg = Message::new(TestMsg1(42));
assert!(msg.downcast_ref::<TestMsg2>().is_none());
}
#[test]
fn test_message_is_without_consuming() {
struct TestMsg(i32);
let msg = Message::new(TestMsg(42));
assert!(msg.is::<TestMsg>());
assert!(msg.is::<TestMsg>());
assert_eq!(msg.downcast::<TestMsg>().unwrap().0, 42);
}
#[test]
fn test_message_debug_format() {
struct TestMsg;
let msg = Message::new(TestMsg);
let debug_str = format!("{:?}", msg);
assert!(debug_str.contains("Message"));
}
#[test]
fn test_interrupt_msg() {
let msg = Message::new(InterruptMsg);
assert!(msg.is::<InterruptMsg>());
assert!(msg.downcast::<InterruptMsg>().is_some());
}
#[test]
fn test_suspend_msg() {
let msg = Message::new(SuspendMsg);
assert!(msg.is::<SuspendMsg>());
}
#[test]
fn test_resume_msg() {
let msg = Message::new(ResumeMsg);
assert!(msg.is::<ResumeMsg>());
}
#[test]
fn test_focus_msg() {
let msg = Message::new(FocusMsg);
assert!(msg.is::<FocusMsg>());
}
#[test]
fn test_blur_msg() {
let msg = Message::new(BlurMsg);
assert!(msg.is::<BlurMsg>());
}
#[test]
fn test_window_size_msg_in_message() {
let size = WindowSizeMsg {
width: 120,
height: 40,
};
let msg = Message::new(size);
assert!(msg.is::<WindowSizeMsg>());
let size_ref = msg.downcast_ref::<WindowSizeMsg>().unwrap();
assert_eq!(size_ref.width, 120);
assert_eq!(size_ref.height, 40);
}
#[test]
fn test_message_with_string() {
let msg = Message::new(String::from("hello"));
assert!(msg.is::<String>());
assert_eq!(msg.downcast::<String>().unwrap(), "hello");
}
#[test]
fn test_message_with_vec() {
let msg = Message::new(vec![1, 2, 3]);
assert!(msg.is::<Vec<i32>>());
assert_eq!(msg.downcast::<Vec<i32>>().unwrap(), vec![1, 2, 3]);
}
#[test]
fn test_message_with_tuple() {
let msg = Message::new((1i32, "hello", 2.71f64));
assert!(msg.is::<(i32, &str, f64)>());
let (a, b, c) = msg.downcast::<(i32, &str, f64)>().unwrap();
assert_eq!(a, 1);
assert_eq!(b, "hello");
assert!((c - 2.71).abs() < f64::EPSILON);
}
#[test]
fn test_message_with_unit() {
let msg = Message::new(());
assert!(msg.is::<()>());
assert!(msg.downcast::<()>().is_some());
}
#[test]
fn test_builtin_msg_equality() {
assert_eq!(QuitMsg, QuitMsg);
assert_eq!(InterruptMsg, InterruptMsg);
assert_eq!(SuspendMsg, SuspendMsg);
assert_eq!(ResumeMsg, ResumeMsg);
assert_eq!(FocusMsg, FocusMsg);
assert_eq!(BlurMsg, BlurMsg);
let size1 = WindowSizeMsg {
width: 80,
height: 24,
};
let size2 = WindowSizeMsg {
width: 80,
height: 24,
};
let size3 = WindowSizeMsg {
width: 120,
height: 40,
};
assert_eq!(size1, size2);
assert_ne!(size1, size3);
}
#[test]
fn test_builtin_msg_clone() {
let quit = QuitMsg;
let quit_copy = quit;
assert_eq!(quit, quit_copy);
let size = WindowSizeMsg {
width: 80,
height: 24,
};
let size_copy = size;
assert_eq!(size, size_copy);
}
#[test]
fn test_builtin_msg_copy() {
let quit = QuitMsg;
let quit_copy = quit; assert_eq!(quit, quit_copy);
let size = WindowSizeMsg {
width: 80,
height: 24,
};
let size_copy = size; assert_eq!(size, size_copy);
}
}