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

Feature and doc generation #1381

Merged
merged 22 commits into from Dec 11, 2021
  •  
  •  
  •  
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