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, Clipboard, 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 children(&self) -> Vec<Tree> {
111 self.with_element(|element| vec![Tree::new(element.as_widget())])
112 }
113
114 fn diff(&self, tree: &mut Tree) {
115 let current = tree
116 .state
117 .downcast_mut::<Internal<Message, Theme, Renderer>>();
118
119 let new_hash = {
120 let mut hasher = FxHasher::default();
121 self.dependency.hash(&mut hasher);
122
123 hasher.finish()
124 };
125
126 if current.hash != new_hash {
127 current.hash = new_hash;
128
129 let element = (self.view)(&self.dependency).into();
130 current.element = Rc::new(RefCell::new(Some(element)));
131
132 (*self.element.borrow_mut()) = Some(current.element.clone());
133 self.with_element(|element| {
134 tree.diff_children(std::slice::from_ref(&element.as_widget()));
135 });
136 } else {
137 (*self.element.borrow_mut()) = Some(current.element.clone());
138 }
139 }
140
141 fn size(&self) -> Size<Length> {
142 self.with_element(|element| element.as_widget().size())
143 }
144
145 fn size_hint(&self) -> Size<Length> {
146 Size {
147 width: Length::Shrink,
148 height: Length::Shrink,
149 }
150 }
151
152 fn layout(
153 &mut self,
154 tree: &mut Tree,
155 renderer: &Renderer,
156 limits: &layout::Limits,
157 ) -> layout::Node {
158 self.with_element_mut(|element| {
159 element
160 .as_widget_mut()
161 .layout(&mut tree.children[0], renderer, limits)
162 })
163 }
164
165 fn operate(
166 &mut self,
167 tree: &mut Tree,
168 layout: Layout<'_>,
169 renderer: &Renderer,
170 operation: &mut dyn widget::Operation,
171 ) {
172 self.with_element_mut(|element| {
173 element
174 .as_widget_mut()
175 .operate(&mut tree.children[0], layout, renderer, operation);
176 });
177 }
178
179 fn update(
180 &mut self,
181 tree: &mut Tree,
182 event: &Event,
183 layout: Layout<'_>,
184 cursor: mouse::Cursor,
185 renderer: &Renderer,
186 clipboard: &mut dyn Clipboard,
187 shell: &mut Shell<'_, Message>,
188 viewport: &Rectangle,
189 ) {
190 self.with_element_mut(|element| {
191 element.as_widget_mut().update(
192 &mut tree.children[0],
193 event,
194 layout,
195 cursor,
196 renderer,
197 clipboard,
198 shell,
199 viewport,
200 );
201 });
202 }
203
204 fn mouse_interaction(
205 &self,
206 tree: &Tree,
207 layout: Layout<'_>,
208 cursor: mouse::Cursor,
209 viewport: &Rectangle,
210 renderer: &Renderer,
211 ) -> mouse::Interaction {
212 self.with_element(|element| {
213 element.as_widget().mouse_interaction(
214 &tree.children[0],
215 layout,
216 cursor,
217 viewport,
218 renderer,
219 )
220 })
221 }
222
223 fn draw(
224 &self,
225 tree: &Tree,
226 renderer: &mut Renderer,
227 theme: &Theme,
228 style: &renderer::Style,
229 layout: Layout<'_>,
230 cursor: mouse::Cursor,
231 viewport: &Rectangle,
232 ) {
233 self.with_element(|element| {
234 element.as_widget().draw(
235 &tree.children[0],
236 renderer,
237 theme,
238 style,
239 layout,
240 cursor,
241 viewport,
242 );
243 });
244 }
245
246 fn overlay<'b>(
247 &'b mut self,
248 tree: &'b mut Tree,
249 layout: Layout<'b>,
250 renderer: &Renderer,
251 viewport: &Rectangle,
252 translation: Vector,
253 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
254 let overlay = InnerBuilder {
255 cell: self.element.borrow().as_ref().unwrap().clone(),
256 element: self
257 .element
258 .borrow()
259 .as_ref()
260 .unwrap()
261 .borrow_mut()
262 .take()
263 .unwrap(),
264 tree: &mut tree.children[0],
265 layout,
266 overlay_builder: |element, tree, layout| {
267 element
268 .as_widget_mut()
269 .overlay(tree, *layout, renderer, viewport, translation)
270 .map(|overlay| RefCell::new(overlay::Nested::new(overlay)))
271 },
272 }
273 .build();
274
275 #[allow(clippy::redundant_closure_for_method_calls)]
276 if overlay.with_overlay(|overlay| overlay.is_some()) {
277 Some(overlay::Element::new(Box::new(Overlay(Some(overlay)))))
278 } else {
279 let heads = overlay.into_heads();
280
281 *self.element.borrow().as_ref().unwrap().borrow_mut() = Some(heads.element);
285
286 None
287 }
288 }
289}
290
291#[self_referencing]
292struct Inner<'a, Message: 'a, Theme: 'a, Renderer: 'a> {
293 cell: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,
294 element: Element<'static, Message, Theme, Renderer>,
295 tree: &'a mut Tree,
296 layout: Layout<'a>,
297
298 #[borrows(mut element, mut tree, layout)]
299 #[not_covariant]
300 overlay: Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,
301}
302
303struct Overlay<'a, Message, Theme, Renderer>(Option<Inner<'a, Message, Theme, Renderer>>);
304
305impl<Message, Theme, Renderer> Drop for Overlay<'_, Message, Theme, Renderer> {
306 fn drop(&mut self) {
307 let heads = self.0.take().unwrap().into_heads();
308 (*heads.cell.borrow_mut()) = Some(heads.element);
309 }
310}
311
312impl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {
313 fn with_overlay_maybe<T>(
314 &self,
315 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
316 ) -> Option<T> {
317 self.0
318 .as_ref()
319 .unwrap()
320 .with_overlay(|overlay| overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut())))
321 }
322
323 fn with_overlay_mut_maybe<T>(
324 &mut self,
325 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
326 ) -> Option<T> {
327 self.0
328 .as_mut()
329 .unwrap()
330 .with_overlay_mut(|overlay| overlay.as_mut().map(|nested| (f)(nested.get_mut())))
331 }
332}
333
334impl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
335 for Overlay<'_, Message, Theme, Renderer>
336where
337 Renderer: core::Renderer,
338{
339 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
340 self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
341 .unwrap_or_default()
342 }
343
344 fn draw(
345 &self,
346 renderer: &mut Renderer,
347 theme: &Theme,
348 style: &renderer::Style,
349 layout: Layout<'_>,
350 cursor: mouse::Cursor,
351 ) {
352 let _ = self.with_overlay_maybe(|overlay| {
353 overlay.draw(renderer, theme, style, layout, cursor);
354 });
355 }
356
357 fn mouse_interaction(
358 &self,
359 layout: Layout<'_>,
360 cursor: mouse::Cursor,
361 renderer: &Renderer,
362 ) -> mouse::Interaction {
363 self.with_overlay_maybe(|overlay| overlay.mouse_interaction(layout, cursor, renderer))
364 .unwrap_or_default()
365 }
366
367 fn update(
368 &mut self,
369 event: &Event,
370 layout: Layout<'_>,
371 cursor: mouse::Cursor,
372 renderer: &Renderer,
373 clipboard: &mut dyn Clipboard,
374 shell: &mut Shell<'_, Message>,
375 ) {
376 let _ = self.with_overlay_mut_maybe(|overlay| {
377 overlay.update(event, layout, cursor, renderer, clipboard, shell);
378 });
379 }
380}
381
382impl<'a, Message, Theme, Renderer, Dependency, View>
383 From<Lazy<'a, Message, Theme, Renderer, Dependency, View>>
384 for Element<'a, Message, Theme, Renderer>
385where
386 View: Into<Element<'static, Message, Theme, Renderer>> + 'static,
387 Renderer: core::Renderer + 'static,
388 Message: 'static,
389 Theme: 'static,
390 Dependency: Hash + 'a,
391{
392 fn from(lazy: Lazy<'a, Message, Theme, Renderer, Dependency, View>) -> Self {
393 Self::new(lazy)
394 }
395}