1use crate::core::layout::{self, Layout};
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget::tree::{self, Tree};
7use crate::core::widget::{self, Widget};
8use crate::core::{self, Event, Length, Rectangle, Shell, Size, Vector};
9
10use rustc_hash::FxHasher;
11use std::hash::{Hash, Hasher};
12
13pub struct Lazy<'a, W, Dependency> {
15 dependency: Dependency,
16 view: Box<dyn Fn(&Dependency) -> W + 'a>,
17 size: Size<Length>,
18}
19
20impl<'a, W, Dependency> Lazy<'a, W, Dependency>
21where
22 Dependency: Hash + 'a,
23{
24 pub fn new(dependency: Dependency, view: impl Fn(&Dependency) -> W + 'a) -> Self {
27 Self {
28 dependency,
29 view: Box::new(view),
30 size: Size::new(Length::Fit, Length::Fit),
31 }
32 }
33}
34
35struct Internal<W> {
36 element: W,
37 hash: u64,
38}
39
40impl<W, Dependency> widget::Meta for Lazy<'_, W, Dependency> {}
41
42impl<'a, W, Message, Theme, Renderer, Dependency> Widget<Message, Theme, Renderer>
43 for Lazy<'a, W, Dependency>
44where
45 W: Widget<Message, Theme, Renderer> + 'static,
46 Dependency: Hash + 'a,
47 Renderer: core::Renderer,
48{
49 fn tag(&self) -> tree::Tag {
50 struct Tag<T>(T);
51 tree::Tag::of::<Tag<W>>()
52 }
53
54 fn state(&self) -> tree::State {
55 tree::State::new(Internal {
56 element: (self.view)(&self.dependency),
57 hash: hash(&self.dependency),
58 })
59 }
60
61 fn diff(&mut self, tree: &mut Tree) {
62 let current = tree.state.downcast_mut::<Internal<W>>();
63
64 let new_hash = hash(&self.dependency);
65
66 if current.hash != new_hash {
67 current.hash = new_hash;
68 current.element = (self.view)(&self.dependency);
69 }
70
71 self.size = current.element.size();
74
75 tree::diff_children(
76 &mut tree.children,
77 std::slice::from_mut(&mut current.element),
78 );
79 }
80
81 fn size(&self) -> Size<Length> {
82 self.size
83 }
84
85 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
86 let cached = tree.state.downcast_mut::<Internal<W>>();
87
88 cached
89 .element
90 .layout(&mut tree.children[0], renderer, limits);
91
92 tree.size = tree.children[0].size;
93 }
94
95 fn operate(
96 &mut self,
97 tree: &mut Tree,
98 layout: Layout,
99 viewport: &Rectangle,
100 renderer: &Renderer,
101 operation: &mut dyn widget::Operation,
102 ) {
103 let cached = tree.state.downcast_mut::<Internal<W>>();
104
105 cached
106 .element
107 .operate(&mut tree.children[0], layout, viewport, renderer, operation);
108 }
109
110 fn update(
111 &mut self,
112 tree: &mut Tree,
113 event: &Event,
114 layout: Layout,
115 cursor: mouse::Cursor,
116 renderer: &Renderer,
117 shell: &mut Shell<'_, Message>,
118 viewport: &Rectangle,
119 ) {
120 let cached = tree.state.downcast_mut::<Internal<W>>();
121
122 cached.element.update(
123 &mut tree.children[0],
124 event,
125 layout,
126 cursor,
127 renderer,
128 shell,
129 viewport,
130 );
131 }
132
133 fn mouse_interaction(
134 &self,
135 tree: &Tree,
136 layout: Layout,
137 cursor: mouse::Cursor,
138 viewport: &Rectangle,
139 renderer: &Renderer,
140 ) -> mouse::Interaction {
141 let cached = tree.state.downcast_ref::<Internal<W>>();
142
143 cached
144 .element
145 .mouse_interaction(&tree.children[0], layout, cursor, viewport, renderer)
146 }
147
148 fn draw(
149 &self,
150 tree: &Tree,
151 renderer: &mut Renderer,
152 theme: &Theme,
153 style: &renderer::Style,
154 layout: Layout,
155 cursor: mouse::Cursor,
156 viewport: &Rectangle,
157 ) {
158 let current = tree.state.downcast_ref::<Internal<W>>();
159
160 current.element.draw(
161 &tree.children[0],
162 renderer,
163 theme,
164 style,
165 layout,
166 cursor,
167 viewport,
168 );
169 }
170
171 fn overlay<'b>(
172 &'b mut self,
173 tree: &'b mut Tree,
174 layout: Layout,
175 renderer: &Renderer,
176 viewport: &Rectangle,
177 translation: Vector,
178 window: Size,
179 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
180 let current = tree.state.downcast_mut::<Internal<W>>();
181
182 current.element.overlay(
183 &mut tree.children[0],
184 layout,
185 renderer,
186 viewport,
187 translation,
188 window,
189 )
190 }
191}
192
193fn hash(data: impl Hash) -> u64 {
194 let mut hasher = FxHasher::default();
195 data.hash(&mut hasher);
196 hasher.finish()
197}