naga_to_tokenstream/
lib.rs1#![deny(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use std::collections::HashSet;
5
6pub mod constants;
8pub mod entry_points;
10pub mod globals;
12pub mod types;
14
15fn collect_tokenstream<I: quote::ToTokens>(
16 items: impl IntoIterator<Item = I>,
17) -> proc_macro2::TokenStream {
18 let mut tokens = proc_macro2::TokenStream::new();
19 for item in items {
20 item.to_tokens(&mut tokens);
21 }
22
23 tokens
24}
25
26fn module_to_source(module: &naga::Module, retain_entry_point: Option<String>) -> Option<String> {
27 #[allow(unused_mut)]
29 let mut module = module.clone();
30
31 if let Some(retain_entry_point) = retain_entry_point {
33 entry_points::filter_entry_points(&mut module, retain_entry_point);
34 }
35
36 #[cfg(feature = "minify")]
38 {
39 wgsl_minifier::minify_module(&mut module);
40 }
41
42 let info = naga::valid::Validator::new(
44 naga::valid::ValidationFlags::empty(),
45 naga::valid::Capabilities::all(),
46 )
47 .validate(&module);
48
49 let info = info.ok()?;
51 let src =
52 naga::back::wgsl::write_string(&module, &info, naga::back::wgsl::WriterFlags::empty())
53 .ok()?;
54
55 #[cfg(feature = "minify")]
57 let src = wgsl_minifier::minify_wgsl_source(&src);
58
59 Some(src)
60}
61
62#[derive(Default)]
64pub struct ModuleToTokensConfig {
65 pub structs_filter: Option<HashSet<String>>,
70 pub gen_glam: bool,
72 pub gen_encase: bool,
74 pub gen_naga: bool,
76}
77
78mod sealed {
79 pub trait SealedModule {}
80 impl SealedModule for naga::Module {}
81}
82
83pub trait ModuleToTokens: sealed::SealedModule {
94 fn to_items(&self, cfg: ModuleToTokensConfig) -> Vec<syn::Item>;
96 fn to_tokens(&self, cfg: ModuleToTokensConfig) -> proc_macro2::TokenStream {
98 collect_tokenstream(self.to_items(cfg))
99 }
100}
101impl ModuleToTokens for naga::Module {
102 fn to_items(&self, cfg: ModuleToTokensConfig) -> Vec<syn::Item> {
103 let mut items = Vec::new();
104 let mut types = types::TypesDefinitions::new(self, cfg.structs_filter.clone(), &cfg);
105
106 let globals = collect_tokenstream(globals::make_globals(self, &mut types, &cfg));
108 let globals: syn::File = syn::parse2(globals).unwrap();
109 let globals_str = format!("```rust\n{}\n```", prettyplease::unparse(&globals));
110 let globals_doc: proc_macro2::TokenStream = quote::quote! { #[doc = #globals_str] };
111 items.push(syn::parse_quote! {
112 #[allow(unused)]
113 #[doc = "Information about the globals within the module, exposed as constants and functions."]
114 #globals_doc
115 pub mod globals {
116 #[allow(unused)]
117 use super::*;
118
119 #globals
120 }
121 });
122
123 let constants = collect_tokenstream(constants::make_constants(self, &mut types, &cfg));
125 let constants: syn::File = syn::parse2(constants).unwrap();
126 let constants_str = format!("```rust\n{}\n```", prettyplease::unparse(&constants));
127 let constants_doc: proc_macro2::TokenStream = quote::quote! { #[doc = #constants_str] };
128 items.push(syn::parse_quote! {
129 #[allow(unused)]
130 #[doc = "Information about the constants within the module, exposed as constants and functions."]
131 #constants_doc
132 pub mod constants {
133 #[allow(unused)]
134 use super::*;
135
136 #constants
137 }
138 });
139
140 let entry_points =
142 collect_tokenstream(entry_points::make_entry_points(self, &mut types, &cfg));
143 let entry_points: syn::File = syn::parse2(entry_points).unwrap();
144 let entry_points_str = format!("```rust\n{}\n```", prettyplease::unparse(&entry_points));
145 let entry_points_doc: proc_macro2::TokenStream =
146 quote::quote! { #[doc = #entry_points_str] };
147 items.push(syn::parse_quote! {
148 #[allow(unused)]
149 #[doc = "Information about the entry points within the module, exposed as constants and functions."]
150 #entry_points_doc
151 pub mod entry_points {
152 #[allow(unused)]
153 use super::*;
154
155 #entry_points
156 }
157 });
158
159 let types = collect_tokenstream(types.definitions());
161 let types: syn::File = syn::parse2(types).unwrap();
162 let types_str = format!("```rust\n{}\n```", prettyplease::unparse(&types));
163 let types_doc: proc_macro2::TokenStream = quote::quote! { #[doc = #types_str] };
164 items.push(syn::parse_quote! {
165 #[allow(unused)]
166 #[doc = "Equivalent Rust definitions of the types defined in this module."]
167 #types_doc
168 pub mod types {
169 #types
170 }
171 });
172 items.push(syn::parse_quote! {
174 #[allow(unused)]
175 use types::*;
176 });
177
178 if let Some(src) = module_to_source(self, None) {
180 items.push(syn::parse_quote! {
181 #[doc = "The sourcecode for the shader, as a constant string."]
182 pub const SOURCE: &'static str = #src;
183 });
184 }
185
186 items
187 }
188}