1mod cfg;
2mod cpp_handle;
3mod format;
4mod names;
5mod value;
6
7use super::*;
8use rayon::prelude::*;
9
10#[derive(Clone)]
11pub struct Writer {
12 pub config: &'static Config,
13 pub namespace: &'static str,
14}
15
16impl Writer {
17 fn with_namespace(&self, namespace: &'static str) -> Self {
18 let mut clone = self.clone();
19 clone.namespace = namespace;
20 clone
21 }
22
23 #[track_caller]
24 pub fn write(&self, tree: TypeTree) {
25 if self.config.package {
26 self.write_package(&tree);
27 } else {
28 self.write_file(tree);
29 }
30 }
31
32 #[track_caller]
33 fn write_file(&self, tree: TypeTree) {
34 let tokens = if self.config.flat {
35 self.write_flat(tree)
36 } else {
37 self.write_modules(&tree)
38 };
39
40 write_to_file(&self.config.output, self.format(&tokens.into_string()));
41 }
42
43 fn write_flat(&self, tree: TypeTree) -> TokenStream {
44 let mut tokens = TokenStream::new();
45
46 for ty in tree.flatten_types() {
47 tokens.combine(ty.write(self));
48 }
49
50 tokens
51 }
52
53 fn write_modules(&self, tree: &TypeTree) -> TokenStream {
54 let mut tokens = TokenStream::new();
55
56 for ty in &tree.types {
57 tokens.combine(ty.write(self));
58 }
59
60 for (name, tree) in &tree.nested {
61 let name = to_ident(name);
62 let nested = self.with_namespace(tree.namespace).write_modules(tree);
63 tokens.combine(quote! { pub mod #name { #nested } });
64 }
65
66 tokens
67 }
68
69 fn write_package(&self, tree: &TypeTree) {
70 for name in tree.nested.keys() {
71 _ = std::fs::remove_dir_all(format!("{}/src/{name}", &self.config.output));
72 }
73
74 let trees = tree.flatten_trees();
75
76 trees.par_iter().for_each(|tree| {
77 let directory = format!(
78 "{}/src/{}",
79 &self.config.output,
80 tree.namespace.replace('.', "/")
81 );
82
83 let mut tokens = TokenStream::new();
84
85 for (name, tree) in &tree.nested {
86 let name = to_ident(name);
87 let feature = tree.feature();
88
89 tokens.combine(quote! {
90 #[cfg(feature = #feature)]
91 pub mod #name;
92 });
93 }
94
95 let writer = self.with_namespace(tree.namespace);
96
97 for ty in &tree.types {
98 tokens.combine(ty.write(&writer));
99 }
100
101 let output = format!("{directory}/mod.rs");
102 write_to_file(&output, self.format(&tokens.into_string()));
103 });
104
105 if self.config.no_toml {
106 return;
107 }
108
109 let toml_path = format!("{}/Cargo.toml", &self.config.output);
110 let mut toml = String::new();
111
112 for line in read_file_lines(&toml_path) {
113 toml.push_str(&line);
114 toml.push('\n');
115
116 if line == "# generated features" {
117 break;
118 }
119 }
120
121 for tree in trees.iter().skip(1) {
122 let feature = tree.feature();
123
124 if let Some(pos) = feature.rfind('_') {
125 let dependency = &feature[..pos];
126
127 toml.push_str(&format!("{feature} = [\"{dependency}\"]\n"));
128 } else if namespace_starts_with(tree.namespace, "Windows.Win32")
129 || namespace_starts_with(tree.namespace, "Windows.Wdk")
130 {
131 toml.push_str(&format!("{feature} = [\"Win32_Foundation\"]\n"));
132 } else if tree.namespace != "Windows.Foundation" {
133 toml.push_str(&format!("{feature} = [\"Foundation\"]\n"));
134 } else {
135 toml.push_str(&format!("{feature} = []\n"));
136 }
137 }
138
139 write_to_file(&toml_path, toml);
140 }
141}
142