Skip to content

Commit

Permalink
Derive standard traits for structs (microsoft#3041)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored and mati865 committed Jun 15, 2024
1 parent a55ea59 commit e6d2e56
Show file tree
Hide file tree
Showing 523 changed files with 32,021 additions and 358,357 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
check:
strategy:
matrix:
rust: [1.62.0, stable, nightly]
rust: [1.70.0, stable, nightly]
runs-on:
- windows-2019
- ubuntu-latest
Expand Down
13 changes: 13 additions & 0 deletions crates/libs/bindgen/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,19 @@ pub fn type_def_has_callback(row: TypeDef) -> bool {
}
}

pub fn type_def_has_float(def: TypeDef) -> bool {
def.kind() == TypeKind::Struct && def.fields().any(|field| type_has_float(&field.ty(Some(def))))
}

pub fn type_has_float(ty: &Type) -> bool {
match ty {
Type::F32 | Type::F64 => true,
Type::Win32Array(ty, _) => type_has_float(ty),
Type::TypeDef(def, _) => type_def_has_float(*def),
_ => false,
}
}

pub fn type_interfaces(ty: &Type) -> Vec<Interface> {
// TODO: collect into btree map and then return collected vec
// This will both sort the results and should make finding dupes faster
Expand Down
114 changes: 26 additions & 88 deletions crates/libs/bindgen/src/rust/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@ fn gen_struct_with_name(writer: &Writer, def: metadata::TypeDef, struct_name: &s
};

let features = writer.cfg_features(&cfg);
let derive = gen_derive(writer, def);

let mut tokens = quote! {
#repr
#features
#derive
pub #struct_or_union #name {#(#fields)*}
};

tokens.combine(&gen_struct_constants(writer, def, &name, &cfg));
tokens.combine(&gen_copy_clone(writer, def, &name, &cfg));
tokens.combine(&gen_debug(writer, def, &name, &cfg));
tokens.combine(&gen_clone(writer, def, &name, &cfg));
tokens.combine(&gen_windows_traits(writer, def, &name, &cfg));
tokens.combine(&gen_compare_traits(writer, def, &name, &cfg));

if !writer.sys {
tokens.combine(&quote! {
Expand Down Expand Up @@ -135,110 +135,48 @@ fn gen_windows_traits(writer: &Writer, def: metadata::TypeDef, name: &TokenStrea
}
}

fn gen_compare_traits(writer: &Writer, def: metadata::TypeDef, name: &TokenStream, cfg: &cfg::Cfg) -> TokenStream {
let features = writer.cfg_features(cfg);
fn gen_derive(writer: &Writer, def: metadata::TypeDef) -> TokenStream {
let mut derive = std::collections::BTreeSet::new();

if writer.sys || metadata::type_def_has_explicit_layout(def) || metadata::type_def_has_packing(def) || metadata::type_def_has_callback(def) {
quote! {}
} else {
let fields = def.fields().filter_map(|f| {
let name = to_ident(f.name());
if f.flags().contains(metadata::FieldAttributes::Literal) {
None
} else {
Some(quote! { self.#name == other.#name })
}
});
if !writer.sys && !metadata::type_def_has_explicit_layout(def) && !metadata::type_def_has_packing(def) {
derive.insert(to_ident("Debug"));
}

quote! {
#features
impl PartialEq for #name {
fn eq(&self, other: &Self) -> bool {
#(#fields)&&*
}
}
#features
impl Eq for #name {}
if writer.sys || metadata::type_def_is_copyable(def) {
derive.insert(to_ident("Copy"));
derive.insert(to_ident("Clone"));
} else if def.flags().contains(metadata::TypeAttributes::WindowsRuntime) {
derive.insert(to_ident("Clone"));
}

if !writer.sys && !metadata::type_def_has_explicit_layout(def) && !metadata::type_def_has_packing(def) && !metadata::type_def_has_callback(def) {
derive.insert(to_ident("PartialEq"));

if !metadata::type_def_has_float(def) {
derive.insert(to_ident("Eq"));
}
}
}

fn gen_debug(writer: &Writer, def: metadata::TypeDef, ident: &TokenStream, cfg: &cfg::Cfg) -> TokenStream {
if writer.sys || metadata::type_def_has_explicit_layout(def) || metadata::type_def_has_packing(def) {
if derive.is_empty() {
quote! {}
} else {
let name = ident.as_str();
let features = writer.cfg_features(cfg);

let fields = def.fields().filter_map(|f| {
if f.flags().contains(metadata::FieldAttributes::Literal) {
None
} else {
let name = f.name();
let ident = to_ident(name);
let ty = f.ty(Some(def));
if metadata::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()
}
}
#[derive(#(#derive),*)]
}
}
}

fn gen_copy_clone(writer: &Writer, def: metadata::TypeDef, name: &TokenStream, cfg: &cfg::Cfg) -> TokenStream {
let features = writer.cfg_features(cfg);

if writer.sys || metadata::type_def_is_copyable(def) {
quote! {
#features
impl Copy for #name {}
#features
impl Clone for #name {
fn clone(&self) -> Self {
*self
}
}
}
} else if def.class_layout().is_some() {
// Don't support copy/clone of packed structs: https://github.com/rust-lang/rust/issues/82523
fn gen_clone(writer: &Writer, def: metadata::TypeDef, name: &TokenStream, cfg: &cfg::Cfg) -> TokenStream {
if writer.sys || metadata::type_def_is_copyable(def) || def.flags().contains(metadata::TypeAttributes::WindowsRuntime) || def.class_layout().is_some() {
quote! {}
} else if !def.flags().contains(metadata::TypeAttributes::WindowsRuntime) {
quote! {
#features
impl Clone for #name {
fn clone(&self) -> Self {
unsafe { core::mem::transmute_copy(self) }
}
}
}
} else {
let fields = def.fields().map(|f| {
let name = to_ident(f.name());
if f.flags().contains(metadata::FieldAttributes::Literal) {
quote! {}
} else if metadata::field_is_blittable(f, def) {
quote! { #name: self.#name }
} else {
quote! { #name: self.#name.clone() }
}
});
let features = writer.cfg_features(cfg);

quote! {
#features
impl Clone for #name {
fn clone(&self) -> Self {
Self { #(#fields),* }
unsafe { core::mem::transmute_copy(self) }
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "windows-core"
version = "0.56.0"
authors = ["Microsoft"]
edition = "2021"
rust-version = "1.62"
rust-version = "1.70"
license = "MIT OR Apache-2.0"
description = "Rust for Windows"
repository = "https://github.com/microsoft/windows-rs"
Expand Down
Loading

0 comments on commit e6d2e56

Please sign in to comment.