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

Introduce new bindgen crate #1379

Merged
merged 64 commits into from Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
77a5f80
api2
kennykerr Nov 29, 2021
afc5850
sys
kennykerr Nov 29, 2021
8c28b46
enum
kennykerr Nov 29, 2021
92f3116
interface
kennykerr Nov 30, 2021
ccd004c
ident
kennykerr Nov 30, 2021
a9f0228
interface
kennykerr Nov 30, 2021
fa55536
structs
kennykerr Nov 30, 2021
da5539d
Vtbl
kennykerr Nov 30, 2021
7f99a1d
struct
kennykerr Nov 30, 2021
5bdef2c
constant
kennykerr Nov 30, 2021
7fdafe1
structs
kennykerr Nov 30, 2021
000c1a8
structs
kennykerr Nov 30, 2021
04277dd
generics
kennykerr Nov 30, 2021
5369ea5
structs
kennykerr Nov 30, 2021
b0a3a24
fmt
kennykerr Dec 1, 2021
48aeff1
interface
kennykerr Dec 1, 2021
ffcaefb
com
kennykerr Dec 1, 2021
3f4a82a
delegates
kennykerr Dec 1, 2021
c8328e8
udt and bstr
kennykerr Dec 2, 2021
0c37414
frunctions
kennykerr Dec 2, 2021
4af9a04
conversion
kennykerr Dec 2, 2021
8582ad0
COM works
kennykerr Dec 2, 2021
28bcf8e
default
kennykerr Dec 2, 2021
0a8d80e
traits
kennykerr Dec 2, 2021
6cde4c3
check
kennykerr Dec 2, 2021
6344094
winrt
kennykerr Dec 3, 2021
2f31e07
fmt
kennykerr Dec 3, 2021
34f573e
gen
kennykerr Dec 3, 2021
deb5b37
ident
kennykerr Dec 3, 2021
ddb82e4
fix
kennykerr Dec 3, 2021
57423f2
interface
kennykerr Dec 3, 2021
6a85439
required
kennykerr Dec 4, 2021
b1c2cf6
required
kennykerr Dec 4, 2021
12cd5c8
classes
kennykerr Dec 6, 2021
c9a399f
classes
kennykerr Dec 7, 2021
025abc0
gen
kennykerr Dec 7, 2021
1e3d14d
delegates
kennykerr Dec 7, 2021
08a0205
delegates
kennykerr Dec 8, 2021
4d56d88
delegate
kennykerr Dec 8, 2021
a19b70c
async
kennykerr Dec 8, 2021
6f4021b
iterator
kennykerr Dec 8, 2021
2c870f0
conversions
kennykerr Dec 8, 2021
7ec15d4
testing
kennykerr Dec 8, 2021
12f88b3
cfg
kennykerr Dec 8, 2021
8a45d43
derive
kennykerr Dec 8, 2021
c322688
bindings
kennykerr Dec 9, 2021
1fe56ad
enum
kennykerr Dec 9, 2021
5e74803
warnings
kennykerr Dec 9, 2021
86b072f
api
kennykerr Dec 9, 2021
8eee378
fmt
kennykerr Dec 9, 2021
92a9b2b
bindgen
kennykerr Dec 9, 2021
d3167da
derive
kennykerr Dec 9, 2021
cbffc83
min
kennykerr Dec 9, 2021
f70514a
pub
kennykerr Dec 9, 2021
355d4a4
sig
kennykerr Dec 9, 2021
17d5b73
api
kennykerr Dec 9, 2021
f9526e3
xaml
kennykerr Dec 9, 2021
9fd807e
test
kennykerr Dec 9, 2021
b123ef4
handle
kennykerr Dec 9, 2021
9dfa69e
agile
kennykerr Dec 9, 2021
cb6abdc
compare
kennykerr Dec 9, 2021
f2e3e38
fmt
kennykerr Dec 9, 2021
2f5dc41
clippy
kennykerr Dec 9, 2021
6bc0c6b
fmt
kennykerr Dec 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
@@ -1,5 +1,5 @@
[package]
name = "windows_gen2"
name = "windows-bindgen"
version = "0.28.0"
authors = ["Microsoft"]
edition = "2018"
Expand Down
77 changes: 77 additions & 0 deletions crates/deps/bindgen/src/async.rs
@@ -0,0 +1,77 @@
use super::*;

pub fn gen_async(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
let kind = def.async_kind();

if kind != AsyncKind::None {
return gen_async_kind(kind, def, def, gen, cfg);
}

let interfaces = if def.kind() == TypeKind::Class { def.class_interfaces().iter().map(|(def, _)| def.clone()).collect() } else { def.required_interfaces() };

for interface in interfaces {
let kind = interface.async_kind();

if kind != AsyncKind::None {
return gen_async_kind(kind, &interface, def, gen, cfg);
}
}

quote! {}
}

fn gen_async_kind(kind: AsyncKind, name: &TypeDef, self_name: &TypeDef, gen: &Gen, cfg: &TokenStream) -> TokenStream {
let return_sig = match kind {
AsyncKind::Operation | AsyncKind::OperationWithProgress => gen_element_name(&name.generics[0], gen),
_ => quote! { () },
};

let handler = match kind {
AsyncKind::Action => quote! { AsyncActionCompletedHandler },
AsyncKind::ActionWithProgress => quote! { AsyncActionWithProgressCompletedHandler },
AsyncKind::Operation => quote! { AsyncOperationCompletedHandler },
AsyncKind::OperationWithProgress => quote! { AsyncOperationWithProgressCompletedHandler },
_ => unimplemented!(),
};

let constraints = gen_type_constraints(self_name, gen);
let name = gen_type_name(self_name, gen);
let namespace = gen.namespace("Windows.Foundation");

quote! {
#cfg
impl<#(#constraints)*> #name {
pub fn get(&self) -> ::windows::core::Result<#return_sig> {
if self.Status()? == #namespace AsyncStatus::Started {
let (_waiter, signaler) = ::windows::core::Waiter::new();
self.SetCompleted(#namespace #handler::new(move |_sender, _args| {
// Safe because the waiter will only be dropped after being signaled.
unsafe { signaler.signal(); }
Ok(())
}))?;
}
self.GetResults()
}
}
#cfg
#[cfg(feature = "std")]
impl<#(#constraints)*> ::std::future::Future for #name {
type Output = ::windows::core::Result<#return_sig>;

fn poll(self: ::std::pin::Pin<&mut Self>, context: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output> {
if self.Status()? == #namespace AsyncStatus::Started {
let waker = context.waker().clone();

let _ = self.SetCompleted(#namespace #handler::new(move |_sender, _args| {
waker.wake_by_ref();
Ok(())
}));

::std::task::Poll::Pending
} else {
::std::task::Poll::Ready(self.GetResults())
}
}
}
}
}
@@ -1,16 +1,17 @@
use super::*;

pub fn gen_callback(def: &TypeDef, gen: &Gen) -> TokenStream {
let name = gen_type_name(def, gen);
pub fn gen(def: &TypeDef, gen: &Gen) -> TokenStream {
let name = gen_ident(def.name());

let method = def.invoke_method();
let signature = method.signature(&[]);
let return_sig = gen_return_sig(&signature, gen);
let arch_cfg = gen.arch_cfg(def.attributes());
let feature_cfg = gen.method_cfg(&method).0;
let feature_cfg = gen.function_cfg(&method);

let params = signature.params.iter().map(|p| {
let name = gen_param_name(&p.param);
let tokens = gen_abi_param_sig(p, gen);
let tokens = gen_param_sig(p, gen);
quote! { #name: #tokens }
});

Expand Down
255 changes: 255 additions & 0 deletions crates/deps/bindgen/src/classes.rs
@@ -0,0 +1,255 @@
use super::*;

pub fn gen(def: &TypeDef, gen: &Gen) -> TokenStream {
if gen.sys {
if def.default_interface().is_some() {
let name = gen_type_ident(def, gen);
quote! {
pub type #name = *mut ::core::ffi::c_void;
}
} else {
quote! {}
}
} else {
gen_class(def, gen)
}
}

fn gen_class(def: &TypeDef, gen: &Gen) -> TokenStream {
let name = gen_type_ident(def, gen);
let has_default = def.default_interface().is_some();
let interfaces = def.class_interfaces();
let mut methods = quote! {};
let mut method_names = BTreeMap::<String, u32>::new();

for (def, kind) in &interfaces {
if gen.min_xaml && *kind == InterfaceKind::Base && gen.namespace.starts_with("Windows.UI.Xaml") && !def.namespace().starts_with("Windows.Foundation") {
continue;
}

let mut vtable_offset = 6;
for method in def.methods() {
methods.combine(&gen_winrt_method(def, *kind, &method, vtable_offset, &mut method_names, gen));
vtable_offset += 1;
}
}

let factories = interfaces.iter().filter_map(|(def, kind)| match kind {
InterfaceKind::Static | InterfaceKind::Composable => {
if def.methods().next().is_some() {
let interface_name = format_token!("{}", def.name());
let interface_type = gen_type_name(def, gen);

Some(quote! {
pub fn #interface_name<R, F: FnOnce(&#interface_type) -> ::windows::core::Result<R>>(
callback: F,
) -> ::windows::core::Result<R> {
static mut SHARED: ::windows::core::FactoryCache<#name, #interface_type> =
::windows::core::FactoryCache::new();
unsafe { SHARED.call(callback) }
}
})
} else {
None
}
}
_ => None,
});

if has_default {
let new = if def.has_default_constructor() {
quote! {
pub fn new() -> ::windows::core::Result<Self> {
Self::IActivationFactory(|f| f.activate_instance::<Self>())
}
fn IActivationFactory<R, F: FnOnce(&::windows::core::IActivationFactory) -> ::windows::core::Result<R>>(
callback: F,
) -> ::windows::core::Result<R> {
static mut SHARED: ::windows::core::FactoryCache<#name, ::windows::core::IActivationFactory> =
::windows::core::FactoryCache::new();
unsafe { SHARED.call(callback) }
}
}
} else {
quote! {}
};

let cfg = gen.type_cfg(def);

let mut tokens = quote! {
#cfg
#[repr(transparent)]
pub struct #name(::windows::core::IUnknown);
#cfg
impl #name {
#new
#methods
#(#factories)*
}
};

tokens.combine(&gen_std_traits(def, &cfg, gen));
tokens.combine(&gen_runtime_trait(def, &cfg, gen));
tokens.combine(&gen_interface_trait(def, &cfg, gen));
tokens.combine(&gen_runtime_name(def, &cfg, gen));
tokens.combine(&gen_async(def, &cfg, gen));
tokens.combine(&gen_iterator(def, &cfg, gen));
tokens.combine(&gen_conversions(def, &cfg, gen));
tokens.combine(&gen_agile(def, &cfg, gen));
tokens
} else {
let mut tokens = quote! {
pub struct #name {}
impl #name {
#methods
#(#factories)*
}
};

tokens.combine(&gen_runtime_name(def, &quote! {}, gen));
tokens
}
}

fn gen_agile(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
if def.is_agile() {
let name = gen_type_ident(def, gen);
quote! {
#cfg
unsafe impl ::core::marker::Send for #name {}
#cfg
unsafe impl ::core::marker::Sync for #name {}
}
} else {
TokenStream::new()
}
}

fn gen_runtime_name(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
let name = gen_type_ident(def, gen);
let runtime_name = format!("{}", def.type_name());

quote! {
#cfg
impl ::windows::core::RuntimeName for #name {
const NAME: &'static str = #runtime_name;
}
}
}

fn gen_conversions(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
let name = gen_type_ident(def, gen);
let mut tokens = quote! {};

for def in &[ElementType::IUnknown, ElementType::IInspectable] {
let into = gen_element_name(def, gen);
tokens.combine(&quote! {
#cfg
impl ::core::convert::From<#name> for #into {
fn from(value: #name) -> Self {
unsafe { ::core::mem::transmute(value) }
}
}
#cfg
impl ::core::convert::From<&#name> for #into {
fn from(value: &#name) -> Self {
::core::convert::From::from(::core::clone::Clone::clone(value))
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for #name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::windows::core::Param::Owned(unsafe { ::core::mem::transmute(self) })
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for &#name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::windows::core::Param::Borrowed(unsafe { ::core::mem::transmute(self) })
}
}
});
}

for (def, kind) in def.class_interfaces() {
if def.is_exclusive() {
continue;
}

if kind != InterfaceKind::Default && kind != InterfaceKind::NonDefault && kind != InterfaceKind::Base {
continue;
}

let into = gen_type_name(&def, gen);
let mut cfg = cfg.clone();
cfg.combine(&gen.type_cfg(&def));

tokens.combine(&quote! {
#cfg
impl ::core::convert::TryFrom<#name> for #into {
type Error = ::windows::core::Error;
fn try_from(value: #name) -> ::windows::core::Result<Self> {
::core::convert::TryFrom::try_from(&value)
}
}
#cfg
impl ::core::convert::TryFrom<&#name> for #into {
type Error = ::windows::core::Error;
fn try_from(value: &#name) -> ::windows::core::Result<Self> {
::windows::core::Interface::cast(value)
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for #name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::windows::core::IntoParam::into_param(&self)
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for &#name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::core::convert::TryInto::<#into>::try_into(self)
.map(::windows::core::Param::Owned)
.unwrap_or(::windows::core::Param::None)
}
}
});
}

for def in def.bases() {
let into = gen_type_name(&def, gen);
let mut cfg = cfg.clone();
cfg.combine(&gen.type_cfg(&def));

tokens.combine(&quote! {
#cfg
impl ::core::convert::From<#name> for #into {
fn from(value: #name) -> Self {
::core::convert::From::from(&value)
}
}
#cfg
impl ::core::convert::From<&#name> for #into {
fn from(value: &#name) -> Self {
// This unwrap is legitimate because conversion to base can never fail because
// the base can never change across versions.
::windows::core::Interface::cast(value).unwrap()
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for #name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::windows::core::IntoParam::into_param(&self)
}
}
#cfg
impl<'a> ::windows::core::IntoParam<'a, #into> for &#name {
fn into_param(self) -> ::windows::core::Param<'a, #into> {
::windows::core::Param::Owned(::core::convert::Into::<#into>::into(self))
}
}
});
}

tokens
}