1 | mod cfg; |
2 | mod cpp_handle; |
3 | mod format; |
4 | mod names; |
5 | mod value; |
6 | |
7 | use super::*; |
8 | use rayon::prelude::*; |
9 | |
10 | #[derive (Clone)] |
11 | pub struct Writer { |
12 | pub config: &'static Config, |
13 | pub namespace: &'static str, |
14 | } |
15 | |
16 | impl 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 | |