1 // Copyright (c) 2022 The Vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 use super::{write_file, VkRegistryData};
11 use heck::ToUpperCamelCase;
12 use proc_macro2::{Ident, TokenStream};
13 use quote::{format_ident, quote};
14 
write(vk_data: &VkRegistryData)15 pub fn write(vk_data: &VkRegistryData) {
16     write_file(
17         "errors.rs",
18         format!(
19             "vk.xml header version {}.{}.{}",
20             vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
21         ),
22         errors_output(&errors_members(&vk_data.errors)),
23     );
24 }
25 
26 #[derive(Clone, Debug)]
27 struct ErrorsMember {
28     name: Ident,
29     ffi_name: Ident,
30 }
31 
errors_output(members: &[ErrorsMember]) -> TokenStream32 fn errors_output(members: &[ErrorsMember]) -> TokenStream {
33     let enum_items = members.iter().map(|ErrorsMember { name, .. }| {
34         quote! { #name, }
35     });
36     let try_from_items = members.iter().map(|ErrorsMember { name, ffi_name }| {
37         quote! { ash::vk::Result::#ffi_name => Self::#name, }
38     });
39 
40     quote! {
41         /// An enumeration of runtime errors that can be returned by Vulkan.
42         #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
43         #[repr(i32)]
44         #[non_exhaustive]
45         pub enum VulkanError {
46             #(#enum_items)*
47             Unnamed(ash::vk::Result),
48         }
49 
50         impl From<ash::vk::Result> for VulkanError {
51             fn from(val: ash::vk::Result) -> VulkanError {
52                 match val {
53                     #(#try_from_items)*
54                     x => Self::Unnamed(x),
55                 }
56             }
57         }
58     }
59 }
60 
errors_members(errors: &[&str]) -> Vec<ErrorsMember>61 fn errors_members(errors: &[&str]) -> Vec<ErrorsMember> {
62     errors
63         .iter()
64         .map(|error| {
65             let ffi_name = error.strip_prefix("VK_").unwrap();
66 
67             let mut parts = ffi_name.split('_').collect::<Vec<_>>();
68 
69             assert!(parts[0] == "ERROR");
70             parts.remove(0);
71 
72             if ["EXT", "KHR", "NV"].contains(parts.last().unwrap()) {
73                 parts.pop();
74             }
75 
76             let name = parts.join("_").to_upper_camel_case();
77 
78             ErrorsMember {
79                 name: format_ident!("{}", name),
80                 ffi_name: format_ident!("{}", ffi_name),
81             }
82         })
83         .collect()
84 }
85