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 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 shell: &mut Shell<'_, Message>,
187 viewport: &Rectangle,
188 ) {
189 self.with_element_mut(|element| {
190 element.as_widget_mut().update(
191 &mut tree.children[0],
192 event,
193 layout,
194 cursor,
195 renderer,
196 shell,
197 viewport,
198 );
199 });
200 }
201
202 fn mouse_interaction(
203 &self,
204 tree: &Tree,
205 layout: Layout<'_>,
206 cursor: mouse::Cursor,
207 viewport: &Rectangle,
208 renderer: &Renderer,
209 ) -> mouse::Interaction {
210 self.with_element(|element| {
211 element.as_widget().mouse_interaction(
212 &tree.children[0],
213 layout,
214 cursor,
215 viewport,
216 renderer,
217 )
218 })
219 }
220
221 fn draw(
222 &self,
223 tree: &Tree,
224 renderer: &mut Renderer,
225 theme: &Theme,
226 style: &renderer::Style,
227 layout: Layout<'_>,
228 cursor: mouse::Cursor,
229 viewport: &Rectangle,
230 ) {
231 self.with_element(|element| {
232 element.as_widget().draw(
233 &tree.children[0],
234 renderer,
235 theme,
236 style,
237 layout,
238 cursor,
239 viewport,
240 );
241 });
242 }
243
244 fn overlay<'b>(
245 &'b mut self,
246 tree: &'b mut Tree,
247 layout: Layout<'b>,
248 renderer: &Renderer,
249 viewport: &Rectangle,
250 translation: Vector,
251 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
252 let overlay = InnerBuilder {
253 cell: self.element.borrow().as_ref().unwrap().clone(),
254 element: self
255 .element
256 .borrow()
257 .as_ref()
258 .unwrap()
259 .borrow_mut()
260 .take()
261 .unwrap(),
262 tree: &mut tree.children[0],
263 layout,
264 overlay_builder: |element, tree, layout| {
265 element
266 .as_widget_mut()
267 .overlay(tree, *layout, renderer, viewport, translation)
268 .map(|overlay| RefCell::new(overlay::Nested::new(overlay)))
269 },
270 }
271 .build();
272
273 #[allow(clippy::redundant_closure_for_method_calls)]
274 if overlay.with_overlay(|overlay| overlay.is_some()) {
275 Some(overlay::Element::new(Box::new(Overlay(Some(overlay)))))
276 } else {
277 let heads = overlay.into_heads();
278
279 *self.element.borrow().as_ref().unwrap().borrow_mut() = Some(heads.element);
283
284 None
285 }
286 }
287}
288
289#[self_referencing]
290struct Inner<'a, Message: 'a, Theme: 'a, Renderer: 'a> {
291 cell: Rc<RefCell<Option<Element<'static, Message, Theme, Renderer>>>>,
292 element: Element<'static, Message, Theme, Renderer>,
293 tree: &'a mut Tree,
294 layout: Layout<'a>,
295
296 #[borrows(mut element, mut tree, layout)]
297 #[not_covariant]
298 overlay: Option<RefCell<overlay::Nested<'this, Message, Theme, Renderer>>>,
299}
300
301struct Overlay<'a, Message, Theme, Renderer>(Option<Inner<'a, Message, Theme, Renderer>>);
302
303impl<Message, Theme, Renderer> Drop for Overlay<'_, Message, Theme, Renderer> {
304 fn drop(&mut self) {
305 let heads = self.0.take().unwrap().into_heads();
306 (*heads.cell.borrow_mut()) = Some(heads.element);
307 }
308}
309
310impl<Message, Theme, Renderer> Overlay<'_, Message, Theme, Renderer> {
311 fn with_overlay_maybe<T>(
312 &self,
313 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
314 ) -> Option<T> {
315 self.0
316 .as_ref()
317 .unwrap()
318 .with_overlay(|overlay| overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut())))
319 }
320
321 fn with_overlay_mut_maybe<T>(
322 &mut self,
323 f: impl FnOnce(&mut overlay::Nested<'_, Message, Theme, Renderer>) -> T,
324 ) -> Option<T> {
325 self.0
326 .as_mut()
327 .unwrap()
328 .with_overlay_mut(|overlay| overlay.as_mut().map(|nested| (f)(nested.get_mut())))
329 }
330}
331
332impl<Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
333 for Overlay<'_, Message, Theme, Renderer>
334where
335 Renderer: core::Renderer,
336{
337 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
338 self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
339 .unwrap_or_default()
340 }
341
342 fn draw(
343 &self,
344 renderer: &mut Renderer,
345 theme: &Theme,
346 style: &renderer::Style,
347 layout: Layout<'_>,
348 cursor: mouse::Cursor,
349 ) {
350 let _ = self.with_overlay_maybe(|overlay| {
351 overlay.draw(renderer, theme, style, layout, cursor);
352 });
353 }
354
355 fn mouse_interaction(
356 &self,
357 layout: Layout<'_>,
358 cursor: mouse::Cursor,
359 renderer: &Renderer,
360 ) -> mouse::Interaction {
361 self.with_overlay_maybe(|overlay| overlay.mouse_interaction(layout, cursor, renderer))
362 .unwrap_or_default()
363 }
364
365 fn update(
366 &mut self,
367 event: &Event,
368 layout: Layout<'_>,
369 cursor: mouse::Cursor,
370 renderer: &Renderer,
371 shell: &mut Shell<'_, Message>,
372 ) {
373 let _ = self.with_overlay_mut_maybe(|overlay| {
374 overlay.update(event, layout, cursor, renderer, shell);
375 });
376 }
377}
378
379impl<'a, Message, Theme, Renderer, Dependency, View>
380 From<Lazy<'a, Message, Theme, Renderer, Dependency, View>>
381 for Element<'a, Message, Theme, Renderer>
382where
383 View: Into<Element<'static, Message, Theme, Renderer>> + 'static,
384 Renderer: core::Renderer + 'static,
385 Message: 'static,
386 Theme: 'static,
387 Dependency: Hash + 'a,
388{
389 fn from(lazy: Lazy<'a, Message, Theme, Renderer, Dependency, View>) -> Self {
390 Self::new(lazy)
391 }
392}