1use std::{
2 collections::HashSet,
3 path::{Path, PathBuf},
4};
5
6use crate::{
7 include::IncludeHandler,
8 position::{ShaderFileRange, ShaderRange},
9 shader::ShaderContextParams,
10 shader_error::ShaderDiagnostic,
11 symbols::{
12 shader_module::ShaderSymbols,
13 symbol_list::{ShaderSymbolList, ShaderSymbolListRef},
14 symbols::{
15 ShaderSymbol, ShaderSymbolData, ShaderSymbolMode, ShaderSymbolRuntime,
16 ShaderSymbolRuntimeContext,
17 },
18 },
19};
20
21#[derive(Debug, Default, Clone)]
22pub struct ShaderRegion {
23 pub range: ShaderRange,
24 pub is_active: bool, }
27
28impl ShaderRegion {
29 pub fn new(range: ShaderRange, is_active: bool) -> Self {
30 Self { range, is_active }
31 }
32}
33
34#[derive(Debug, Default, Clone)]
35pub struct ShaderPreprocessorContext {
36 defines: Vec<ShaderSymbol>,
37 include_handler: IncludeHandler,
38 dirty_files: HashSet<PathBuf>, depth: usize,
40}
41
42impl ShaderPreprocessorContext {
43 pub fn main(file_path: &Path, shader_params: ShaderContextParams) -> Self {
44 Self {
45 defines: shader_params
46 .defines
47 .iter()
48 .map(|(key, value)| ShaderSymbol {
49 label: key.clone(),
50 requirement: None,
51 data: ShaderSymbolData::Macro {
52 value: value.clone(),
53 },
54 mode: ShaderSymbolMode::RuntimeContext(ShaderSymbolRuntimeContext::new()),
55 })
56 .collect(),
57 include_handler: IncludeHandler::main(
58 &file_path,
59 shader_params.includes,
60 shader_params.path_remapping,
61 ),
62 dirty_files: HashSet::new(),
63 depth: 0,
64 }
65 }
66 pub fn mark_dirty(&mut self, file_path: PathBuf) {
67 self.dirty_files.insert(file_path);
68 }
69 pub fn search_path_in_includes(&mut self, path: &Path) -> Option<PathBuf> {
70 self.include_handler.search_path_in_includes(path)
71 }
72 pub fn push_directory_stack(&mut self, canonical_path: &Path) {
73 self.include_handler.push_directory_stack(canonical_path);
74 }
75 pub fn push_define(&mut self, name: &str, value: &str) {
76 self.defines.push(ShaderSymbol {
77 label: name.into(),
78 requirement: None,
79 data: ShaderSymbolData::Macro {
80 value: value.into(),
81 },
82 mode: ShaderSymbolMode::RuntimeContext(ShaderSymbolRuntimeContext::new()),
83 });
84 }
85 pub fn append_defines(&mut self, defines: Vec<ShaderPreprocessorDefine>) {
86 self.defines
87 .extend(defines.iter().map(|define| define.symbol.clone()));
88 }
89 pub fn increase_depth(&mut self) -> bool {
90 if self.depth < IncludeHandler::DEPTH_LIMIT {
91 self.depth += 1;
92 true
93 } else {
94 false
95 }
96 }
97 pub fn decrease_depth(&mut self) {
98 assert!(self.depth > 0, "Decreasing depth but zero.");
99 self.depth -= 1;
100 }
101 pub fn get_visited_count(&mut self, path: &Path) -> usize {
102 self.include_handler.get_visited_count(path)
103 }
104 pub fn is_dirty(&self, file_path: &Path, context: &ShaderPreprocessorContext) -> bool {
105 fn are_defines_equal(lhs: &Vec<ShaderSymbol>, rhs: &Vec<ShaderSymbol>) -> bool {
108 if lhs.len() != rhs.len() {
109 return false;
110 }
111 for lhs_symbol in lhs.iter() {
112 if rhs
113 .iter()
114 .find(|rhs_symbol| {
115 lhs_symbol.label == rhs_symbol.label
116 && match (&lhs_symbol.data, &rhs_symbol.data) {
117 (
118 ShaderSymbolData::Macro { value: l_value },
119 ShaderSymbolData::Macro { value: r_value },
120 ) => l_value == r_value,
121 _ => false,
122 }
123 })
124 .is_none()
125 {
126 return false;
127 }
128 }
129 true
130 }
131 fn are_includes_equal(lhs: &HashSet<PathBuf>, rhs: &HashSet<PathBuf>) -> bool {
132 if lhs.len() != rhs.len() {
133 return false;
134 }
135 for lhs_symbol in lhs.iter() {
136 if rhs
137 .iter()
138 .find(|rhs_symbol| lhs_symbol.as_os_str() == rhs_symbol.as_os_str())
139 .is_none()
140 {
141 return false;
142 }
143 }
144 true
145 }
146 !are_defines_equal(&context.defines, &self.defines)
147 || !are_includes_equal(
148 context.include_handler.get_includes(),
149 self.include_handler.get_includes(),
150 )
151 || context.dirty_files.contains(file_path)
152 }
153 pub fn get_define_value(&self, name: &str) -> Option<String> {
154 self.defines
155 .iter()
156 .find(|symbol| *symbol.label == *name)
157 .map(|symbol| match &symbol.data {
158 ShaderSymbolData::Macro { value } => value.clone(),
159 _ => panic!("Expected ShaderSymbolData::Macro"),
160 })
161 }
162 pub fn get_defines(&self) -> &Vec<ShaderSymbol> {
163 &self.defines
164 }
165}
166
167#[derive(Debug, Clone)]
168pub struct ShaderPreprocessorInclude {
169 pub cache: Option<ShaderSymbols>,
171 symbol: ShaderSymbol,
172}
173
174#[derive(Debug, Clone)]
175pub struct ShaderPreprocessorDefine {
176 symbol: ShaderSymbol,
177}
178
179#[derive(Debug, Default, Clone, PartialEq, Eq)]
180pub enum ShaderPreprocessorMode {
181 #[default]
182 Default,
183 Once,
184 OnceVisited,
185}
186
187#[derive(Debug, Default, Clone)]
188pub struct ShaderPreprocessor {
189 pub context: ShaderPreprocessorContext, pub includes: Vec<ShaderPreprocessorInclude>,
192 pub defines: Vec<ShaderPreprocessorDefine>,
193 pub regions: Vec<ShaderRegion>,
194 pub diagnostics: Vec<ShaderDiagnostic>, pub mode: ShaderPreprocessorMode,
196}
197impl ShaderPreprocessorDefine {
198 pub fn new(name: String, range: ShaderFileRange, value: Option<String>) -> Self {
199 Self {
200 symbol: ShaderSymbol {
201 label: name.clone(),
202 requirement: None,
203 data: ShaderSymbolData::Macro {
204 value: match &value {
205 Some(value) => value.clone(),
206 None => "".into(),
207 },
208 },
209 mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::global(
210 range.file_path,
211 range.range,
212 )),
213 },
214 }
215 }
216 pub fn get_file_path(&self) -> &Path {
217 &self.symbol.mode.unwrap_runtime().file_path
218 }
219 pub fn get_range(&self) -> &ShaderRange {
220 &self.symbol.mode.unwrap_runtime().range
221 }
222 pub fn get_name(&self) -> &String {
223 &self.symbol.label
224 }
225 pub fn get_value(&self) -> Option<&String> {
226 match &self.symbol.data {
227 ShaderSymbolData::Macro { value } => Some(value),
228 _ => None,
229 }
230 }
231}
232impl ShaderPreprocessorInclude {
233 pub fn new(relative_path: String, absolute_path: PathBuf, range: ShaderFileRange) -> Self {
234 Self {
235 cache: None,
236 symbol: ShaderSymbol {
237 label: relative_path,
238 requirement: None,
239 data: ShaderSymbolData::Include {
240 target: absolute_path,
241 },
242 mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::global(
243 range.file_path,
244 range.range,
245 )),
246 },
247 }
248 }
249 pub fn get_range(&self) -> &ShaderRange {
250 &self.symbol.mode.unwrap_runtime().range
251 }
252 pub fn get_file_range(&self) -> ShaderFileRange {
253 let runtime = self.symbol.mode.unwrap_runtime();
254 runtime.range.clone_into_file(runtime.file_path.clone())
255 }
256 pub fn get_relative_path(&self) -> &String {
257 &self.symbol.label
258 }
259 pub fn get_absolute_path(&self) -> &Path {
260 match &self.symbol.data {
261 ShaderSymbolData::Include { target } => &target,
262 _ => panic!("Expected ShaderSymbolData::Link"),
263 }
264 }
265 pub fn get_cache(&self) -> &ShaderSymbols {
266 self.cache.as_ref().unwrap()
267 }
268 pub fn get_cache_mut(&mut self) -> &mut ShaderSymbols {
269 self.cache.as_mut().unwrap()
270 }
271}
272
273impl ShaderPreprocessor {
274 pub fn new(context: ShaderPreprocessorContext) -> Self {
275 Self {
276 context: context,
277 includes: Vec::new(),
278 defines: Vec::new(),
279 regions: Vec::new(),
280 diagnostics: Vec::new(),
281 mode: ShaderPreprocessorMode::default(),
282 }
283 }
284 pub fn preprocess_symbols<'a>(
285 &'a self,
286 shader_symbols: &'a ShaderSymbolList,
287 ) -> ShaderSymbolListRef<'a> {
288 let inactive_regions: Vec<&ShaderRegion> =
290 self.regions.iter().filter(|r| !r.is_active).collect();
291 let mut preprocessed_symbols =
292 shader_symbols.filter(move |_symbol_type, symbol| match &symbol.mode {
293 ShaderSymbolMode::Runtime(runtime) => inactive_regions
294 .iter()
295 .find(|r| r.range.contain_bounds(&runtime.range))
296 .is_none(),
297 ShaderSymbolMode::RuntimeContext(_) => true, ShaderSymbolMode::Intrinsic(_) => true, });
300 let mut define_symbols: Vec<&ShaderSymbol> =
302 self.defines.iter().map(|define| &define.symbol).collect();
303 let mut include_symbols: Vec<&ShaderSymbol> = self
305 .includes
306 .iter()
307 .map(|include| &include.symbol)
308 .collect();
309 preprocessed_symbols.macros.append(&mut define_symbols);
310 preprocessed_symbols.includes.append(&mut include_symbols);
311 preprocessed_symbols
312 }
313}