Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit core types for standalone code generation #2421

Merged
merged 2 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 2 additions & 197 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use method_names::*;
use std::collections::*;
use std::fmt::Write;
use tokens::*;
mod standalone;
pub use standalone::*;

#[doc(hidden)]
pub use gen::*;
Expand Down Expand Up @@ -194,203 +196,6 @@ pub fn component(namespace: &str, files: &[File]) -> String {
bindings
}

/// Generates standalone bindings for Windows APIs.
pub fn standalone(names: &[&str]) -> String {
let files = &File::with_default(&[]).unwrap();
let reader = &Reader::new(files);
let mut gen = &mut Gen::new(reader);
gen.standalone = true;
gen.sys = true;
let mut tokens: TokenStream = format!(
r#"// Bindings generated by `windows-bindgen` {}

"#,
std::env!("CARGO_PKG_VERSION")
)
.into();

tokens.combine(&allow());

tokens.combine(&quote! {
pub type HRESULT = i32;
pub type HSTRING = *mut ::core::ffi::c_void;
pub type IUnknown = *mut ::core::ffi::c_void;
pub type IInspectable = *mut ::core::ffi::c_void;
pub type PSTR = *mut u8;
pub type PWSTR = *mut u16;
pub type PCSTR = *const u8;
pub type PCWSTR = *const u16;
pub type BSTR = *const u16;
#[repr(C)]
pub struct GUID {
pub data1: u32,
pub data2: u16,
pub data3: u16,
pub data4: [u8; 8],
}
impl GUID {
pub const fn from_u128(uuid: u128) -> Self {
Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() }
}
}
impl ::core::marker::Copy for GUID {}
impl ::core::clone::Clone for GUID {
fn clone(&self) -> Self {
*self
}
}
});

let mut type_names = BTreeSet::new();

for name in names {
let type_name = TypeName::parse(name);
let mut found = false;

if let Some(def) = reader.get(type_name).next() {
found = true;
type_names.insert(type_name);
for def in reader.type_def_cfg(def, &[]).types.values().flatten() {
type_names.insert(reader.type_def_type_name(*def));
}
}

if !found {
if let Some(def) = reader
.get(TypeName::new(type_name.namespace, "Apis"))
.next()
{
for method in gen.reader.type_def_methods(def) {
if found {
break;
}
let name = gen.reader.method_def_name(method);
if name == type_name.name {
found = true;
type_names.insert(type_name);
for def in reader
.signature_cfg(&reader.method_def_signature(method, &[]))
.types
.values()
.flatten()
{
type_names.insert(reader.type_def_type_name(*def));
}
}
}
for field in gen.reader.type_def_fields(def) {
if found {
break;
}
let name = gen.reader.field_name(field);
if name == type_name.name {
found = true;
type_names.insert(type_name);
for def in reader.field_cfg(field).types.values().flatten() {
type_names.insert(reader.type_def_type_name(*def));
}
}
}
}
}
}

for type_name in type_names {
let mut found = false;

for def in reader.get(type_name) {
found = true;
let kind = gen.reader.type_def_kind(def);

match kind {
TypeKind::Class | TypeKind::Interface => unimplemented!(),
TypeKind::Enum => tokens.combine(&enums::gen(gen, def)),
TypeKind::Struct => {
if gen.reader.type_def_fields(def).next().is_none() {
if let Some(guid) = gen.reader.type_def_guid(def) {
let ident = to_ident(type_name.name);
let value = gen.guid(&guid);
let guid = gen.type_name(&Type::GUID);
let cfg = gen.reader.type_def_cfg(def, &[]);
let doc = gen.cfg_doc(&cfg);
let constant = quote! {
#doc
pub const #ident: #guid = #value;
};
tokens.combine(&constant);
continue;
}
}
tokens.combine(&structs::gen(gen, def));
}
TypeKind::Delegate => tokens.combine(&delegates::gen(gen, def)),
}
}

if !found {
if let Some(def) = reader
.get(TypeName::new(type_name.namespace, "Apis"))
.next()
{
for method in gen.reader.type_def_methods(def) {
if found {
break;
}
let name = gen.reader.method_def_name(method);
if name == type_name.name {
found = true;
tokens.combine(&functions::gen(gen, method));
}
}
for field in gen.reader.type_def_fields(def) {
if found {
break;
}
let name = gen.reader.field_name(field);
if name == type_name.name {
found = true;
tokens.combine(&constants::gen(gen, field));
}
}
}
}
}

try_format(tokens.into_string())
}

fn try_format(tokens: String) -> String {
use std::io::Write;

let Ok(mut child) = std::process::Command::new("rustfmt").stdin(std::process::Stdio::piped()).stdout(std::process::Stdio::piped()).stderr(std::process::Stdio::null()).spawn() else {
return tokens;
};

let Some(mut stdin) = child.stdin.take() else {
return tokens;
};

if stdin.write_all(tokens.as_bytes()).is_err() {
return tokens;
}

drop(stdin);

let Ok(output) = child.wait_with_output() else {
return tokens;
};

if !output.status.success() {
return tokens;
}

if let Ok(result) = String::from_utf8(output.stdout) {
result
} else {
tokens
}
}

fn allow() -> TokenStream {
quote! {
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
Expand Down
Loading