1use std::any::Any;
53use std::fmt;
54
55use iced::{Element, Subscription, Task, Theme};
56
57pub trait Demo: Sized + 'static {
63 type Message: Any + Clone + Send + fmt::Debug;
64
65 fn boot() -> (Self, Task<Self::Message>);
70
71 fn update(&mut self, message: Self::Message) -> Task<Self::Message>;
72
73 fn view(&self) -> Element<'_, Self::Message>;
74
75 fn theme(&self) -> Theme;
76
77 fn set_theme(&mut self, theme: Theme);
80
81 fn subscription(&self) -> Subscription<Self::Message> {
82 Subscription::none()
83 }
84}
85
86pub struct SceneMessage(Box<dyn ErasedMessage>);
89
90trait ErasedMessage: Any + Send {
91 fn clone_box(&self) -> Box<dyn ErasedMessage>;
92 fn into_any(self: Box<Self>) -> Box<dyn Any>;
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
94}
95
96impl<M: Any + Clone + Send + fmt::Debug> ErasedMessage for M {
97 fn clone_box(&self) -> Box<dyn ErasedMessage> {
98 Box::new(self.clone())
99 }
100
101 fn into_any(self: Box<Self>) -> Box<dyn Any> {
102 self
103 }
104
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 fmt::Debug::fmt(self, f)
107 }
108}
109
110impl SceneMessage {
111 pub fn new<M: Any + Clone + Send + fmt::Debug>(message: M) -> Self {
112 Self(Box::new(message))
113 }
114
115 pub fn downcast<M: Any>(self) -> Result<M, Self> {
121 if (*self.0).type_id() != std::any::TypeId::of::<M>() {
122 return Err(self);
123 }
124
125 match self.0.into_any().downcast::<M>() {
126 Ok(message) => Ok(*message),
127 Err(_) => unreachable!("type id was checked above"),
128 }
129 }
130}
131
132impl Clone for SceneMessage {
133 fn clone(&self) -> Self {
134 Self(self.0.clone_box())
135 }
136}
137
138impl fmt::Debug for SceneMessage {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 self.0.fmt(f)
141 }
142}
143
144pub trait Scene {
146 fn update(&mut self, message: SceneMessage) -> Task<SceneMessage>;
147 fn view(&self) -> Element<'_, SceneMessage>;
148 fn theme(&self) -> Theme;
149 fn set_theme(&mut self, theme: Theme);
150 fn subscription(&self) -> Subscription<SceneMessage>;
151}
152
153struct Erased<A>(A);
154
155impl<A: Demo> Scene for Erased<A> {
156 fn update(&mut self, message: SceneMessage) -> Task<SceneMessage> {
157 match message.downcast::<A::Message>() {
158 Ok(message) => self.0.update(message).map(SceneMessage::new::<A::Message>),
159 Err(_) => Task::none(),
160 }
161 }
162
163 fn view(&self) -> Element<'_, SceneMessage> {
164 self.0.view().map(SceneMessage::new::<A::Message>)
165 }
166
167 fn theme(&self) -> Theme {
168 self.0.theme()
169 }
170
171 fn set_theme(&mut self, theme: Theme) {
172 self.0.set_theme(theme);
173 }
174
175 fn subscription(&self) -> Subscription<SceneMessage> {
176 self.0.subscription().map(SceneMessage::new::<A::Message>)
179 }
180}
181
182pub fn erase<A: Demo>() -> (Box<dyn Scene>, Task<SceneMessage>) {
184 let (app, task) = A::boot();
185
186 (
187 Box::new(Erased(app)),
188 task.map(SceneMessage::new::<A::Message>),
189 )
190}
191
192pub struct SceneDef {
194 pub name: &'static str,
196 pub boot: fn() -> (Box<dyn Scene>, Task<SceneMessage>),
197}