1use crate::{
2 context::ContextStack,
3 element::{ElementKey, ElementType},
4 hook::{AnyHook, Hook, Hooks},
5 multimap::RemoveOnlyMultimap,
6 props::{AnyProps, Props},
7 render::{ComponentDrawer, ComponentUpdater, UpdateContext},
8};
9use core::{
10 any::{Any, TypeId},
11 marker::PhantomData,
12 pin::Pin,
13 task::{Context, Poll},
14};
15use futures::future::poll_fn;
16use taffy::NodeId;
17
18pub(crate) struct ComponentHelper<C: Component> {
19 _marker: PhantomData<C>,
20}
21
22impl<C: Component> ComponentHelper<C> {
23 pub fn boxed() -> Box<dyn ComponentHelperExt> {
24 Box::new(Self {
25 _marker: PhantomData,
26 })
27 }
28}
29
30#[doc(hidden)]
31pub trait ComponentHelperExt: Any + Send + Sync {
32 fn new_component(&self, props: AnyProps) -> Box<dyn AnyComponent>;
33 fn update_component(
34 &self,
35 component: &mut Box<dyn AnyComponent>,
36 props: AnyProps,
37 hooks: Hooks,
38 updater: &mut ComponentUpdater,
39 );
40 fn component_type_id(&self) -> TypeId;
41 fn copy(&self) -> Box<dyn ComponentHelperExt>;
42}
43
44impl<C: Component> ComponentHelperExt for ComponentHelper<C> {
45 fn new_component(&self, props: AnyProps) -> Box<dyn AnyComponent> {
46 Box::new(C::new(unsafe { props.downcast_ref_unchecked() }))
47 }
48
49 fn update_component(
50 &self,
51 component: &mut Box<dyn AnyComponent>,
52 props: AnyProps,
53 hooks: Hooks,
54 updater: &mut ComponentUpdater,
55 ) {
56 component.update(props, hooks, updater);
57 }
58
59 fn component_type_id(&self) -> TypeId {
60 TypeId::of::<C>()
61 }
62
63 fn copy(&self) -> Box<dyn ComponentHelperExt> {
64 Self::boxed()
65 }
66}
67
68pub trait Component: Any + Send + Sync + Unpin {
74 type Props<'a>: Props
76 where
77 Self: 'a;
78
79 fn new(props: &Self::Props<'_>) -> Self;
81
82 fn update(
84 &mut self,
85 _props: &mut Self::Props<'_>,
86 _hooks: Hooks,
87 _updater: &mut ComponentUpdater,
88 ) {
89 }
90
91 fn draw(&mut self, _drawer: &mut ComponentDrawer<'_>) {}
93
94 fn poll_change(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
97 Poll::Pending
98 }
99}
100
101impl<C: Component> ElementType for C {
102 type Props<'a> = C::Props<'a>;
103}
104
105#[doc(hidden)]
106pub trait AnyComponent: Any + Send + Sync + Unpin {
107 fn update(&mut self, props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater);
108 fn draw(&mut self, drawer: &mut ComponentDrawer<'_>);
109 fn poll_change(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>;
110}
111
112impl<C: Any + Component> AnyComponent for C {
113 fn update(&mut self, mut props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater) {
114 Component::update(
115 self,
116 unsafe { props.downcast_mut_unchecked() },
117 hooks,
118 updater,
119 );
120 }
121
122 fn draw(&mut self, drawer: &mut ComponentDrawer<'_>) {
123 Component::draw(self, drawer);
124 }
125
126 fn poll_change(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
127 Component::poll_change(self, cx)
128 }
129}
130
131pub(crate) struct InstantiatedComponent {
132 node_id: NodeId,
133 component: Box<dyn AnyComponent>,
134 children: Components,
135 helper: Box<dyn ComponentHelperExt>,
136 hooks: Vec<Box<dyn AnyHook>>,
137 first_update: bool,
138 has_transparent_layout: bool,
139}
140
141impl InstantiatedComponent {
142 pub fn new(node_id: NodeId, props: AnyProps, helper: Box<dyn ComponentHelperExt>) -> Self {
143 Self {
144 node_id,
145 component: helper.new_component(props),
146 children: Components::default(),
147 helper,
148 hooks: Default::default(),
149 first_update: true,
150 has_transparent_layout: false,
151 }
152 }
153
154 pub fn node_id(&self) -> NodeId {
155 self.node_id
156 }
157
158 pub fn component(&self) -> &dyn AnyComponent {
159 &*self.component
160 }
161
162 pub fn update(
163 &mut self,
164 context: &mut UpdateContext<'_>,
165 unattached_child_node_ids: &mut Vec<NodeId>,
166 component_context_stack: &mut ContextStack<'_>,
167 props: AnyProps,
168 ) {
169 let mut updater = ComponentUpdater::new(
170 self.node_id,
171 &mut self.children,
172 unattached_child_node_ids,
173 context,
174 component_context_stack,
175 );
176 self.hooks.pre_component_update(&mut updater);
177 self.helper.update_component(
178 &mut self.component,
179 props,
180 Hooks::new(&mut self.hooks, self.first_update),
181 &mut updater,
182 );
183 self.hooks.post_component_update(&mut updater);
184 self.first_update = false;
185 self.has_transparent_layout = updater.has_transparent_layout();
186 }
187
188 pub fn draw(&mut self, drawer: &mut ComponentDrawer<'_>) {
189 if self.has_transparent_layout {
190 if let Some(child) = self.children.components.iter().next().as_ref() {
193 drawer.for_child_node_layout(child.node_id, |drawer| {
194 self.hooks.pre_component_draw(drawer);
195 self.component.draw(drawer);
196 });
197 } else {
198 self.hooks.pre_component_draw(drawer);
199 self.component.draw(drawer);
200 }
201 } else {
202 self.hooks.pre_component_draw(drawer);
203 self.component.draw(drawer);
204 }
205
206 drawer.with_clip_rect_for_children(|drawer| {
207 self.children.draw(drawer);
208 });
209
210 if self.has_transparent_layout {
211 if let Some(child) = self.children.components.iter().next().as_ref() {
212 drawer.for_child_node_layout(child.node_id, |drawer| {
213 self.hooks.post_component_draw(drawer);
214 });
215 } else {
216 self.hooks.post_component_draw(drawer);
217 }
218 } else {
219 self.hooks.post_component_draw(drawer);
220 }
221 }
222
223 pub async fn wait(&mut self) {
224 let mut self_mut = Pin::new(self);
225 poll_fn(|cx| self_mut.as_mut().poll_change(cx)).await;
226 }
227
228 fn poll_change(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
229 let component_status = Pin::new(&mut *self.component).poll_change(cx);
230 let children_status = Pin::new(&mut self.children).poll_change(cx);
231 let hooks_status = Pin::new(&mut self.hooks).poll_change(cx);
232 if component_status.is_ready() || children_status.is_ready() || hooks_status.is_ready() {
233 Poll::Ready(())
234 } else {
235 Poll::Pending
236 }
237 }
238}
239
240#[derive(Default)]
241pub(crate) struct Components {
242 pub components: RemoveOnlyMultimap<ElementKey, InstantiatedComponent>,
243}
244
245impl Components {
246 pub fn draw(&mut self, drawer: &mut ComponentDrawer<'_>) {
247 for component in self.components.iter_mut() {
248 if component.has_transparent_layout {
249 component.draw(drawer);
250 } else {
251 drawer.for_child_node_layout(component.node_id, |drawer| {
252 component.draw(drawer);
253 });
254 }
255 }
256 }
257
258 pub fn poll_change(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
259 let mut is_ready = false;
260 for component in self.components.iter_mut() {
261 if Pin::new(&mut *component).poll_change(cx).is_ready() {
262 is_ready = true;
263 }
264 }
265 if is_ready {
266 Poll::Ready(())
267 } else {
268 Poll::Pending
269 }
270 }
271}