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