1use crate::{
31 DeviceInfo, Global, GlobalHooksInfo, InstanceInfo, Layer, LayerManifest, LayerVulkanCommand,
32};
33use ash::vk;
34use mockall::mock;
35use once_cell::sync::Lazy;
36use std::{
37 any::Any,
38 borrow::Borrow,
39 collections::HashMap,
40 marker::PhantomData,
41 ops::Deref,
42 sync::{Arc, Mutex, MutexGuard, Weak},
43};
44
45pub use crate::bindings::vk_layer::{
46 VkLayerDeviceCreateInfo, VkLayerDeviceLink, VkLayerFunction, VkLayerInstanceCreateInfo,
47};
48
49mod device_hooks_mock;
50mod global_hooks_mock;
51mod instance_hooks_mock;
52
53use device_hooks_mock::MockDeviceHooks;
54use global_hooks_mock::MockGlobalHooks;
55use instance_hooks_mock::MockInstanceHooks;
56
57type Deleter<T> = Box<dyn FnOnce(&mut T) + Send + Sync>;
58
59pub struct Del<T> {
63 data: T,
64 deleter: Option<Deleter<T>>,
65}
66
67impl<T> Del<T> {
68 pub fn new(data: T, deleter: impl FnOnce(&mut T) + Send + Sync + 'static) -> Self {
70 Del {
71 data,
72 deleter: Some(Box::new(deleter)),
73 }
74 }
75}
76
77impl<T> Deref for Del<T> {
78 type Target = T;
79
80 fn deref(&self) -> &Self::Target {
81 &self.data
82 }
83}
84
85impl<T> Drop for Del<T> {
86 fn drop(&mut self) {
87 (self.deleter.take().unwrap())(&mut self.data);
88 }
89}
90
91impl<T> AsRef<T> for Del<T> {
92 fn as_ref(&self) -> &T {
93 self.deref()
94 }
95}
96
97pub struct ArcDel<T>(pub Arc<Del<T>>);
99
100impl<T> ArcDel<T> {
101 pub fn new(data: T, deleter: impl FnOnce(&mut T) + Send + Sync + 'static) -> Self {
103 ArcDel(Arc::new(Del::new(data, deleter)))
104 }
105}
106
107impl<T> Borrow<T> for ArcDel<T> {
108 fn borrow(&self) -> &T {
109 &self.0.data
110 }
111}
112
113impl<T: Default> Default for ArcDel<T> {
114 fn default() -> Self {
115 Self(Arc::new(Del::new(Default::default(), |_| {})))
116 }
117}
118
119impl<T> From<Del<T>> for ArcDel<T> {
120 fn from(value: Del<T>) -> Self {
121 Self(Arc::new(value))
122 }
123}
124
125impl<T> Deref for ArcDel<T> {
126 type Target = T;
127 fn deref(&self) -> &Self::Target {
128 self.0.as_ref()
129 }
130}
131
132impl<T> AsRef<T> for ArcDel<T> {
133 fn as_ref(&self) -> &T {
134 self.0.as_ref()
135 }
136}
137
138impl<T> Clone for ArcDel<T> {
139 fn clone(&self) -> Self {
140 Self(self.0.clone())
141 }
142}
143
144mock! {
145 pub Drop {}
146 impl Drop for Drop {
147 fn drop(&mut self);
148 }
149}
150
151pub trait TestLayerMock: 'static {
153 type TestLayerType: Layer;
156
157 fn instance() -> &'static Global<Self::TestLayerType>;
159
160 fn mock() -> &'static Self;
167
168 fn manifest(&self) -> LayerManifest;
170
171 fn hooked_global_commands(&self) -> &[LayerVulkanCommand];
173
174 fn hooked_instance_commands(&self) -> &[LayerVulkanCommand];
176
177 fn hooked_device_commands(&self) -> &[LayerVulkanCommand];
179}
180
181#[derive(Default)]
186pub struct MockGlobalHooksInfo<T: TestLayerMock> {
187 pub mock_hooks: Mutex<MockGlobalHooks>,
189 _marker: PhantomData<fn(T)>,
190}
191
192impl<T: TestLayerMock> GlobalHooksInfo for MockGlobalHooksInfo<T> {
193 type HooksType = MockGlobalHooks;
194 type HooksRefType<'a> = MutexGuard<'a, MockGlobalHooks>;
195 fn hooked_commands() -> &'static [LayerVulkanCommand] {
196 T::mock().hooked_global_commands()
197 }
198
199 fn hooks(&self) -> Self::HooksRefType<'_> {
200 self.mock_hooks.lock().unwrap()
201 }
202}
203
204#[derive(Default)]
209pub struct MockInstanceInfo<T: TestLayerMock> {
210 pub mock_hooks: Mutex<MockInstanceHooks>,
212 mock_drop: Mutex<Option<MockDrop>>,
213 _marker: PhantomData<fn(T)>,
214}
215
216impl<T: TestLayerMock> MockInstanceInfo<T> {
217 pub fn with_mock_drop(&self, f: impl FnOnce(&mut MockDrop)) {
222 let mut mock_drop = self.mock_drop.lock().unwrap();
223 let mock_drop = mock_drop.get_or_insert_with(Default::default);
224 f(mock_drop);
225 }
226}
227
228impl<T: TestLayerMock> InstanceInfo for MockInstanceInfo<T> {
229 type HooksType = MockInstanceHooks;
230 type HooksRefType<'a> = MutexGuard<'a, MockInstanceHooks>;
231 fn hooked_commands() -> &'static [LayerVulkanCommand] {
232 T::mock().hooked_instance_commands()
233 }
234
235 fn hooks(&self) -> Self::HooksRefType<'_> {
236 self.mock_hooks.lock().unwrap()
237 }
238}
239
240#[derive(Default)]
245pub struct MockDeviceInfo<T: TestLayerMock> {
246 pub mock_hooks: Mutex<MockDeviceHooks>,
248 mock_drop: Mutex<Option<MockDrop>>,
249 _marker: PhantomData<fn(T)>,
250}
251
252impl<T: TestLayerMock> MockDeviceInfo<T> {
253 pub fn with_mock_drop(&self, f: impl FnOnce(&mut MockDrop)) {
258 let mut mock_drop = self.mock_drop.lock().unwrap();
259 let mock_drop = mock_drop.get_or_insert_with(Default::default);
260 f(mock_drop);
261 }
262}
263
264impl<T: TestLayerMock> DeviceInfo for MockDeviceInfo<T> {
265 type HooksType = MockDeviceHooks;
266 type HooksRefType<'a> = MutexGuard<'a, MockDeviceHooks>;
267
268 fn hooked_commands() -> &'static [LayerVulkanCommand] {
269 T::mock().hooked_device_commands()
270 }
271
272 fn hooks(&self) -> Self::HooksRefType<'_> {
273 self.mock_hooks.lock().unwrap()
274 }
275}
276
277pub struct Tag<const I: usize>;
280
281pub trait TestLayerTag: Sync + Send + 'static {}
283
284impl<const I: usize> TestLayerTag for Tag<I> {}
285
286pub struct TestLayer<T: TestLayerTag = Tag<0>> {
291 global_hooks_info: MockGlobalHooksInfo<MockTestLayer<T>>,
292 instances: Mutex<HashMap<vk::Instance, Weak<Del<<Self as Layer>::InstanceInfo>>>>,
293 devices: Mutex<HashMap<vk::Device, Weak<Del<<Self as Layer>::DeviceInfo>>>>,
294 _marker: PhantomData<fn(T)>,
295}
296
297impl<T: TestLayerTag> TestLayer<T> {
298 pub fn get_instance_info(
300 &self,
301 instance: vk::Instance,
302 ) -> Option<Arc<impl Deref<Target = <Self as Layer>::InstanceInfo>>> {
303 self.instances
304 .lock()
305 .unwrap()
306 .get(&instance)
307 .and_then(Weak::upgrade)
308 }
309
310 pub fn get_device_info(
312 &self,
313 device: vk::Device,
314 ) -> Option<Arc<impl Deref<Target = <Self as Layer>::DeviceInfo>>> {
315 self.devices
316 .lock()
317 .unwrap()
318 .get(&device)
319 .and_then(Weak::upgrade)
320 }
321}
322
323impl<T: TestLayerTag> Default for TestLayer<T> {
324 fn default() -> Self {
325 Self {
326 global_hooks_info: Default::default(),
327 instances: Default::default(),
328 devices: Default::default(),
329 _marker: Default::default(),
330 }
331 }
332}
333
334impl<T: TestLayerTag> Layer for TestLayer<T> {
335 type GlobalHooksInfo = MockGlobalHooksInfo<MockTestLayer<T>>;
336 type InstanceInfo = MockInstanceInfo<MockTestLayer<T>>;
337 type DeviceInfo = MockDeviceInfo<MockTestLayer<T>>;
338 type InstanceInfoContainer = ArcDel<Self::InstanceInfo>;
339 type DeviceInfoContainer = ArcDel<Self::DeviceInfo>;
340
341 fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
342 MockTestLayer::<T>::instance()
343 }
344
345 fn manifest() -> LayerManifest {
346 MockTestLayer::<T>::mock().manifest()
347 }
348
349 fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
350 &self.global_hooks_info
351 }
352
353 fn create_device_info(
354 &self,
355 _physical_device: vk::PhysicalDevice,
356 _create_info: &vk::DeviceCreateInfo,
357 _allocator: Option<&vk::AllocationCallbacks>,
358 device: Arc<ash::Device>,
359 _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
360 ) -> ArcDel<Self::DeviceInfo> {
361 let device_handle = device.handle();
362 let device_info = ArcDel::new(Default::default(), move |_| {
363 let layer = &Self::global_instance().layer_info;
364 layer.devices.lock().unwrap().remove(&device_handle);
365 });
366 self.devices
367 .lock()
368 .unwrap()
369 .insert(device.handle(), Arc::downgrade(&device_info.0));
370 device_info
371 }
372
373 fn create_instance_info(
374 &self,
375 _create_info: &vk::InstanceCreateInfo,
376 _allocator: Option<&vk::AllocationCallbacks>,
377 instance: Arc<ash::Instance>,
378 _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
379 ) -> ArcDel<Self::InstanceInfo> {
380 let instance_handle = instance.handle();
381 let instance_info = ArcDel::new(Default::default(), move |_| {
382 let layer = &Self::global_instance().layer_info;
383 layer.instances.lock().unwrap().remove(&instance_handle);
384 });
385 self.instances
386 .lock()
387 .unwrap()
388 .insert(instance.handle(), Arc::downgrade(&instance_info.0));
389 instance_info
390 }
391}
392
393mock! {
394 pub TestLayer<T: TestLayerTag = Tag<0>> {}
395
396 impl<T: TestLayerTag> TestLayerMock for TestLayer<T> {
397 type TestLayerType = TestLayer<T>;
398
399 fn instance() -> &'static Global<TestLayer<T>>;
400 fn mock() -> &'static Self;
401
402 fn manifest(&self) -> LayerManifest;
403 fn hooked_global_commands(&self) -> &[LayerVulkanCommand];
404 fn hooked_instance_commands(&self) -> &[LayerVulkanCommand];
405 fn hooked_device_commands(&self) -> &[LayerVulkanCommand];
406 }
407}
408
409impl<T: TestLayerTag> MockTestLayer<T> {
410 pub fn set_default_expectations(&mut self) {
413 self.expect_manifest()
414 .return_const(LayerManifest::test_default());
415 self.expect_hooked_global_commands().return_const(vec![]);
416 self.expect_hooked_instance_commands().return_const(vec![]);
417 self.expect_hooked_device_commands().return_const(vec![]);
418 }
419}
420
421pub struct TestGlobal<T: TestLayerTag = Tag<0>> {
425 layer_mock: Lazy<MockTestLayer<T>>,
426 layer_global: Lazy<Global<TestLayer<T>>>,
427}
428
429pub struct TestGlobalBuilder<T: TestLayerTag = Tag<0>> {
431 layer_mock_builder: fn() -> MockTestLayer<T>,
432 layer_global_builder: fn() -> Global<TestLayer<T>>,
433}
434
435impl<T: TestLayerTag> TestGlobalBuilder<T> {
436 pub const fn set_layer_mock_builder(
445 self,
446 layer_mock_builder: fn() -> MockTestLayer<T>,
447 ) -> Self {
448 Self {
449 layer_mock_builder,
450 ..self
451 }
452 }
453
454 pub const fn set_layer_global_builder(
460 self,
461 layer_global_builder: fn() -> Global<TestLayer<T>>,
462 ) -> Self {
463 Self {
464 layer_global_builder,
465 ..self
466 }
467 }
468
469 pub const fn build(&self) -> TestGlobal<T> {
473 TestGlobal {
474 layer_mock: Lazy::new(self.layer_mock_builder),
475 layer_global: Lazy::new(self.layer_global_builder),
476 }
477 }
478}
479
480impl<T: TestLayerTag> TestGlobal<T> {
481 pub const fn builder() -> TestGlobalBuilder<T> {
483 TestGlobalBuilder {
484 layer_mock_builder: || {
485 let mut mock = MockTestLayer::<T>::default();
486 mock.set_default_expectations();
487 mock
488 },
489 layer_global_builder: Default::default,
490 }
491 }
492
493 pub fn create_context(&'static self) -> Box<dyn Any> {
495 let layer_mock_ctx = MockTestLayer::mock_context();
496 layer_mock_ctx.expect().return_const(&*self.layer_mock);
497 let layer_global_ctx = MockTestLayer::instance_context();
498 layer_global_ctx.expect().return_const(&*self.layer_global);
499 Box::new((layer_mock_ctx, layer_global_ctx))
500 }
501}
502
503pub trait LayerManifestExt {
505 fn test_default() -> Self;
507}
508
509impl LayerManifestExt for LayerManifest {
510 fn test_default() -> Self {
511 Self {
512 name: "VK_LAYER_GOOGLE_test",
513 spec_version: vk::API_VERSION_1_1,
514 ..Default::default()
515 }
516 }
517}