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(target_arch = "wasm32"))]
42type AnyBox = Box<dyn std::any::Any + Send + Sync>;
43#[cfg(target_arch = "wasm32")]
44type AnyBox = Box<dyn std::any::Any>;
45
46#[cfg(not(target_arch = "wasm32"))]
47pub trait MaybeSendSync: Send + Sync + 'static {}
48#[cfg(not(target_arch = "wasm32"))]
49impl<T: Send + Sync + 'static> MaybeSendSync for T {}
50
51#[cfg(target_arch = "wasm32")]
52pub trait MaybeSendSync: 'static {}
53#[cfg(target_arch = "wasm32")]
54impl<T: 'static> MaybeSendSync for T {}
55
56#[derive(Default)]
57pub struct CallbackResources {
58 map: HashMap<TypeId, AnyBox>,
59}
60
61impl CallbackResources {
62 pub fn insert<T: MaybeSendSync>(&mut self, value: T) {
63 self.map.insert(TypeId::of::<T>(), Box::new(value));
64 }
65
66 pub fn get<T: MaybeSendSync>(&self) -> Option<&T> {
67 self.map
68 .get(&TypeId::of::<T>())
69 .and_then(|b| b.downcast_ref::<T>())
70 }
71
72 pub fn get_mut<T: MaybeSendSync>(&mut self) -> Option<&mut T> {
73 self.map
74 .get_mut(&TypeId::of::<T>())
75 .and_then(|b| b.downcast_mut::<T>())
76 }
77
78 pub fn get_or_insert_with<T: MaybeSendSync + Default>(&mut self) -> &mut T {
79 let id = TypeId::of::<T>();
80 if !self.map.contains_key(&id) {
81 self.map.insert(id, Box::new(T::default()));
82 }
83 self.map.get_mut(&id).unwrap().downcast_mut::<T>().unwrap()
84 }
85
86 pub fn remove<T: 'static>(&mut self) -> Option<T> {
87 self.map
88 .remove(&TypeId::of::<T>())
89 .and_then(|b| b.downcast::<T>().ok())
90 .map(|b| *b)
91 }
92
93 pub fn contains<T: 'static>(&self) -> bool {
94 self.map.contains_key(&TypeId::of::<T>())
95 }
96}
97
98#[derive(Clone, Copy, Debug)]
99pub struct ScreenDescriptor {
100 pub size_in_pixels: [u32; 2],
101 pub pixels_per_point: f32,
102 pub target_format: wgpu::TextureFormat,
104 pub sample_count: u32,
106}
107
108pub trait WgpuCallback: Send + Sync + 'static {
110 fn prepare(
113 &self,
114 _device: &wgpu::Device,
115 _queue: &wgpu::Queue,
116 _encoder: &mut wgpu::CommandEncoder,
117 _screen_descriptor: &ScreenDescriptor,
118 _resources: &mut CallbackResources,
119 ) -> Vec<wgpu::CommandBuffer> {
120 Vec::new()
121 }
122
123 fn finish_prepare(
125 &self,
126 _device: &wgpu::Device,
127 _queue: &wgpu::Queue,
128 _encoder: &mut wgpu::CommandEncoder,
129 _screen_descriptor: &ScreenDescriptor,
130 _resources: &mut CallbackResources,
131 ) -> Vec<wgpu::CommandBuffer> {
132 Vec::new()
133 }
134
135 fn paint(
136 &self,
137 info: PaintCallbackInfo,
138 render_pass: &mut wgpu::RenderPass<'static>,
139 resources: &CallbackResources,
140 );
141}
142
143pub struct Callback(pub Box<dyn WgpuCallback>);
144
145impl Callback {
146 #[deprecated(note = "rect is ignored; use Callback::new(callback) - layout supplies rect")]
147 pub fn new_paint_callback(
148 _rect: Rect,
149 callback: impl WgpuCallback + 'static,
150 ) -> PaintCallbackPayload {
151 Arc::new(Self(Box::new(callback)))
152 }
153
154 pub fn new(callback: impl WgpuCallback + 'static) -> PaintCallbackPayload {
156 Arc::new(Self(Box::new(callback)))
157 }
158
159 pub fn embedded_view(
162 modifier: repose_core::Modifier,
163 callback: impl WgpuCallback + 'static,
164 ) -> repose_core::View {
165 let payload = Self::new(callback);
166 let mut m = modifier.paint_callback(payload);
167 let has_size = m.size.is_some()
168 || m.width.is_some()
169 || m.height.is_some()
170 || m.fill_max.is_some()
171 || m.fill_max_w.is_some()
172 || m.fill_max_h.is_some();
173 if !has_size {
174 m = m.size(100.0, 100.0);
175 }
176 repose_core::View::new(0, repose_core::ViewKind::Box).modifier(m)
177 }
178}