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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
mod classes;
mod com_methods;
mod constants;
mod delegates;
mod enums;
mod extensions;
mod functions;
mod gen;
mod handles;
mod implements;
mod interfaces;
mod iterators;
mod method_names;
mod replacements;
mod structs;
mod winrt_methods;
pub use gen::*;
use metadata::reader::*;
use method_names::*;
use std::collections::*;
use std::fmt::Write;
use tokens::*;
pub fn define(gen: &Gen, name: &str) -> String {
let mut tokens = String::new();
let type_name = TypeName::parse(name);
for def in gen.reader.get(type_name) {
if let Some(def) = gen.define(def) {
tokens.push_str(def.as_str());
}
}
if tokens.is_empty() {
if let Some(apis) = gen.reader.get(TypeName::new(type_name.namespace, "Apis")).next() {
for method in gen.reader.type_def_methods(apis) {
if gen.reader.method_def_name(method) == type_name.name {
tokens.push_str(functions::gen(gen, method).as_str());
}
}
if tokens.is_empty() {
for field in gen.reader.type_def_fields(apis) {
if gen.reader.field_name(field) == type_name.name {
tokens.push_str(constants::gen(gen, field).as_str());
}
}
}
}
}
assert!(!tokens.is_empty(), "`{}` not found", name);
tokens
}
pub fn namespace(gen: &Gen, tree: &Tree) -> String {
let namespaces = tree.nested.iter().map(move |(name, tree)| {
let name = to_ident(name);
let namespace = tree.namespace[tree.namespace.find('.').unwrap() + 1..].replace('.', "_");
if gen.cfg {
quote! {
#[cfg(feature = #namespace)] pub mod #name;
}
} else {
quote! {
pub mod #name;
}
}
});
let mut functions = vec![];
if gen.sys {
if let Some(apis) = gen.reader.get(TypeName::new(tree.namespace, "Apis")).next() {
let mut methods = BTreeMap::new();
for method in gen.reader.type_def_methods(apis) {
combine(&mut methods, gen.reader.method_def_name(method), functions::gen(gen, method));
}
if !methods.is_empty() {
let methods = methods.values();
functions = vec![quote! {
#[cfg_attr(windows, link(name = "windows"))]
extern "system" {
#(#methods)*
}
}];
}
}
}
let mut types = BTreeMap::<&str, TokenStream>::new();
for def in gen.reader.namespace_types(tree.namespace) {
if let Some(tokens) = gen.define(def) {
combine_type(&mut types, gen.reader.type_def_type_name(def), tokens);
} else {
if !gen.sys {
for method in gen.reader.type_def_methods(def) {
combine(&mut types, gen.reader.method_def_name(method), functions::gen(gen, method));
}
}
for field in gen.reader.type_def_fields(def) {
combine(&mut types, gen.reader.field_name(field), constants::gen(gen, field));
}
}
}
let types = types.values();
let tokens = quote! {
#(#namespaces)*
#(#functions)*
#(#types)*
};
tokens.into_string()
}
pub fn namespace_impl(gen: &Gen, tree: &Tree) -> String {
let mut types = BTreeMap::<&str, TokenStream>::new();
for def in gen.reader.namespace_types(tree.namespace) {
combine_type(&mut types, gen.reader.type_def_type_name(def), implements::gen(gen, def));
}
let types = types.values();
let tokens = quote! {
#(#types)*
};
tokens.into_string()
}
pub fn component(namespace: &str, files: &[File]) -> String {
let reader = &Reader::new(files);
let tree = reader.tree(namespace, &[]).expect("Namespace not found");
let mut gen = Gen::new(reader);
gen.namespace = tree.namespace;
gen.component = true;
let mut bindings = crate::namespace(&gen, &tree);
bindings.push_str(&namespace_impl(&gen, &tree));
bindings
}
fn combine<'a>(types: &mut BTreeMap<&'a str, TokenStream>, name: &'a str, tokens: TokenStream) {
types.entry(name).or_default().combine(&tokens);
}
fn combine_type<'a>(types: &mut BTreeMap<&'a str, TokenStream>, type_name: TypeName<'a>, tokens: TokenStream) {
if !CORE_TYPES.iter().any(|(x, _)| x == &type_name) {
types.entry(type_name.name).or_default().combine(&tokens);
}
}
fn expand_generics(generics: TokenStream, new: TokenStream) -> TokenStream {
if generics.is_empty() {
quote!(#new)
} else {
quote!(#generics, #new)
}
}
fn expand_where_clause(where_clause: TokenStream, generic: TokenStream) -> TokenStream {
if where_clause.is_empty() {
quote!(where #generic)
} else {
quote!(#where_clause #generic)
}
}