1use super::*;
2
3#[derive(Clone, Debug)]
4pub struct CppStruct {
5 pub def: TypeDef,
6 pub name: &'static str,
7 pub nested: BTreeMap<&'static str, CppStruct>,
8}
9
10impl Ord for CppStruct {
11 fn cmp(&self, other: &Self) -> Ordering {
12 (self.name, self.def).cmp(&(other.name, other.def))
13 }
14}
15
16impl PartialOrd for CppStruct {
17 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
18 Some(self.cmp(other))
19 }
20}
21
22impl PartialEq for CppStruct {
23 fn eq(&self, other: &Self) -> bool {
24 self.def == other.def
25 }
26}
27
28impl Eq for CppStruct {}
29
30impl std::hash::Hash for CppStruct {
31 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
32 self.def.hash(state);
33 }
34}
35
36impl CppStruct {
37 pub fn type_name(&self) -> TypeName {
38 TypeName(self.def.namespace(), self.name)
39 }
40
41 pub fn write_name(&self, writer: &Writer) -> TokenStream {
42 self.type_name().write(writer, &[])
43 }
44
45 pub fn is_handle(&self) -> bool {
46 self.def.has_attribute("NativeTypedefAttribute")
47 }
48
49 pub fn write(&self, writer: &Writer) -> TokenStream {
50 if self.is_handle() {
51 return writer.write_cpp_handle(self.def);
52 }
53
54 if self.def.fields().next().is_none() {
55 if let Some(guid) = self.def.guid_attribute() {
56 return writer.write_cpp_const_guid(to_ident(self.name), &guid);
57 }
58 }
59
60 let mut dependencies = TypeMap::new();
61
62 if writer.config.package {
63 self.dependencies(&mut dependencies);
64 }
65
66 let cfg = writer.write_cfg(self.def, self.def.namespace(), &dependencies, false);
67 self.write_with_cfg(writer, &cfg)
68 }
69
70 fn write_with_cfg(&self, writer: &Writer, cfg: &TokenStream) -> TokenStream {
71 let name = to_ident(self.name);
72 let flags = self.def.flags();
73 let is_union = flags.contains(TypeAttributes::ExplicitLayout);
74 let has_explicit_layout = self.has_explicit_layout();
75 let has_packing = self.has_packing();
76
77 let fields: Vec<_> = self
78 .def
79 .fields()
80 .filter(|field| !field.flags().contains(FieldAttributes::Literal))
81 .map(|field| (field.name(), field.ty(Some(self))))
82 .collect();
83
84 let is_copyable = self.is_copyable();
85
86 let fields = {
87 let fields = fields.iter().map(|(name, ty)| {
88 let name = to_ident(name);
89
90 let ty = if !writer.config.sys && is_union && !ty.is_copyable() {
91 let ty = ty.write_default(writer);
92 quote! { core::mem::ManuallyDrop<#ty> }
93 } else if !writer.config.sys && ty.is_dropped() {
94 if let Type::ArrayFixed(ty, len) = ty {
95 let ty = ty.write_default(writer);
96 let len = Literal::usize_unsuffixed(*len);
97 quote! { [core::mem::ManuallyDrop<#ty>; #len] }
98 } else {
99 let ty = ty.write_default(writer);
100 quote! { core::mem::ManuallyDrop<#ty> }
101 }
102 } else {
103 ty.write_default(writer)
104 };
105
106 quote! { pub #name: #ty, }
107 });
108
109 let fields = quote! { #(#fields)* };
110
111 if fields.is_empty() {
112 quote! {
113 (pub u8);
114 }
115 } else {
116 quote! {
117 { #fields }
118 }
119 }
120 };
121
122 let mut derive = DeriveWriter::new(writer, self.type_name());
123 let mut manual_clone = None;
124
125 if writer.config.sys || is_copyable {
126 derive.extend(["Clone", "Copy"]);
127 } else if !matches!(
128 TypeName(self.def.namespace(), self.def.name()),
129 TypeName::VARIANT | TypeName::PROPVARIANT
130 ) {
131 if has_explicit_layout {
132 manual_clone = Some(quote! {
133 #cfg
134 impl Clone for #name {
135 fn clone(&self) -> Self {
136 unsafe { core::mem::transmute_copy(self) }
137 }
138 }
139 });
140 } else if !has_packing {
141 derive.extend(["Clone"]);
142 }
143 }
144
145 if !writer.config.sys && !has_explicit_layout && !has_packing {
146 derive.extend(["Debug", "PartialEq"]);
147 }
148
149 let default = if writer.config.sys {
150 quote! {}
151 } else {
152 quote! {
153 #cfg
154 impl Default for #name {
155 fn default() -> Self {
156 unsafe { core::mem::zeroed() }
157 }
158 }
159 }
160 };
161
162 let struct_or_union = if is_union {
163 quote! { union }
164 } else {
165 quote! { struct }
166 };
167
168 let repr = if let Some(layout) = self.def.class_layout() {
169 let packing = Literal::usize_unsuffixed(layout.packing_size());
170 quote! { #[repr(C, packed(#packing))] }
171 } else {
172 quote! { #[repr(C)] }
173 };
174
175 let constants = {
176 let constants = self.def.fields().filter_map(|f| {
177 if f.flags().contains(FieldAttributes::Literal) {
178 if let Some(constant) = f.constant() {
179 let name = to_ident(f.name());
180 let ty = constant.ty().write_name(writer);
181 let value = constant.value().write();
182
183 return Some(quote! {
184 pub const #name: #ty = #value;
185 });
186 }
187 }
188
189 None
190 });
191
192 let mut constants = quote! { #(#constants)* };
193
194 if !constants.is_empty() {
195 constants = quote! {
196 #cfg
197 impl #name {
198 #constants
199 }
200 };
201 }
202
203 constants
204 };
205
206 let mut tokens = quote! {
207 #repr
208 #cfg
209 #derive
210 pub #struct_or_union #name
211 #fields
212 #constants
213 #manual_clone
214 #default
215 };
216
217 for nested in self.nested.values() {
218 tokens.combine(nested.write_with_cfg(writer, cfg));
219 }
220
221 tokens
222 }
223
224 pub fn dependencies(&self, dependencies: &mut TypeMap) {
225 for field in self.def.fields() {
226 field.ty(Some(self)).dependencies(dependencies);
227 }
228
229 if let Some(attribute) = self.def.find_attribute("AlsoUsableForAttribute") {
230 if let Some((_, Value::Str(type_name))) = attribute.args().first() {
231 self.def
232 .reader()
233 .unwrap_full_name(self.def.namespace(), type_name)
234 .dependencies(dependencies);
235 }
236 }
237 }
238
239 pub fn is_copyable(&self) -> bool {
240 if matches!(
241 self.def.type_name(),
242 TypeName::VARIANT | TypeName::PROPVARIANT
243 ) {
244 return false;
245 }
246
247 self.def
248 .fields()
249 .all(|field| field.ty(Some(self)).is_copyable())
250 }
251
252 pub fn has_explicit_layout(&self) -> bool {
253 self.def.flags().contains(TypeAttributes::ExplicitLayout)
254 || self
255 .def
256 .fields()
257 .any(|field| field.ty(Some(self)).has_explicit_layout())
258 }
259
260 pub fn has_packing(&self) -> bool {
261 self.def.class_layout().is_some()
262 || self
263 .def
264 .fields()
265 .any(|field| field.ty(Some(self)).has_packing())
266 }
267
268 pub fn size(&self) -> usize {
269 if self.def.flags().contains(TypeAttributes::ExplicitLayout) {
270 self.def
271 .fields()
272 .map(|field| field.ty(Some(self)).size())
273 .max()
274 .unwrap_or(1)
275 } else {
276 let mut sum = 0;
277 for field in self.def.fields() {
278 let ty = field.ty(Some(self));
279 let size = ty.size();
280 let align = ty.align();
281 sum = (sum + (align - 1)) & !(align - 1);
282 sum += size;
283 }
284 sum
285 }
286 }
287
288 pub fn align(&self) -> usize {
289 self.def
290 .fields()
291 .map(|field| field.ty(Some(self)).align())
292 .max()
293 .unwrap_or(1)
294 }
295}
296