Skip to content

Commit

Permalink
Feature and doc generation (#1381)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Dec 11, 2021
1 parent b1145a6 commit f0c3723
Show file tree
Hide file tree
Showing 1,326 changed files with 511,067 additions and 11,741 deletions.
10 changes: 5 additions & 5 deletions crates/libs/bindgen/src/async.rs
@@ -1,10 +1,10 @@
use super::*;

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

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

let interfaces = if def.kind() == TypeKind::Class { def.class_interfaces().iter().map(|(def, _)| def.clone()).collect() } else { def.required_interfaces() };
Expand All @@ -13,14 +13,14 @@ pub fn gen_async(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
let kind = interface.async_kind();

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

quote! {}
}

fn gen_async_kind(kind: AsyncKind, name: &TypeDef, self_name: &TypeDef, gen: &Gen, cfg: &TokenStream) -> TokenStream {
fn gen_async_kind(kind: AsyncKind, name: &TypeDef, self_name: &TypeDef, cfg: &Cfg, gen: &Gen) -> TokenStream {
let return_sig = match kind {
AsyncKind::Operation | AsyncKind::OperationWithProgress => gen_element_name(&name.generics[0], gen),
_ => quote! { () },
Expand All @@ -37,6 +37,7 @@ fn gen_async_kind(kind: AsyncKind, name: &TypeDef, self_name: &TypeDef, gen: &Ge
let constraints = gen_type_constraints(self_name, gen);
let name = gen_type_name(self_name, gen);
let namespace = gen.namespace("Windows.Foundation");
let cfg = cfg.and_async().gen(gen);

quote! {
#cfg
Expand All @@ -54,7 +55,6 @@ fn gen_async_kind(kind: AsyncKind, name: &TypeDef, self_name: &TypeDef, gen: &Ge
}
}
#cfg
#[cfg(feature = "std")]
impl<#(#constraints)*> ::std::future::Future for #name {
type Output = ::windows::core::Result<#return_sig>;

Expand Down
6 changes: 2 additions & 4 deletions crates/libs/bindgen/src/callbacks.rs
Expand Up @@ -6,8 +6,7 @@ pub fn gen(def: &TypeDef, gen: &Gen) -> TokenStream {
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.function_cfg(&method);
let cfg = gen.type_cfg(def).gen_with_doc(gen);

let params = signature.params.iter().map(|p| {
let name = gen_param_name(&p.param);
Expand All @@ -16,8 +15,7 @@ pub fn gen(def: &TypeDef, gen: &Gen) -> TokenStream {
});

quote! {
#arch_cfg
#feature_cfg
#cfg
pub type #name = ::core::option::Option<unsafe extern "system" fn(#(#params),*) #return_sig>;
}
}
117 changes: 117 additions & 0 deletions crates/libs/bindgen/src/cfg.rs
@@ -0,0 +1,117 @@
use super::*;

#[derive(Default, Clone)]
pub struct Cfg {
pub arch: BTreeSet<&'static str>,
pub features: BTreeSet<&'static str>,
}

impl Cfg {
pub fn new() -> Self {
Default::default()
}

pub fn union(&self, other: Self) -> Self {
Self { arch: self.arch.union(&other.arch).cloned().collect(), features: self.features.union(&other.features).cloned().collect() }
}

pub fn and_iterator(&self) -> Self {
let mut combo = self.clone();
combo.features.insert("Windows.Foundation.Collections");
combo
}

pub fn and_async(&self) -> Self {
let mut combo = self.clone();
combo.features.insert("std");
combo.features.insert("Windows.Foundation");
combo
}

pub fn gen_with_doc(&self, gen: &Gen) -> TokenStream {
let doc = self.gen_doc(gen);
let requires = self.gen(gen);
quote! { #doc #requires }
}

pub fn gen_doc(&self, gen: &Gen) -> TokenStream {
if !gen.doc {
quote! {}
} else {
let mut tokens = format!("'{}'", to_feature(gen.namespace));

for features in &self.features {
tokens.push_str(&format!(", '{}'", to_feature(features)));
}

format!(r#"#[doc = "*Required features: {}*"]"#, tokens).into()
}
}

pub fn gen(&self, gen: &Gen) -> TokenStream {
if !gen.cfg {
quote! {}
} else {
let arch = match self.arch.len() {
0 => quote! {},
1 => {
let arch = &self.arch;
quote! { #[cfg(#(target_arch = #arch),*)] }
}
_ => {
let arch = &self.arch;
quote! { #[cfg(any(#(target_arch = #arch),*))] }
}
};

let features = match self.features.len() {
0 => quote! {},
1 => {
let features = self.features.iter().cloned().map(to_feature);
quote! { #[cfg(#(feature = #features)*)] }
}
_ => {
let features = self.features.iter().cloned().map(to_feature);
quote! { #[cfg(all( #(feature = #features),* ))] }
}
};

quote! { #arch #features }
}
}

pub fn gen_not(&self, gen: &Gen) -> TokenStream {
if !gen.cfg || self.features.is_empty() {
quote! {}
} else {
match self.features.len() {
0 => quote! {},
1 => {
let features = self.features.iter().cloned().map(to_feature);
quote! { #[cfg(not(#(feature = #features)*))] }
}
_ => {
let features = self.features.iter().cloned().map(to_feature);
quote! { #[cfg(not(all( #(feature = #features),* )))] }
}
}
}
}
}

fn to_feature(name: &str) -> String {
let mut feature = String::new();

for name in name.split('.').skip(1) {
feature.push_str(name);
feature.push('_');
}

if feature.is_empty() {
feature = name.to_string();
} else {
feature.truncate(feature.len() - 1);
}

feature
}
40 changes: 28 additions & 12 deletions crates/libs/bindgen/src/classes.rs
Expand Up @@ -22,6 +22,10 @@ fn gen_class(def: &TypeDef, gen: &Gen) -> TokenStream {
let mut methods = quote! {};
let mut method_names = BTreeMap::<String, u32>::new();

let cfg = gen.type_cfg(def);
let features = cfg.gen(gen);
let doc = cfg.gen_doc(gen);

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;
Expand All @@ -39,8 +43,17 @@ fn gen_class(def: &TypeDef, gen: &Gen) -> TokenStream {
if def.methods().next().is_some() {
let interface_name = format_token!("{}", def.name());
let interface_type = gen_type_name(def, gen);
let features = gen.type_cfg(def).gen(gen);

let hidden = if gen.doc {
quote! { #[doc(hidden)] }
} else {
quote! {}
};

Some(quote! {
#hidden
#features
pub fn #interface_name<R, F: FnOnce(&#interface_type) -> ::windows::core::Result<R>>(
callback: F,
) -> ::windows::core::Result<R> {
Expand Down Expand Up @@ -74,13 +87,12 @@ fn gen_class(def: &TypeDef, gen: &Gen) -> TokenStream {
quote! {}
};

let cfg = gen.type_cfg(def);

let mut tokens = quote! {
#cfg
#doc
#features
#[repr(transparent)]
pub struct #name(::windows::core::IUnknown);
#cfg
#features
impl #name {
#new
#methods
Expand All @@ -99,21 +111,25 @@ fn gen_class(def: &TypeDef, gen: &Gen) -> TokenStream {
tokens
} else {
let mut tokens = quote! {
#doc
#features
pub struct #name {}
#features
impl #name {
#methods
#(#factories)*
}
};

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

fn gen_agile(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
fn gen_agile(def: &TypeDef, cfg: &Cfg, gen: &Gen) -> TokenStream {
if def.is_agile() {
let name = gen_type_ident(def, gen);
let cfg = cfg.gen(gen);
quote! {
#cfg
unsafe impl ::core::marker::Send for #name {}
Expand All @@ -125,9 +141,10 @@ fn gen_agile(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
}
}

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

quote! {
#cfg
Expand All @@ -137,12 +154,13 @@ fn gen_runtime_name(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream
}
}

fn gen_conversions(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
fn gen_conversions(def: &TypeDef, cfg: &Cfg, 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);
let cfg = cfg.gen(gen);
tokens.combine(&quote! {
#cfg
impl ::core::convert::From<#name> for #into {
Expand Down Expand Up @@ -181,8 +199,7 @@ fn gen_conversions(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {
}

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

tokens.combine(&quote! {
#cfg
Expand Down Expand Up @@ -218,8 +235,7 @@ fn gen_conversions(def: &TypeDef, cfg: &TokenStream, gen: &Gen) -> TokenStream {

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

tokens.combine(&quote! {
#cfg
Expand Down
5 changes: 2 additions & 3 deletions crates/libs/bindgen/src/constants.rs
Expand Up @@ -4,15 +4,14 @@ use super::*;

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

let signature = def.signature(None);

let cfg = gen.field_cfg(def);
let cfg = gen.field_cfg(def).gen_with_doc(gen);

if let Some(constant) = def.constant() {
if signature.kind == constant.value_type() {
let value = gen_constant_type_value(&constant.value());
quote! {
#cfg
pub const #name: #value;
}
} else {
Expand Down
13 changes: 8 additions & 5 deletions crates/libs/bindgen/src/delegates.rs
Expand Up @@ -24,16 +24,19 @@ fn gen_win_delegate(def: &TypeDef, gen: &Gen) -> TokenStream {
let method = def.invoke_method();
let signature = method.signature(&def.generics);
let fn_constraint = gen_fn_constraint(&signature, gen);
let cfg = gen.function_cfg(&method);
let cfg = gen.type_cfg(def);
let doc = cfg.gen_doc(gen);
let features = cfg.gen(gen);
let vtbl_signature = gen_vtbl_signature(def, &method, gen);
let invoke = gen_winrt_method(def, InterfaceKind::Default, &method, 3, &mut BTreeMap::new(), gen);
let invoke_upcall = gen_winrt_upcall(&signature, quote! { ((*this).invoke) }, gen);

let mut tokens = quote! {
#cfg
#doc
#features
#[repr(transparent)]
pub struct #name<#(#generics)*>(pub ::windows::core::IUnknown, #(#phantoms)*) where #(#constraints)*;
#cfg
#features
impl<#(#constraints)*> #name<#(#generics)*> {
pub fn new<#fn_constraint>(invoke: F) -> Self {
let com = #boxed::<#(#generics)* F> {
Expand All @@ -47,14 +50,14 @@ fn gen_win_delegate(def: &TypeDef, gen: &Gen) -> TokenStream {
}
#invoke
}
#cfg
#features
#[repr(C)]
struct #boxed<#(#generics)* #fn_constraint> where #(#constraints)* {
vtable: *const #vtbl<#(#generics)*>,
invoke: F,
count: ::windows::core::RefCount,
}
#cfg
#features
impl<#(#constraints)* #fn_constraint> #boxed<#(#generics)* F> {
const VTABLE: #vtbl<#(#generics)*> = #vtbl::<#(#generics)*>(
Self::QueryInterface,
Expand Down

0 comments on commit f0c3723

Please sign in to comment.