#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
use std::collections::HashSet;
pub mod constants;
pub mod entry_points;
pub mod globals;
pub mod types;
fn collect_tokenstream<I: quote::ToTokens>(
items: impl IntoIterator<Item = I>,
) -> proc_macro2::TokenStream {
let mut tokens = proc_macro2::TokenStream::new();
for item in items {
item.to_tokens(&mut tokens);
}
tokens
}
fn module_to_source(module: &naga::Module, retain_entry_point: Option<String>) -> Option<String> {
#[allow(unused_mut)]
let mut module = module.clone();
if let Some(retain_entry_point) = retain_entry_point {
entry_points::filter_entry_points(&mut module, retain_entry_point);
}
#[cfg(feature = "minify")]
{
wgsl_minifier::minify_module(&mut module);
}
let info = naga::valid::Validator::new(
naga::valid::ValidationFlags::empty(),
naga::valid::Capabilities::all(),
)
.validate(&module);
let info = info.ok()?;
let src =
naga::back::wgsl::write_string(&module, &info, naga::back::wgsl::WriterFlags::empty())
.ok()?;
#[cfg(feature = "minify")]
let src = wgsl_minifier::minify_wgsl_source(&src);
return Some(src);
}
pub struct ModuleToTokensConfig {
pub structs_filter: Option<HashSet<String>>,
}
impl Default for ModuleToTokensConfig {
fn default() -> Self {
Self {
structs_filter: None,
}
}
}
mod sealed {
pub trait SealedModule {}
impl SealedModule for naga::Module {}
}
pub trait ModuleToTokens: sealed::SealedModule {
fn to_items(&self, cfg: ModuleToTokensConfig) -> Vec<syn::Item>;
fn to_tokens(&self, cfg: ModuleToTokensConfig) -> proc_macro2::TokenStream {
collect_tokenstream(self.to_items(cfg))
}
}
impl ModuleToTokens for naga::Module {
fn to_items(&self, cfg: ModuleToTokensConfig) -> Vec<syn::Item> {
let mut items = Vec::new();
let mut types = types::TypesDefinitions::new(&self, cfg.structs_filter);
let globals = collect_tokenstream(globals::make_globals(self, &mut types));
items.push(syn::parse_quote! {
#[allow(unused)]
#[doc = "Information about the globals within the module, exposed as constants and functions."]
pub mod globals {
#[allow(unused)]
use super::*;
#globals
}
});
let constants = collect_tokenstream(constants::make_constants(self, &mut types));
items.push(syn::parse_quote! {
#[allow(unused)]
#[doc = "Information about the constants within the module, exposed as constants and functions."]
pub mod constants {
#[allow(unused)]
use super::*;
#constants
}
});
let entry_points = collect_tokenstream(entry_points::make_entry_points(self, &mut types));
items.push(syn::parse_quote! {
#[allow(unused)]
#[doc = "Information about the entry points within the module, exposed as constants and functions."]
pub mod entry_points {
#[allow(unused)]
use super::*;
#entry_points
}
});
let types = collect_tokenstream(types.definitions());
items.push(syn::parse_quote! {
#[allow(unused)]
#[doc = "Equivalent Rust definitions of the types defined in this module."]
pub mod types {
#types
}
});
items.push(syn::parse_quote! {
#[allow(unused)]
use types::*;
});
if let Some(src) = module_to_source(self, None) {
items.push(syn::parse_quote! {
#[doc = "The sourcecode for the shader, as a constant string."]
pub const SOURCE: &'static str = #src;
});
}
items
}
}