1#![allow(clippy::await_holding_refcell_ref, clippy::type_complexity)]
2pub(crate) mod helpers;
3
4pub mod component;
5
6#[allow(deprecated)]
7pub use component::Component;
8
9mod cache;
10
11use crate::core::Element;
12use crate::core::layout::{self, Layout};
13use crate::core::mouse;
14use crate::core::overlay;
15use crate::core::renderer;
16use crate::core::widget::tree::{self, Tree};
17use crate::core::widget::{self, Widget};
18use crate::core::{self, Event, Length, Rectangle, Shell, Size, Vector};
19
20use ouroboros::self_referencing;
21use rustc_hash::FxHasher;
22use std::cell::RefCell;
23use std::hash::{Hash, Hasher as H};
24use std::rc::Rc;
25
26#[cfg(feature = "lazy")]
28pub struct Lazy<'a, Message, Theme, Renderer, Dependency, View> {
29 dependency: Dependency,
30 view: Box<dyn Fn(&Dependency) -> View + 'a>,
31 element: RefCell<Option<Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>>>,
32}
33
34impl<'a, Message, Theme, Renderer, Dependency, View>
35 Lazy<'a, Message, Theme, Renderer, Dependency, View>
36where
37 Dependency: Hash + 'a,
38 View: Into<Element<'static, Message, Theme, Renderer>>,
39{
40 pub fn new(dependency: Dependency, view: impl Fn(&Dependency) -> View + 'a) -> Self {
43 Self {
44 dependency,
45 view: Box::new(view),
46 element: RefCell::new(None),
47 }
48 }
49
50 fn with_element<T>(&self, f: impl FnOnce(&Element<'_, Message, Theme, Renderer>) -> T) -> T {
51 f(self
52 .element
53 .borrow()
54 .as_ref()
55 .unwrap()
56 .borrow()
57 .as_ref()
58 .unwrap())
59 }
60
61 fn with_element_mut<T>(
62 &self,
63 f: impl FnOnce(&mut Element<'_, Message, Theme, Renderer>) -> T,
64 ) -> T {
65 f(self
66 .element
67 .borrow()
68 .as_ref()
69 .unwrap()
70 .borrow_mut()
71 .as_mut()
72 .unwrap())
73 }
74}
75
76struct Internal<Message, Theme, Renderer> {
77 element: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,
78 hash: u64,
79}
80
81impl<'a, Message, Theme, Renderer, Dependency, View> Widget<Message, Theme, Renderer>
82 for Lazy<'a, Message, Theme, Renderer, Dependency, View>
83where
84 View: Into<Element<'static, Message, Theme, Renderer>> + 'static,
85 Dependency: Hash + 'a,
86 Message: 'static,
87 Theme: 'static,
88 Renderer: core::Renderer + 'static,
89{
90 fn tag(&self) -> tree::Tag {
91 struct Tag<T>(T);
92 tree::Tag::of::<Tag<View>>()
93 }
94
95 fn state(&self) -> tree::State {
96 let hash = {
97 let mut hasher = FxHasher::default();
98 self.dependency.hash(&mut hasher);
99
100 hasher.finish()
101 };
102
103 let element = Rc::new(RefCell::new(Some((self.view)(&self.dependency).into())));
104
105 (*self.element.borrow_mut()) = Some(element.clone());
106
107 tree::State::new(Internal { element, hash })
108 }
109
110 fn diff(&mut self, tree: &mut Tree) {
111 let current = tree
112 .state
113 .downcast_mut::<Internal<Message, Theme, Renderer>>();
114
115 let new_hash = {
116 let mut hasher = FxHasher::default();
117 self.dependency.hash(&mut hasher);
118
119 hasher.finish()
120 };
121
122 if current.hash != new_hash {
123 current.hash = new_hash;
124
125 let element = (self.view)(&self.dependency).into();
126 current.element = Rc::new(RefCell::new(Some(element)));
127 }
128
129 (*self.element.borrow_mut()) = Some(current.element.clone());
130
131 self.with_element_mut(|element| {
132 tree.diff_children(std::slice::from_mut(&mut element.as_widget_mut()));
133 });
134 }
135
136 fn size(&self) -> Size<Length> {
137 self.with_element(|element| element.as_widget().size())
138 }
139
140 fn layout(
141 &mut self,
142 tree: &mut Tree,
143 renderer: &Renderer,
144 limits: &layout::Limits,
145 ) -> layout::Node {
146 self.with_element_mut(|element| {
147 element
148 .as_widget_mut()
149 .layout(&mut tree.children[0], renderer, limits)
150 })
151 }
152
153 fn operate(
154 &mut self,
155 tree: &mut Tree,
156 layout: Layout<'_>,
157 renderer: &Renderer,
158 operation: &mut dyn widget::Operation,
159 ) {
160 self.with_element_mut(|element| {
161 element
162 .as_widget_mut()
163 .operate(&mut tree.children[0], layout, renderer, operation);
164 });
165 }
166
167 fn update(
168 &mut self,
169 tree: &mut Tree,
170 event: &Event,
171 layout: Layout<'_>,
172 cursor: mouse::Cursor,
173 renderer: &Renderer,
174 shell: &mut Shell<'_, Message>,
175 viewport: &Rectangle,
176 ) {
177 self.with_element_mut(|element| {
178 element.as_widget_mut().update(
179 &mut tree.children[0],
180 event,
181 layout,
182 cursor,
183 renderer,
184 shell,
185 viewport,
186 );
187 });
188 }
189
190 fn mouse_interaction(
191 &self,
192 tree: &Tree,
193 layout: Layout<'_>,
194 cursor: mouse::Cursor,
195 viewport: &Rectangle,
196 renderer: &Renderer,
197 ) -> mouse::Interaction {
198 self.with_element(|element| {
199 element.as_widget().mouse_interaction(
200 &tree.children[0],
201 layout,
202 cursor,
203 viewport,
204 renderer,
205 )
206 })
207 }
208
209 fn draw(
210 &self,
211 tree: &Tree,
212 renderer: &mut Renderer,
213 theme: &Theme,
214 style: &renderer::Style,
215 layout: Layout<'_>,
216 cursor: mouse::Cursor,
217 viewport: &Rectangle,
218 ) {
219 self.with_element(|element| {
220 element.as_widget().draw(
221 &tree.children[0],
222 renderer,
223 theme,
224 style,
225 layout,
226 cursor,
227 viewport,
228 );
229 });
230 }
231
232 fn overlay<'b>(
233 &'b mut self,
234 tree: &'b mut Tree,
235 layout: Layout<'b>,
236 renderer: &Renderer,
237 viewport: &Rectangle,
238 translation: Vector,
239 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
240 let overlay = InnerBuilder {
241 cell: self.element.borrow().as_ref().unwrap().clone(),
242 element: self
243 .element
244 .borrow()
245 .as_ref()
246 .unwrap()
247 .borrow_mut()
248 .take()
249 .unwrap(),
250 tree: &mut tree.children[0],
251 layout,
252 overlay_builder: |element, tree, layout| {
253 element
254 .as_widget_mut()
255 .overlay(tree, *layout, renderer, viewport, translation)
256 .map(|overlay| RefCell::new(overlay::Nested::new(overlay)))
257 },
258 }
259 .build();
260
261 #[allow(clippy::redundant_closure_for_method_calls)]
262 if overlay.with_overlay(|overlay| overlay.is_some()) {
263 Some(overlay::Element::new(Box::new(Overlay(Some(overlay)))))
264 } else {
265 let heads = overlay.into_heads();
266
267 *self.element.borrow().as_ref().unwrap().borrow_mut() = Some(heads.element);
271
272 None
273 }
274 }
275}
276
277#[self_referencing]
278struct Inner<'a, Message: 'a, Theme: 'a, Renderer: 'a> {
279 cell: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,
280 element: Element<'static, Message, Theme, Renderer>,
281 tree: &'a mut Tree,
282 layout: Layout<'a>,
283
284 #[borrows(mut element, mut tree, layout)]
285 #[not_covariant]
286 overlay: Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,
287}
288
289struct Overlay<'a, Message, Theme, Renderer>(Option<Inner<'a, Message, Theme, Renderer>>);
290
291impl<Message, Theme, Renderer> Drop for Overlay<'_, Message, Theme, Renderer> {
292 fn drop(&mut self) {
293 let heads = self.0.take().unwrap().into_heads();
294 (*heads.cell.borrow_mut()) = Some(heads.element);
295 }
296}
297
298impl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {
299 fn with_overlay_maybe<T>(
300 &self,
301 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
302 ) -> Option<T> {
303 self.0
304 .as_ref()
305 .unwrap()
306 .with_overlay(|overlay| overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut())))
307 }
308
309 fn with_overlay_mut_maybe<T>(
310 &mut self,
311 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
312 ) -> Option<T> {
313 self.0
314 .as_mut()
315 .unwrap()
316 .with_overlay_mut(|overlay| overlay.as_mut().map(|nested| (f)(nested.get_mut())))
317 }
318}
319
320impl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
321 for Overlay<'_, Message, Theme, Renderer>
322where
323 Renderer: core::Renderer,
324{
325 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
326 self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
327 .unwrap_or_default()
328 }
329
330 fn draw(
331 &self,
332 renderer: &mut Renderer,
333 theme: &Theme,
334 style: &renderer::Style,
335 layout: Layout<'_>,
336 cursor: mouse::Cursor,
337 ) {
338 let _ = self.with_overlay_maybe(|overlay| {
339 overlay.draw(renderer, theme, style, layout, cursor);
340 });
341 }
342
343 fn mouse_interaction(
344 &self,
345 layout: Layout<'_>,
346 cursor: mouse::Cursor,
347 renderer: &Renderer,
348 ) -> mouse::Interaction {
349 self.with_overlay_maybe(|overlay| overlay.mouse_interaction(layout, cursor, renderer))
350 .unwrap_or_default()
351 }
352
353 fn update(
354 &mut self,
355 event: &Event,
356 layout: Layout<'_>,
357 cursor: mouse::Cursor,
358 renderer: &Renderer,
359 shell: &mut Shell<'_, Message>,
360 ) {
361 let _ = self.with_overlay_mut_maybe(|overlay| {
362 overlay.update(event, layout, cursor, renderer, shell);
363 });
364 }
365}
366
367impl<'a, Message, Theme, Renderer, Dependency, View>
368 From<Lazy<'a, Message, Theme, Renderer, Dependency, View>>
369 for Element<'a, Message, Theme, Renderer>
370where
371 View: Into<Element<'static, Message, Theme, Renderer>> + 'static,
372 Renderer: core::Renderer + 'static,
373 Message: 'static,
374 Theme: 'static,
375 Dependency: Hash + 'a,
376{
377 fn from(lazy: Lazy<'a, Message, Theme, Renderer, Dependency, View>) -> Self {
378 Self::new(lazy)
379 }
380}