1use std::any::TypeId;
35use std::collections::HashMap;
36use std::sync::Arc;
37
38use repose_core::{PaintCallbackInfo, PaintCallbackPayload, Rect};
39
40#[cfg(not(all(
42 target_arch = "wasm32",
43 any(
44 not(feature = "fragile-send-sync-non-atomic-wasm"),
45 target_feature = "atomics"
46 )
47)))]
48type AnyBox = Box<dyn std::any::Any + Send + Sync>;
49#[cfg(all(
50 target_arch = "wasm32",
51 any(
52 not(feature = "fragile-send-sync-non-atomic-wasm"),
53 target_feature = "atomics"
54 )
55))]
56type AnyBox = Box<dyn std::any::Any>;
57
58#[cfg(not(all(
59 target_arch = "wasm32",
60 any(
61 not(feature = "fragile-send-sync-non-atomic-wasm"),
62 target_feature = "atomics"
63 )
64)))]
65pub trait MaybeSendSync: Send + Sync + 'static {}
66#[cfg(not(all(
67 target_arch = "wasm32",
68 any(
69 not(feature = "fragile-send-sync-non-atomic-wasm"),
70 target_feature = "atomics"
71 )
72)))]
73impl<T: Send + Sync + 'static> MaybeSendSync for T {}
74
75#[cfg(all(
76 target_arch = "wasm32",
77 any(
78 not(feature = "fragile-send-sync-non-atomic-wasm"),
79 target_feature = "atomics"
80 )
81))]
82pub trait MaybeSendSync: 'static {}
83#[cfg(all(
84 target_arch = "wasm32",
85 any(
86 not(feature = "fragile-send-sync-non-atomic-wasm"),
87 target_feature = "atomics"
88 )
89))]
90impl<T: 'static> MaybeSendSync for T {}
91
92#[derive(Default)]
93pub struct CallbackResources {
94 map: HashMap<TypeId, AnyBox>,
95}
96
97impl CallbackResources {
98 pub fn insert<T: MaybeSendSync>(&mut self, value: T) {
99 self.map.insert(TypeId::of::<T>(), Box::new(value));
100 }
101
102 pub fn get<T: MaybeSendSync>(&self) -> Option<&T> {
103 self.map
104 .get(&TypeId::of::<T>())
105 .and_then(|b| b.downcast_ref::<T>())
106 }
107
108 pub fn get_mut<T: MaybeSendSync>(&mut self) -> Option<&mut T> {
109 self.map
110 .get_mut(&TypeId::of::<T>())
111 .and_then(|b| b.downcast_mut::<T>())
112 }
113
114 pub fn get_or_insert_with<T: MaybeSendSync + Default>(&mut self) -> &mut T {
115 let id = TypeId::of::<T>();
116 self.map.entry(id).or_insert_with(|| Box::new(T::default()));
117 self.map.get_mut(&id).unwrap().downcast_mut::<T>().unwrap()
118 }
119
120 pub fn remove<T: 'static>(&mut self) -> Option<T> {
121 self.map
122 .remove(&TypeId::of::<T>())
123 .and_then(|b| b.downcast::<T>().ok())
124 .map(|b| *b)
125 }
126
127 pub fn contains<T: 'static>(&self) -> bool {
128 self.map.contains_key(&TypeId::of::<T>())
129 }
130
131 pub fn len(&self) -> usize {
132 self.map.len()
133 }
134
135 pub fn is_empty(&self) -> bool {
136 self.map.is_empty()
137 }
138
139 pub fn clear(&mut self) {
140 self.map.clear();
141 }
142}
143
144#[derive(Clone, Copy, Debug)]
145pub struct ScreenDescriptor {
146 pub size_in_pixels: [u32; 2],
147 pub pixels_per_point: f32,
148 pub target_format: wgpu::TextureFormat,
150 pub sample_count: u32,
152}
153
154pub struct CallbackRenderPass<'pass, 'encoder> {
155 pass: &'pass mut wgpu::RenderPass<'encoder>,
156 target_format: wgpu::TextureFormat,
157 sample_count: u32,
158}
159
160impl<'pass, 'encoder> CallbackRenderPass<'pass, 'encoder> {
161 pub(crate) fn new(
162 pass: &'pass mut wgpu::RenderPass<'encoder>,
163 target_format: wgpu::TextureFormat,
164 sample_count: u32,
165 ) -> Self {
166 Self {
167 pass,
168 target_format,
169 sample_count,
170 }
171 }
172
173 pub fn target_format(&self) -> wgpu::TextureFormat {
174 self.target_format
175 }
176
177 pub fn sample_count(&self) -> u32 {
178 self.sample_count
179 }
180
181 pub fn set_pipeline(&mut self, pipeline: &wgpu::RenderPipeline) {
182 self.pass.set_pipeline(pipeline);
183 }
184
185 pub fn set_bind_group(&mut self, index: u32, bind_group: &wgpu::BindGroup, offsets: &[u32]) {
186 self.pass.set_bind_group(index, bind_group, offsets);
187 }
188
189 pub fn set_vertex_buffer(&mut self, slot: u32, buffer: wgpu::BufferSlice<'_>) {
190 self.pass.set_vertex_buffer(slot, buffer);
191 }
192
193 pub fn set_index_buffer(&mut self, buffer: wgpu::BufferSlice<'_>, format: wgpu::IndexFormat) {
194 self.pass.set_index_buffer(buffer, format);
195 }
196
197 pub fn set_viewport(
198 &mut self,
199 x: f32,
200 y: f32,
201 width: f32,
202 height: f32,
203 min_depth: f32,
204 max_depth: f32,
205 ) {
206 self.pass
207 .set_viewport(x, y, width, height, min_depth, max_depth);
208 }
209
210 pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
211 self.pass.set_scissor_rect(x, y, width, height);
212 }
213
214 pub fn set_stencil_reference(&mut self, reference: u32) {
215 self.pass.set_stencil_reference(reference);
216 }
217
218 pub fn draw(&mut self, vertices: std::ops::Range<u32>, instances: std::ops::Range<u32>) {
219 self.pass.draw(vertices, instances);
220 }
221
222 pub fn draw_indexed(
223 &mut self,
224 indices: std::ops::Range<u32>,
225 base_vertex: i32,
226 instances: std::ops::Range<u32>,
227 ) {
228 self.pass.draw_indexed(indices, base_vertex, instances);
229 }
230}
231
232pub trait WgpuCallback: Send + Sync + 'static {
234 fn resource_key(&self) -> Option<&str> {
235 None
236 }
237
238 fn resource_type_id(&self) -> TypeId {
239 TypeId::of::<Self>()
240 }
241
242 fn prepare(
245 &self,
246 _device: &wgpu::Device,
247 _queue: &wgpu::Queue,
248 _encoder: &mut wgpu::CommandEncoder,
249 _screen_descriptor: &ScreenDescriptor,
250 _resources: &mut CallbackResources,
251 ) -> Vec<wgpu::CommandBuffer> {
252 Vec::new()
253 }
254
255 fn finish_prepare(
257 &self,
258 _device: &wgpu::Device,
259 _queue: &wgpu::Queue,
260 _encoder: &mut wgpu::CommandEncoder,
261 _screen_descriptor: &ScreenDescriptor,
262 _resources: &mut CallbackResources,
263 ) -> Vec<wgpu::CommandBuffer> {
264 Vec::new()
265 }
266
267 fn paint(
268 &self,
269 info: PaintCallbackInfo,
270 render_pass: &mut CallbackRenderPass<'_, '_>,
271 resources: &CallbackResources,
272 );
273}
274
275pub struct Callback(pub Box<dyn WgpuCallback>);
276
277impl Callback {
278 #[deprecated(note = "rect is ignored; use Callback::new(callback) - layout supplies rect")]
279 pub fn new_paint_callback(
280 _rect: Rect,
281 callback: impl WgpuCallback + 'static,
282 ) -> PaintCallbackPayload {
283 Arc::new(Self(Box::new(callback)))
284 }
285
286 #[allow(clippy::new_ret_no_self)]
289 pub fn new(callback: impl WgpuCallback + 'static) -> PaintCallbackPayload {
290 Arc::new(Self(Box::new(callback)))
291 }
292
293 pub fn embedded_view(
296 modifier: repose_core::Modifier,
297 callback: impl WgpuCallback + 'static,
298 ) -> repose_core::View {
299 let payload = Self::new(callback);
300 let mut m = modifier.paint_callback(payload);
301 let has_size = m.size.is_some()
302 || m.width.is_some()
303 || m.height.is_some()
304 || m.fill_max.is_some()
305 || m.fill_max_w.is_some()
306 || m.fill_max_h.is_some();
307 if !has_size {
308 m = m.size(repose_core::Dp(100.0), repose_core::Dp(100.0));
309 }
310 repose_core::View::new(0, repose_core::ViewKind::Box).modifier(m)
311 }
312}