diff options
Diffstat (limited to 'vendor/windows-bindgen/src/structs.rs')
-rw-r--r-- | vendor/windows-bindgen/src/structs.rs | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/vendor/windows-bindgen/src/structs.rs b/vendor/windows-bindgen/src/structs.rs new file mode 100644 index 000000000..89670bdb5 --- /dev/null +++ b/vendor/windows-bindgen/src/structs.rs @@ -0,0 +1,316 @@ +use super::*; + +pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { + if gen.reader.type_def_is_contract(def) { + return quote! {}; + } + + if gen.reader.type_def_is_handle(def) { + return handles::gen(gen, def); + } + + gen_struct_with_name(gen, def, gen.reader.type_def_name(def), &Cfg::default()) +} + +fn gen_struct_with_name(gen: &Gen, def: TypeDef, struct_name: &str, cfg: &Cfg) -> TokenStream { + let name = to_ident(struct_name); + + if gen.reader.type_def_fields(def).next().is_none() { + let mut tokens = quote! { + #[repr(C)] + pub struct #name(pub u8); + impl ::core::marker::Copy for #name {} + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + *self + } + } + }; + if !gen.sys { + tokens.combine("e! { + impl ::windows::core::TypeKind for #name { + type TypeKind = ::windows::core::CopyType; + } + }); + } + return tokens; + } + + let flags = gen.reader.type_def_flags(def); + let cfg = cfg.union(&gen.reader.type_def_cfg(def, &[])); + + let repr = if let Some(layout) = gen.reader.type_def_class_layout(def) { + let packing = Literal::usize_unsuffixed(gen.reader.class_layout_packing_size(layout)); + quote! { #[repr(C, packed(#packing))] } + } else { + quote! { #[repr(C)] } + }; + + let fields = gen.reader.type_def_fields(def).map(|f| { + let name = to_ident(gen.reader.field_name(f)); + let ty = gen.reader.field_type(f, Some(def)); + + if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { + quote! {} + } else if !gen.sys + && flags.contains(TypeAttributes::EXPLICIT_LAYOUT) + && !gen.reader.field_is_copyable(f, def) + { + // Rust can't tell that the type is copyable and won't accept windows::core::ManuallyDrop + let ty = gen.type_default_name(&ty); + quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } + } else if !gen.sys + && !flags.contains(TypeAttributes::WINRT) + && !gen.reader.field_is_blittable(f, def) + { + if let Type::Win32Array((ty, len)) = ty { + let ty = gen.type_default_name(&ty); + quote! { pub #name: [::std::mem::ManuallyDrop<#ty>; #len], } + } else { + let ty = gen.type_default_name(&ty); + quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } + } + } else { + let ty = gen.type_default_name(&ty); + quote! { pub #name: #ty, } + } + }); + + let struct_or_union = if flags.contains(TypeAttributes::EXPLICIT_LAYOUT) { + quote! { union } + } else { + quote! { struct } + }; + + let doc = gen.cfg_doc(&cfg); + let features = gen.cfg_features(&cfg); + + let mut tokens = quote! { + #repr + #doc + #features + pub #struct_or_union #name {#(#fields)*} + }; + + tokens.combine(&gen_struct_constants(gen, def, &name, &cfg)); + tokens.combine(&gen_copy_clone(gen, def, &name, &cfg)); + tokens.combine(&gen_debug(gen, def, &name, &cfg)); + tokens.combine(&gen_windows_traits(gen, def, &name, &cfg)); + tokens.combine(&gen_compare_traits(gen, def, &name, &cfg)); + + if !gen.sys { + tokens.combine("e! { + #features + impl ::core::default::Default for #name { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } + } + }); + } + + for (index, nested_type) in gen.reader.nested_types(def).enumerate() { + let nested_name = format!("{struct_name}_{index}"); + tokens.combine(&gen_struct_with_name(gen, nested_type, &nested_name, &cfg)); + } + + tokens +} + +fn gen_windows_traits(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + if gen.sys { + quote! {} + } else { + let features = gen.cfg_features(cfg); + let is_copy = gen.reader.type_def_is_blittable(def); + + let type_kind = if is_copy { + quote! { CopyType } + } else { + quote! { ValueType } + }; + + let mut tokens = quote! { + #features + impl ::windows::core::TypeKind for #name { + type TypeKind = ::windows::core::#type_kind; + } + }; + + if gen + .reader + .type_def_flags(def) + .contains(TypeAttributes::WINRT) + { + let signature = + Literal::byte_string(gen.reader.type_def_signature(def, &[]).as_bytes()); + + tokens.combine("e! { + #features + impl ::windows::core::RuntimeType for #name { + const SIGNATURE: ::windows::imp::ConstBuffer = ::windows::imp::ConstBuffer::from_slice(#signature); + } + }); + } + + tokens + } +} + +fn gen_compare_traits(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + let features = gen.cfg_features(cfg); + + if gen.sys + || gen.reader.type_def_has_explicit_layout(def) + || gen.reader.type_def_has_packing(def) + || gen.reader.type_def_has_callback(def) + { + quote! {} + } else { + let fields = gen.reader.type_def_fields(def).filter_map(|f| { + let name = to_ident(gen.reader.field_name(f)); + if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { + None + } else { + Some(quote! { self.#name == other.#name }) + } + }); + + quote! { + #features + impl ::core::cmp::PartialEq for #name { + fn eq(&self, other: &Self) -> bool { + #(#fields)&&* + } + } + #features + impl ::core::cmp::Eq for #name {} + } + } +} + +fn gen_debug(gen: &Gen, def: TypeDef, ident: &TokenStream, cfg: &Cfg) -> TokenStream { + if gen.sys + || gen.reader.type_def_has_explicit_layout(def) + || gen.reader.type_def_has_packing(def) + { + quote! {} + } else { + let name = ident.as_str(); + let features = gen.cfg_features(cfg); + + let fields = gen.reader.type_def_fields(def).filter_map(|f| { + if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { + None + } else { + let name = gen.reader.field_name(f); + let ident = to_ident(name); + let ty = gen.reader.field_type(f, Some(def)); + if gen.reader.type_has_callback(&ty) { + None + } else { + Some(quote! { .field(#name, &self.#ident) }) + } + } + }); + + quote! { + #features + impl ::core::fmt::Debug for #ident { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct(#name) #(#fields)* .finish() + } + } + } + } +} + +fn gen_copy_clone(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + let features = gen.cfg_features(cfg); + + if gen.sys || gen.reader.type_def_is_copyable(def) { + quote! { + #features + impl ::core::marker::Copy for #name {} + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + *self + } + } + } + } else if gen.reader.type_def_class_layout(def).is_some() { + // Don't support copy/clone of packed structs: https://github.com/rust-lang/rust/issues/82523 + quote! {} + } else if !gen + .reader + .type_def_flags(def) + .contains(TypeAttributes::WINRT) + { + quote! { + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + unsafe { ::core::mem::transmute_copy(self) } + } + } + } + } else { + let fields = gen.reader.type_def_fields(def).map(|f| { + let name = to_ident(gen.reader.field_name(f)); + if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { + quote! {} + } else if gen.reader.field_is_blittable(f, def) { + quote! { #name: self.#name } + } else { + quote! { #name: self.#name.clone() } + } + }); + + quote! { + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + Self { #(#fields),* } + } + } + } + } +} + +fn gen_struct_constants( + gen: &Gen, + def: TypeDef, + struct_name: &TokenStream, + cfg: &Cfg, +) -> TokenStream { + let features = gen.cfg_features(cfg); + + let constants = gen.reader.type_def_fields(def).filter_map(|f| { + if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { + if let Some(constant) = gen.reader.field_constant(f) { + let name = to_ident(gen.reader.field_name(f)); + let value = gen.typed_value(&gen.reader.constant_value(constant)); + + return Some(quote! { + pub const #name: #value; + }); + } + } + + None + }); + + let mut tokens = quote! { #(#constants)* }; + + if !tokens.is_empty() { + tokens = quote! { + #features + impl #struct_name { + #tokens + } + }; + } + + tokens +} |