/
implements.rs
129 lines (110 loc) · 4.8 KB
/
implements.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use super::*;
pub fn gen(def: &TypeDef, gen: &Gen) -> TokenStream {
if def.kind() != TypeKind::Interface || !def.can_implement() {
return quote! {};
}
let type_ident = gen_ident(def.name());
let impl_ident = type_ident.join("_Impl");
let vtbl_ident = type_ident.join("_Vtbl");
let constraints = gen_type_constraints(def, gen);
let generics = gen_type_generics(def, gen);
let phantoms = gen_named_phantoms(def, gen);
let cfg = gen.type_impl_cfg(def);
let mut requires = quote! {};
fn gen_required_trait(def: &TypeDef, gen: &Gen) -> TokenStream {
let name = gen_impl_ident(def, gen);
let namespace = gen.namespace(def.namespace());
quote! {
+ #namespace #name
}
}
let mut matches = quote! { iid == &<#type_ident<#(#generics)*> as ::windows::core::Interface>::IID };
for def in def.vtable_types() {
if let ElementType::TypeDef(def) = def {
requires.combine(&gen_required_trait(&def, gen));
let name = gen_ident(def.name());
let namespace = gen.namespace(def.namespace());
matches.combine("e! {
|| iid == &<#namespace #name as ::windows::core::Interface>::IID
})
}
}
if def.is_winrt() {
for def in def.required_interfaces() {
requires.combine(&gen_required_trait(&def, gen));
}
}
let runtime_name = gen_runtime_name(def, &cfg, gen);
let cfg = cfg.gen(gen);
let mut method_names = MethodNames::new();
method_names.add_vtable_types(def);
let method_traits = def.methods().map(|method| {
let name = method_names.add(&method);
let signature = gen_impl_signature(def, &method, gen);
// If it can be implemented but is exclusive and has no return value then
// it is a Xaml override so give it a default implementation to make it easier
// to override individual methods for Xaml notifications.
if def.is_exclusive() && method.signature(&def.generics).return_sig.is_none() {
quote! {
fn #name #signature {
::core::result::Result::Ok(())
}
}
} else {
quote! { fn #name #signature; }
}
});
let mut method_names = MethodNames::new();
method_names.add_vtable_types(def);
let method_impls = def.methods().map(|method| {
let name = method_names.add(&method);
let signature = method.signature(&def.generics);
let vtbl_signature = gen_vtbl_signature(def, &method, gen);
let invoke_upcall = if def.is_winrt() { gen_winrt_upcall(&signature, quote! { (*this).#name }, gen) } else { gen_win32_upcall(&signature, quote! { (*this).#name }) };
quote! {
unsafe extern "system" fn #name<#(#constraints)* Identity: ::windows::core::IUnknownImpl, Impl: #impl_ident<#(#generics)*>, const OFFSET: isize> #vtbl_signature {
let this = (this as *mut ::windows::core::RawPtr).offset(OFFSET) as *mut Identity;
let this = (*this).get_impl() as *mut Impl;
#invoke_upcall
}
}
});
let mut methods = quote! {};
match def.vtable_types().last() {
Some(ElementType::IUnknown) => methods.combine("e! { base: ::windows::core::IUnknownVtbl::new::<Identity, OFFSET>(), }),
Some(ElementType::IInspectable) => methods.combine("e! { base: ::windows::core::IInspectableVtbl::new::<Identity, #type_ident<#(#generics)*>, OFFSET>(), }),
Some(ElementType::TypeDef(def)) => {
let vtbl = gen_vtbl_ident(def, gen);
let namespace = gen.namespace(def.namespace());
methods.combine("e! { base: #namespace #vtbl::new::<Identity, Impl, OFFSET>(), });
}
_ => {}
}
let mut method_names = MethodNames::new();
method_names.add_vtable_types(def);
for method in def.methods() {
let name = method_names.add(&method);
// TODO: can we use core::ptr::addr_of to avoid the need for const_fn_fn_ptr_basics?
methods.combine("e! { #name: #name::<#(#generics)* Identity, Impl, OFFSET>, });
}
quote! {
#cfg
pub trait #impl_ident<#(#generics)*> : Sized #requires where #(#constraints)* {
#(#method_traits)*
}
#runtime_name
#cfg
impl<#(#constraints)*> #vtbl_ident<#(#generics)*> {
pub const fn new<Identity: ::windows::core::IUnknownImpl, Impl: #impl_ident<#(#generics)*>, const OFFSET: isize>() -> #vtbl_ident<#(#generics)*> {
#(#method_impls)*
Self{
#methods
#(#phantoms)*
}
}
pub fn matches(iid: &windows::core::GUID) -> bool {
#matches
}
}
}
}