1 | use super::*; |
2 | |
3 | impl Writer { |
4 | pub fn write_cpp_handle(&self, def: TypeDef) -> TokenStream { |
5 | let tn = def.type_name(); |
6 | let name = to_ident(def.name()); |
7 | let ty = def.underlying_type(); |
8 | let ty_name = ty.write_name(self); |
9 | |
10 | if self.config.sys { |
11 | quote! { |
12 | pub type #name = #ty_name; |
13 | } |
14 | } else { |
15 | let mut derive = quote! { Clone, Copy, Debug, PartialEq, Eq, }; |
16 | |
17 | let default = if ty.is_pointer() { |
18 | quote! { |
19 | impl Default for #name { |
20 | fn default() -> Self { |
21 | unsafe { core::mem::zeroed() } |
22 | } |
23 | } |
24 | } |
25 | } else { |
26 | derive.combine(quote! { Default, }); |
27 | quote! {} |
28 | }; |
29 | |
30 | let invalid = def.invalid_values(); |
31 | |
32 | let is_invalid = if ty.is_pointer() && (invalid.is_empty() || invalid == [0]) { |
33 | quote! { |
34 | impl #name { |
35 | pub fn is_invalid(&self) -> bool { |
36 | self.0.is_null() |
37 | } |
38 | } |
39 | } |
40 | } else if invalid.is_empty() { |
41 | quote! {} |
42 | } else { |
43 | let invalid = invalid.iter().map(|value| { |
44 | let literal = Literal::i64_unsuffixed(*value); |
45 | |
46 | if ty.is_pointer() || (*value < 0 && ty.is_unsigned()) { |
47 | quote! { self.0 == #literal as _ } |
48 | } else { |
49 | quote! { self.0 == #literal } |
50 | } |
51 | }); |
52 | quote! { |
53 | impl #name { |
54 | pub fn is_invalid(&self) -> bool { |
55 | #(#invalid)||* |
56 | } |
57 | } |
58 | } |
59 | }; |
60 | |
61 | let free = if let Some(function) = def.free_function() { |
62 | if is_invalid.is_empty() { |
63 | // TODO: https://github.com/microsoft/win32metadata/issues/1891 |
64 | quote! {} |
65 | } else { |
66 | let link = function.write_link(self, true); |
67 | let free = to_ident(function.method.name()); |
68 | let signature = function.method.signature(def.namespace(), &[]); |
69 | |
70 | // BCryptCloseAlgorithmProvider has an unused trailing parameter. |
71 | let tail = if signature.params.len() > 1 { |
72 | quote! { , 0 } |
73 | } else { |
74 | quote! {} |
75 | }; |
76 | |
77 | quote! { |
78 | impl windows_core::Free for #name { |
79 | #[inline] |
80 | unsafe fn free(&mut self) { |
81 | if !self.is_invalid() { |
82 | #link |
83 | unsafe { #free(self.0 #tail); } |
84 | } |
85 | } |
86 | } |
87 | } |
88 | } |
89 | } else { |
90 | quote! {} |
91 | }; |
92 | |
93 | let must_use = if matches!( |
94 | tn, |
95 | TypeName::BOOL | TypeName::NTSTATUS | TypeName::RPC_STATUS |
96 | ) { |
97 | quote! { #[must_use] } |
98 | } else { |
99 | quote! {} |
100 | }; |
101 | |
102 | let mut result = quote! { |
103 | #must_use |
104 | #[repr(transparent)] |
105 | #[derive(#derive)] |
106 | pub struct #name(pub #ty_name); |
107 | #is_invalid |
108 | #free |
109 | #default |
110 | }; |
111 | |
112 | if let Some(attribute) = def.find_attribute("AlsoUsableForAttribute" ) { |
113 | if let Some((_, Value::Str(type_name))) = attribute.args().first() { |
114 | let ty = def.reader().unwrap_full_name(def.namespace(), type_name); |
115 | |
116 | let ty = ty.write_name(self); |
117 | |
118 | result.combine(quote! { |
119 | impl windows_core::imp::CanInto<#ty> for #name {} |
120 | impl From<#name> for #ty { |
121 | fn from(value: #name) -> Self { |
122 | Self(value.0) |
123 | } |
124 | } |
125 | }); |
126 | } |
127 | } |
128 | |
129 | result |
130 | } |
131 | } |
132 | } |
133 | |