1use std::any::{Any, TypeId};
2
3use crate::prelude::{Constraints, Offset, PaintContext, Size};
4
5use self::{
6 contexts::{build_ctx::STATE_UPDATE_SUPRESSED, render_ctx::AnyRenderContext, Context},
7 events::Event,
8 implementors::{
9 inherited::InheritedWidgetOS, leaf::LeafWidgetOS, multi::MultiChildWidgetOS,
10 single::SingleChildWidgetOS, view::ViewWidgetOS,
11 },
12 local_key::LocalKeyAny,
13};
14
15pub mod contexts;
16pub mod events;
17pub mod implementors;
18pub mod impls;
19pub mod local_key;
20pub mod widget_eq;
21
22pub trait Widget: WidgetDebug {
23 fn unique_type(&self) -> TypeId;
27
28 fn kind(&self) -> WidgetKind;
29}
30
31#[derive(Clone, Copy)]
32pub enum WidgetKind<'a> {
33 View(&'a (dyn ViewWidgetOS + 'a)),
34 Inherited(&'a (dyn InheritedWidgetOS + 'a)),
35 Leaf(&'a (dyn LeafWidgetOS + 'a)),
36 SingleChild(&'a (dyn SingleChildWidgetOS + 'a)),
37 MultiChild(&'a (dyn MultiChildWidgetOS + 'a)),
38}
39
40#[derive(Clone)]
41pub struct WidgetPtr<'a> {
42 pub(crate) kind: WidgetKind<'a>,
44
45 pub(crate) owned: Option<*mut (dyn Widget + 'a)>,
47}
48
49impl<'a> WidgetPtr<'a> {
50 pub fn from_ref(widget: &'a (dyn Widget + 'a)) -> Self {
51 Self {
52 kind: widget.kind(),
53 owned: None,
54 }
55 }
56
57 pub fn from_owned(widget: Box<dyn Widget + 'a>) -> Self {
61 unsafe {
67 Self {
68 kind: std::mem::transmute::<WidgetKind, WidgetKind>(widget.kind()),
69 owned: Some(Box::into_raw(widget)),
70 }
71 }
72 }
73
74 pub unsafe fn drop(self) {
81 if let Some(widget) = self.owned {
82 drop(Box::from_raw(widget));
83 }
84 }
85
86 pub fn build(&self, ctx: &Context) -> Vec<WidgetPtr<'static>> {
90 let ptrs = match self.kind {
91 WidgetKind::View(w) => vec![w.build(ctx)],
92 WidgetKind::Leaf(_) => vec![],
93 WidgetKind::SingleChild(w) => vec![w.build(ctx)],
94 WidgetKind::MultiChild(w) => w.build(ctx),
95 WidgetKind::Inherited(w) => vec![w.child()],
96 };
97
98 unsafe { std::mem::transmute::<Vec<WidgetPtr>, Vec<WidgetPtr>>(ptrs) }
100 }
101
102 pub fn create_state(&self) -> Box<dyn Any> {
103 match self.kind {
104 WidgetKind::View(w) => w.create_state(),
105 WidgetKind::Leaf(w) => w.create_state(),
106 WidgetKind::SingleChild(w) => w.create_state(),
107 WidgetKind::MultiChild(w) => w.create_state(),
108 WidgetKind::Inherited(w) => w.create_state(),
109 }
110 }
111
112 pub fn create_render_state(&self) -> Box<dyn Any> {
113 match self.kind {
114 WidgetKind::View(_) => Box::new(()),
115 WidgetKind::Leaf(w) => w.create_render_state(),
116 WidgetKind::MultiChild(w) => w.create_render_state(),
117 WidgetKind::SingleChild(w) => w.create_render_state(),
118 WidgetKind::Inherited(w) => w.create_render_state(),
119 }
120 }
121
122 pub fn layout<'b>(
123 &self,
124 render_ctx: &'b mut AnyRenderContext,
125 constraints: Constraints,
126 ) -> Size {
127 match self.kind {
128 WidgetKind::View(w) => w.layout(render_ctx, constraints),
129 WidgetKind::Leaf(w) => w.layout(render_ctx, constraints),
130 WidgetKind::MultiChild(w) => w.layout(render_ctx, constraints),
131 WidgetKind::SingleChild(w) => w.layout(render_ctx, constraints),
132 WidgetKind::Inherited(w) => w.layout(render_ctx, constraints),
133 }
134 }
135
136 pub fn paint<'b>(
137 &self,
138 render_ctx: &'b mut AnyRenderContext,
139 piet: &mut PaintContext,
140 offset: &Offset,
141 ) {
142 match self.kind {
143 WidgetKind::View(w) => w.paint(render_ctx, piet, offset),
144 WidgetKind::Leaf(w) => w.paint(render_ctx, piet, offset),
145 WidgetKind::MultiChild(w) => w.paint(render_ctx, piet, offset),
146 WidgetKind::SingleChild(w) => w.paint(render_ctx, piet, offset),
147 WidgetKind::Inherited(w) => w.paint(render_ctx, piet, offset),
148 }
149 }
150
151 pub fn mount(&self, build_ctx: &Context) {
152 STATE_UPDATE_SUPRESSED.store(true, std::sync::atomic::Ordering::SeqCst);
153
154 match self.kind {
155 WidgetKind::View(w) => w.mount(build_ctx),
156 WidgetKind::Leaf(w) => w.mount(build_ctx),
157 WidgetKind::MultiChild(w) => w.mount(build_ctx),
158 WidgetKind::SingleChild(w) => w.mount(build_ctx),
159 WidgetKind::Inherited(w) => w.mount(build_ctx),
160 }
161
162 STATE_UPDATE_SUPRESSED.store(false, std::sync::atomic::Ordering::SeqCst);
163 }
164
165 pub fn unmount(&self, build_ctx: &Context) {
166 STATE_UPDATE_SUPRESSED.store(true, std::sync::atomic::Ordering::SeqCst);
167
168 match self.kind {
169 WidgetKind::View(w) => w.unmount(build_ctx),
170 WidgetKind::Leaf(w) => w.unmount(build_ctx),
171 WidgetKind::MultiChild(w) => w.unmount(build_ctx),
172 WidgetKind::SingleChild(w) => w.unmount(build_ctx),
173 WidgetKind::Inherited(w) => w.unmount(build_ctx),
174 }
175
176 STATE_UPDATE_SUPRESSED.store(false, std::sync::atomic::Ordering::SeqCst);
177 }
178
179 pub(crate) fn handle_event(&self, render_ctx: &mut AnyRenderContext, event: &Event) -> bool {
185 match self.kind {
186 WidgetKind::View(w) => w.handle_event(render_ctx, event),
187 WidgetKind::Leaf(w) => w.handle_event(render_ctx, event),
188 WidgetKind::SingleChild(w) => w.handle_event(render_ctx, event),
189 WidgetKind::MultiChild(w) => w.handle_event(render_ctx, event),
190 WidgetKind::Inherited(w) => w.handle_event(render_ctx, event),
191 }
192 }
193
194 pub fn can_update(&self, other: &WidgetPtr) -> bool {
198 self.unique_type_id() == other.unique_type_id()
199 && self.state_type_id() == other.state_type_id()
200 }
201
202 pub fn eq(&self, other: &WidgetPtr) -> bool {
204 if self.is_borrowed() {
207 if self.widget_ptr() != other.widget_ptr() {
208 return false;
209 }
210 }
211
212 match self.kind {
213 WidgetKind::View(w) => {
214 if let WidgetKind::View(wo) = other.kind {
215 return w.eq(wo.as_any_ext());
216 }
217 }
218 WidgetKind::Leaf(w) => {
219 if let WidgetKind::Leaf(wo) = other.kind {
220 return w.eq(wo.as_any_ext());
221 }
222 }
223 WidgetKind::SingleChild(w) => {
224 if let WidgetKind::SingleChild(wo) = other.kind {
225 return w.eq(wo.as_any_ext());
226 }
227 }
228 WidgetKind::MultiChild(w) => {
229 if let WidgetKind::MultiChild(wo) = other.kind {
230 return w.eq(wo.as_any_ext());
231 }
232 }
233 WidgetKind::Inherited(w) => {
234 if let WidgetKind::Inherited(wo) = other.kind {
235 return w.eq(wo.as_any_ext());
236 }
237 }
238 }
239
240 false
241 }
242
243 pub fn has_key(&self) -> bool {
244 self.local_key().is_some()
245 }
246
247 pub fn local_key(&self) -> Option<LocalKeyAny<'a>> {
248 match self.kind {
249 WidgetKind::View(w) => w.local_key(),
250 WidgetKind::Leaf(w) => w.local_key(),
251 WidgetKind::MultiChild(w) => w.local_key(),
252 WidgetKind::SingleChild(w) => w.local_key(),
253 WidgetKind::Inherited(w) => w.local_key(),
254 }
255 }
256
257 fn unique_type_id(&self) -> TypeId {
258 match self.kind {
259 WidgetKind::View(w) => w.unique_type(),
260 WidgetKind::Leaf(w) => w.unique_type(),
261 WidgetKind::SingleChild(w) => w.unique_type(),
262 WidgetKind::MultiChild(w) => w.unique_type(),
263 WidgetKind::Inherited(w) => w.unique_type(),
264 }
265 }
266
267 fn state_type_id(&self) -> TypeId {
268 match self.kind {
269 WidgetKind::View(w) => w.state_type_id(),
270 WidgetKind::Leaf(w) => w.state_type_id(),
271 WidgetKind::SingleChild(w) => w.state_type_id(),
272 WidgetKind::MultiChild(w) => w.state_type_id(),
273 WidgetKind::Inherited(w) => w.state_type_id(),
274 }
275 }
276
277 pub fn debug_name(&self) -> &'static str {
278 match self.kind {
279 WidgetKind::View(w) => w.debug_name(),
280 WidgetKind::Leaf(w) => w.debug_name(),
281 WidgetKind::SingleChild(w) => w.debug_name(),
282 WidgetKind::MultiChild(w) => w.debug_name(),
283 WidgetKind::Inherited(w) => w.debug_name(),
284 }
285 }
286
287 pub fn debug_name_short(&self) -> &'static str {
288 match self.kind {
289 WidgetKind::View(w) => w.debug_name_short(),
290 WidgetKind::Leaf(w) => w.debug_name_short(),
291 WidgetKind::SingleChild(w) => w.debug_name_short(),
292 WidgetKind::MultiChild(w) => w.debug_name_short(),
293 WidgetKind::Inherited(w) => w.debug_name_short(),
294 }
295 }
296
297 pub fn inherited_key(&self) -> TypeId {
298 match self.kind {
299 WidgetKind::Inherited(w) => w.inherited_key(),
300 _ => panic!("Widget::inherited_key() called on non-inherited widget"),
301 }
302 }
303
304 fn is_borrowed(&self) -> bool {
305 self.owned.is_none()
306 }
307
308 fn widget_ptr(&self) -> *const () {
309 match self.kind {
310 WidgetKind::View(w) => w as *const _ as *const (),
311 WidgetKind::Inherited(w) => w as *const _ as *const (),
312 WidgetKind::Leaf(w) => w as *const _ as *const (),
313 WidgetKind::SingleChild(w) => w as *const _ as *const (),
314 WidgetKind::MultiChild(w) => w as *const _ as *const (),
315 }
316 }
317}
318
319impl Default for WidgetPtr<'_> {
320 fn default() -> Self {
321 WidgetPtr::from_owned(Box::new(()))
322 }
323}
324
325pub trait WidgetDebug {
326 fn debug_name(&self) -> &'static str;
327 fn debug_name_short(&self) -> &'static str;
328}
329
330impl<T> WidgetDebug for T {
331 default fn debug_name(&self) -> &'static str {
332 let full_name = std::any::type_name::<T>();
333 full_name
334 }
335
336 fn debug_name_short(&self) -> &'static str {
337 let full_name = std::any::type_name::<T>();
338
339 let mut start = 0;
340 let mut end = full_name.len();
341
342 for (n, char) in full_name.chars().enumerate() {
343 if char == '<' {
344 end = n;
345 break;
346 } else if char == ':' {
347 start = n + 1;
348 }
349 }
350
351 &full_name[start..end]
352 }
353}
354
355pub trait WidgetUniqueType {
356 fn unique_type(&self) -> TypeId;
357}
358
359impl<T> WidgetUniqueType for T {
360 default fn unique_type(&self) -> TypeId {
361 unreachable!()
362 }
363}
364
365impl<T: Widget> WidgetUniqueType for T {
366 fn unique_type(&self) -> TypeId {
367 T::unique_type(self)
368 }
369}
370
371pub(crate) trait IntoWidgetPtr {
372 fn into_widget_ptr<'a>(self) -> WidgetPtr<'a>
373 where
374 Self: 'a;
375}
376
377impl<T: Widget> IntoWidgetPtr for T {
378 default fn into_widget_ptr<'a>(self) -> WidgetPtr<'a>
379 where
380 Self: 'a,
381 {
382 WidgetPtr::from_owned(Box::new(self))
383 }
384}
385
386impl<T: Widget> IntoWidgetPtr for &T {
387 default fn into_widget_ptr<'a>(self) -> WidgetPtr<'a>
388 where
389 Self: 'a,
390 {
391 WidgetPtr::from_ref(self)
392 }
393}
394
395impl IntoWidgetPtr for &dyn Widget {
396 default fn into_widget_ptr<'a>(self) -> WidgetPtr<'a>
397 where
398 Self: 'a,
399 {
400 WidgetPtr::from_ref(self)
401 }
402}
403
404pub(crate) use any_ext::*;
405
406mod any_ext {
407 use std::{
408 any::{Any, TypeId},
409 marker::PhantomData,
410 };
411
412 pub trait AnyExt: AsAny {
416 fn type_id(&self) -> TypeId;
417
418 fn as_any_ext<'a>(&'a self) -> &'a (dyn AnyExt + 'a);
420 }
421
422 impl<T> AnyExt for T {
423 fn type_id(&self) -> TypeId {
424 get_type_id::<T>()
425 }
426
427 fn as_any_ext<'a>(&'a self) -> &'a dyn AnyExt {
428 self
429 }
430 }
431
432 impl<'a> dyn AnyExt + 'a {
433 pub unsafe fn downcast_ref<T>(&self) -> Option<&T> {
485 match AnyExt::type_id(self) == get_type_id::<T>() {
486 true => Some(&*(self as *const _ as *const T)),
487 false => None,
488 }
489 }
490
491 pub unsafe fn downcast_mut<T>(&mut self) -> Option<&mut T> {
495 match AnyExt::type_id(self) == get_type_id::<T>() {
496 true => Some(&mut *(self as *mut _ as *mut T)),
497 false => None,
498 }
499 }
500 }
501
502 struct TypeIdKey<T>(PhantomData<T>);
503
504 impl<T> TypeIdKey<T> {
505 fn new() -> Self {
506 TypeIdKey(PhantomData)
507 }
508 }
509
510 fn get_type_id<T>() -> TypeId {
511 unsafe {
512 let key = <TypeIdKey<T>>::new();
513
514 let any = std::mem::transmute::<&dyn AsAny, &'static dyn AsAny>(&key);
519 let any = any.as_any();
520 Any::type_id(any)
521 }
522 }
523
524 pub trait AsAny {
526 fn as_any(&'static self) -> &dyn Any;
527 }
528
529 impl<T> AsAny for T {
530 fn as_any(&'static self) -> &dyn Any {
531 self
532 }
533 }
534
535 #[cfg(test)]
536 mod test {
537 use super::*;
538
539 #[test]
540 fn should_downcast() {
541 unsafe {
542 assert!((&16usize as &dyn AnyExt).downcast_ref::<usize>().is_some());
543 assert!((&String::new() as &dyn AnyExt)
544 .downcast_ref::<String>()
545 .is_some());
546 assert!((&std::sync::Mutex::new(2u8) as &dyn AnyExt)
547 .downcast_ref::<std::sync::Mutex<u8>>()
548 .is_some());
549 }
550 }
551
552 #[test]
553 fn should_not_downcast() {
554 unsafe {
555 assert!((&16usize as &dyn AnyExt).downcast_ref::<u8>().is_none());
556 assert!((&std::sync::Mutex::new(2u8) as &dyn AnyExt)
557 .downcast_ref::<std::sync::Mutex<usize>>()
558 .is_none());
559 }
560 }
561 }
562}