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::{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{
48 fn tag(&self) -> tree::Tag {
49 struct Tag<T>(T);
50 tree::Tag::of::<Tag<W>>()
51 }
52
53 fn state(&self) -> tree::State {
54 tree::State::new(Internal {
55 element: (self.view)(&self.dependency),
56 hash: hash(&self.dependency),
57 })
58 }
59
60 fn diff(&mut self, tree: &mut Tree) {
61 let current = tree.state.downcast_mut::<Internal<W>>();
62
63 let new_hash = hash(&self.dependency);
64
65 if current.hash != new_hash {
66 current.hash = new_hash;
67 current.element = (self.view)(&self.dependency);
68 }
69
70 self.size = current.element.size();
73
74 tree::diff_children(
75 &mut tree.children,
76 std::slice::from_mut(&mut current.element),
77 );
78 }
79
80 fn size(&self) -> Size<Length> {
81 self.size
82 }
83
84 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
85 let cached = tree.state.downcast_mut::<Internal<W>>();
86
87 cached
88 .element
89 .layout(&mut tree.children[0], renderer, limits);
90
91 tree.size = tree.children[0].size;
92 }
93
94 fn operate(
95 &mut self,
96 tree: &mut Tree,
97 layout: Layout,
98 viewport: &Rectangle,
99 renderer: &Renderer,
100 operation: &mut dyn widget::Operation,
101 ) {
102 let cached = tree.state.downcast_mut::<Internal<W>>();
103
104 cached
105 .element
106 .operate(&mut tree.children[0], layout, viewport, renderer, operation);
107 }
108
109 fn update(
110 &mut self,
111 tree: &mut Tree,
112 event: &Event,
113 layout: Layout,
114 cursor: mouse::Cursor,
115 renderer: &Renderer,
116 shell: &mut Shell<'_, Message>,
117 viewport: &Rectangle,
118 ) {
119 let cached = tree.state.downcast_mut::<Internal<W>>();
120
121 cached.element.update(
122 &mut tree.children[0],
123 event,
124 layout,
125 cursor,
126 renderer,
127 shell,
128 viewport,
129 );
130 }
131
132 fn mouse_interaction(
133 &self,
134 tree: &Tree,
135 layout: Layout,
136 cursor: mouse::Cursor,
137 viewport: &Rectangle,
138 renderer: &Renderer,
139 ) -> mouse::Interaction {
140 let cached = tree.state.downcast_ref::<Internal<W>>();
141
142 cached
143 .element
144 .mouse_interaction(&tree.children[0], layout, cursor, viewport, renderer)
145 }
146
147 fn draw(
148 &self,
149 tree: &Tree,
150 renderer: &mut Renderer,
151 theme: &Theme,
152 style: &renderer::Style,
153 layout: Layout,
154 cursor: mouse::Cursor,
155 viewport: &Rectangle,
156 ) {
157 let current = tree.state.downcast_ref::<Internal<W>>();
158
159 current.element.draw(
160 &tree.children[0],
161 renderer,
162 theme,
163 style,
164 layout,
165 cursor,
166 viewport,
167 );
168 }
169
170 fn overlay<'b>(
171 &'b mut self,
172 tree: &'b mut Tree,
173 layout: Layout,
174 renderer: &Renderer,
175 viewport: &Rectangle,
176 translation: Vector,
177 window: Size,
178 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
179 let current = tree.state.downcast_mut::<Internal<W>>();
180
181 current.element.overlay(
182 &mut tree.children[0],
183 layout,
184 renderer,
185 viewport,
186 translation,
187 window,
188 )
189 }
190}
191
192fn hash(data: impl Hash) -> u64 {
193 let mut hasher = FxHasher::default();
194 data.hash(&mut hasher);
195 hasher.finish()
196}