Skip to content

Commit

Permalink
Introduce new bindgen crate (#1379)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Dec 10, 2021
1 parent 1b8c179 commit 0164002
Show file tree
Hide file tree
Showing 791 changed files with 967,156 additions and 917,807 deletions.
@@ -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
}

0 comments on commit 0164002

Please sign in to comment.