1use crate::core as vk;
3use libloading::Library;
4use std::{ffi::CStr, sync::Arc};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum CreatedHandle {
9 Instance(vk::InstanceHandle),
10 Device(vk::DeviceHandle),
11}
12
13#[derive(Debug)]
17#[must_use = "a created native object still needs explicit recovery"]
18pub struct InitializationFailure {
19 pub(crate) handle: CreatedHandle,
20 pub(crate) missing_command: &'static str,
21 pub(crate) library: Option<Arc<Library>>,
22 pub(crate) instance: vk::InstanceHandle,
23 pub(crate) gipa: unsafe extern "system" fn(
24 vk::InstanceHandle,
25 *const std::ffi::c_char,
26 ) -> vk::PFN_vkVoidFunction,
27 pub(crate) gdpa: vk::PFN_vkGetDeviceProcAddr,
28}
29
30impl PartialEq for InitializationFailure {
31 fn eq(&self, other: &Self) -> bool {
32 self.handle == other.handle
34 && self.instance == other.instance
35 && self.missing_command == other.missing_command
36 }
37}
38
39impl std::fmt::Display for InitializationFailure {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 write!(
42 f,
43 "missing {}; {:?} requires recovery",
44 self.missing_command, self.handle
45 )
46 }
47}
48
49impl std::error::Error for InitializationFailure {}
50
51impl InitializationFailure {
52 fn exported(&self, name: &CStr) -> vk::PFN_vkVoidFunction {
53 unsafe {
56 self.library.as_ref().and_then(|library| {
57 library
58 .get::<unsafe extern "system" fn()>(name.to_bytes_with_nul())
59 .ok()
60 .map(|symbol| *symbol)
61 })
62 }
63 }
64
65 pub fn handle(&self) -> CreatedHandle {
67 self.handle
68 }
69
70 pub fn missing_command(&self) -> &'static str {
72 self.missing_command
73 }
74
75 pub unsafe fn destroy(self, allocator: Option<&vk::AllocationCallbacks>) -> Result<(), Self> {
83 let allocator = allocator.map_or(std::ptr::null(), |value| value);
84 let _retained = &self.library;
86 match self.handle {
87 CreatedHandle::Instance(handle) => {
88 let function = unsafe { (self.gipa)(handle, c"vkDestroyInstance".as_ptr()) }
90 .or_else(|| self.exported(c"vkDestroyInstance"));
91 let function = unsafe {
93 std::mem::transmute::<vk::PFN_vkVoidFunction, vk::PFN_vkDestroyInstance>(function)
94 };
95 let Some(function) = function else {
96 return Err(self);
97 };
98 unsafe { function(handle, allocator) };
100 }
101 CreatedHandle::Device(handle) => {
102 let function = unsafe {
104 self
105 .gdpa
106 .and_then(|load| load(handle, c"vkDestroyDevice".as_ptr()))
107 .or_else(|| (self.gipa)(self.instance, c"vkDestroyDevice".as_ptr()))
108 .or_else(|| self.exported(c"vkDestroyDevice"))
109 };
110 let function = unsafe {
112 std::mem::transmute::<vk::PFN_vkVoidFunction, vk::PFN_vkDestroyDevice>(function)
113 };
114 let Some(function) = function else {
115 return Err(self);
116 };
117 unsafe { function(handle, allocator) };
119 }
120 }
121 Ok(())
122 }
123}
124
125#[cfg(test)]
126#[path = "../../../test/rs/load/test_failure.rs"]
127mod tests;