waterui_core/components/
anyview.rs1use core::{
8 any::{Any, TypeId, type_name},
9 fmt::Debug,
10};
11
12use alloc::boxed::Box;
13
14use crate::{Environment, View, layout::StretchAxis};
15
16trait AnyViewImpl: 'static {
17 fn body(self: Box<Self>, env: Environment) -> AnyView;
18 fn type_id(&self) -> TypeId {
19 TypeId::of::<Self>()
20 }
21 fn name(&self) -> &'static str {
22 type_name::<Self>()
23 }
24 fn stretch_axis(&self) -> StretchAxis;
25}
26
27impl<T: View> AnyViewImpl for T {
28 fn body(self: Box<Self>, env: Environment) -> AnyView {
29 AnyView::new(View::body(*self, &env))
30 }
31 fn stretch_axis(&self) -> StretchAxis {
32 View::stretch_axis(self)
33 }
34}
35
36#[must_use]
40pub struct AnyView(Box<dyn AnyViewImpl>);
41
42impl Debug for AnyView {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 f.write_fmt(format_args!("AnyView({})", self.name()))
45 }
46}
47
48impl Default for AnyView {
49 fn default() -> Self {
50 Self::new(())
51 }
52}
53
54impl AnyView {
55 pub fn new<V: View>(view: V) -> Self {
60 #[allow(clippy::missing_panics_doc)]
61 if TypeId::of::<V>() == TypeId::of::<Self>() {
62 let any = &mut Some(view) as &mut dyn Any;
63 return any
64 .downcast_mut::<Option<Self>>()
65 .expect("downcast to option should succeed")
66 .take()
67 .expect("option should contain a value"); }
69
70 Self(Box::new(view))
71 }
72
73 #[must_use]
75 pub fn is<T: 'static>(&self) -> bool {
76 self.type_id() == TypeId::of::<T>()
77 }
78
79 #[must_use]
81 pub fn type_id(&self) -> TypeId {
82 AnyViewImpl::type_id(&*self.0)
83 }
84
85 #[must_use]
87 pub fn name(&self) -> &'static str {
88 AnyViewImpl::name(&*self.0)
89 }
90
91 #[must_use]
96 pub fn stretch_axis(&self) -> StretchAxis {
97 AnyViewImpl::stretch_axis(&*self.0)
98 }
99
100 #[must_use]
105 pub unsafe fn downcast_unchecked<T: 'static>(self) -> Box<T> {
106 unsafe { Box::from_raw(Box::into_raw(self.0).cast::<T>()) }
107 }
108
109 #[must_use]
114 pub const unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
115 unsafe { &*(&raw const *self.0).cast::<T>() }
116 }
117
118 pub const unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
123 unsafe { &mut *(&raw mut *self.0).cast::<T>() }
124 }
125
126 pub fn downcast<T: 'static>(self) -> Result<Box<T>, Self> {
135 if self.is::<T>() {
136 unsafe { Ok(self.downcast_unchecked()) }
137 } else {
138 Err(self)
139 }
140 }
141
142 #[must_use]
146 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
147 unsafe { self.is::<T>().then(|| self.downcast_ref_unchecked()) }
148 }
149
150 pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
154 unsafe { self.is::<T>().then(move || self.downcast_mut_unchecked()) }
155 }
156}
157
158impl View for AnyView {
159 fn body(self, env: &Environment) -> impl View {
160 self.0.body(env.clone())
161 }
162}
163
164#[cfg(test)]
165mod test {
166 use core::any::TypeId;
167
168 use super::AnyView;
169
170 #[test]
171 pub fn get_type_id() {
172 assert_eq!(AnyView::new(()).type_id(), TypeId::of::<()>());
173 }
174}