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