repose_render_wgpu/
callback.rs1use 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
132#[derive(Clone, Copy, Debug)]
133pub struct ScreenDescriptor {
134 pub size_in_pixels: [u32; 2],
135 pub pixels_per_point: f32,
136 pub target_format: wgpu::TextureFormat,
138 pub sample_count: u32,
140}
141
142pub trait WgpuCallback: Send + Sync + 'static {
144 fn prepare(
147 &self,
148 _device: &wgpu::Device,
149 _queue: &wgpu::Queue,
150 _encoder: &mut wgpu::CommandEncoder,
151 _screen_descriptor: &ScreenDescriptor,
152 _resources: &mut CallbackResources,
153 ) -> Vec<wgpu::CommandBuffer> {
154 Vec::new()
155 }
156
157 fn finish_prepare(
159 &self,
160 _device: &wgpu::Device,
161 _queue: &wgpu::Queue,
162 _encoder: &mut wgpu::CommandEncoder,
163 _screen_descriptor: &ScreenDescriptor,
164 _resources: &mut CallbackResources,
165 ) -> Vec<wgpu::CommandBuffer> {
166 Vec::new()
167 }
168
169 fn paint(
170 &self,
171 info: PaintCallbackInfo,
172 render_pass: &mut wgpu::RenderPass<'static>,
173 resources: &CallbackResources,
174 );
175}
176
177pub struct Callback(pub Box<dyn WgpuCallback>);
178
179impl Callback {
180 #[deprecated(note = "rect is ignored; use Callback::new(callback) - layout supplies rect")]
181 pub fn new_paint_callback(
182 _rect: Rect,
183 callback: impl WgpuCallback + 'static,
184 ) -> PaintCallbackPayload {
185 Arc::new(Self(Box::new(callback)))
186 }
187
188 #[allow(clippy::new_ret_no_self)]
191 pub fn new(callback: impl WgpuCallback + 'static) -> PaintCallbackPayload {
192 Arc::new(Self(Box::new(callback)))
193 }
194
195 pub fn embedded_view(
198 modifier: repose_core::Modifier,
199 callback: impl WgpuCallback + 'static,
200 ) -> repose_core::View {
201 let payload = Self::new(callback);
202 let mut m = modifier.paint_callback(payload);
203 let has_size = m.size.is_some()
204 || m.width.is_some()
205 || m.height.is_some()
206 || m.fill_max.is_some()
207 || m.fill_max_w.is_some()
208 || m.fill_max_h.is_some();
209 if !has_size {
210 m = m.size(repose_core::Dp(100.0), repose_core::Dp(100.0));
211 }
212 repose_core::View::new(0, repose_core::ViewKind::Box).modifier(m)
213 }
214}