CoalescedError type
diff --git a/vello/src/lib.rs b/vello/src/lib.rs index 6bcda87..7772a8e 100644 --- a/vello/src/lib.rs +++ b/vello/src/lib.rs
@@ -221,8 +221,8 @@ /// Failed to compile the shaders. #[cfg(feature = "hot_reload")] - #[error("Failed to compile shader: {0}")] - ShaderCompilation(#[from] vello_shaders::compile::Error), + #[error("Failed to compile shaders:\n{0}")] + ShaderCompilation(#[from] vello_shaders::compile::ErrorVec), } #[allow(dead_code)] // this can be unused when wgpu feature is not used
diff --git a/vello_shaders/src/compile/mod.rs b/vello_shaders/src/compile/mod.rs index ef7d9b6..ca19406 100644 --- a/vello_shaders/src/compile/mod.rs +++ b/vello_shaders/src/compile/mod.rs
@@ -5,6 +5,7 @@ use naga::valid::{Capabilities, ModuleInfo, ValidationError, ValidationFlags}; use naga::{AddressSpace, ArraySize, ImageClass, Module, StorageAccess, WithSpan}; use std::collections::{HashMap, HashSet}; +use std::fmt; use std::path::{Path, PathBuf}; use std::sync::OnceLock; use thiserror::Error; @@ -18,6 +19,10 @@ use crate::types::{BindType, BindingInfo, WorkgroupBufferInfo}; pub type Result<T> = std::result::Result<T, Error>; +pub type CoalescedResult<T> = std::result::Result<T, ErrorVec>; + +#[derive(Error, Debug)] +pub struct ErrorVec(Vec<Error>); #[derive(Error, Debug)] #[error("{source} ({name}) {msg}")] @@ -28,7 +33,7 @@ } #[derive(Error, Debug)] -pub enum InnerError { +enum InnerError { #[error("failed to parse shader")] Parse(#[from] wgsl::ParseError), @@ -39,6 +44,15 @@ EntryPointNotFound, } +impl fmt::Display for ErrorVec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for e in self.0.iter() { + write!(f, "{e}")?; + } + Ok(()) + } +} + impl Error { fn new(wgsl: &str, name: &str, error: impl Into<InnerError>) -> Error { let source = error.into(); @@ -163,11 +177,11 @@ } /// Same as [`ShaderInfo::from_dir`] but uses the default shader directory provided by [`shader_dir`]. - pub fn from_default() -> Result<HashMap<String, Self>> { + pub fn from_default() -> CoalescedResult<HashMap<String, Self>> { ShaderInfo::from_dir(shader_dir()) } - pub fn from_dir(shader_dir: impl AsRef<Path>) -> Result<HashMap<String, Self>> { + pub fn from_dir(shader_dir: impl AsRef<Path>) -> CoalescedResult<HashMap<String, Self>> { use std::fs; let shader_dir = shader_dir.as_ref(); let permutation_map = if let Ok(permutations_source) = @@ -179,6 +193,7 @@ }; //println!("{permutation_map:?}"); let imports = preprocess::get_imports(shader_dir); + let mut errors = vec![]; let mut info = HashMap::default(); let defines: HashSet<_> = if cfg!(feature = "full") { vec!["full".to_string()] @@ -206,18 +221,34 @@ let mut defines = defines.clone(); defines.extend(permutation.defines.iter().cloned()); let source = preprocess::preprocess(&contents, &defines, &imports); - let shader_info = Self::new(&permutation.name, source.clone(), "main")?; - info.insert(permutation.name.clone(), shader_info); + match Self::new(&permutation.name, source, "main") { + Ok(shader_info) => { + info.insert(permutation.name.clone(), shader_info); + } + Err(e) => { + errors.push(e); + } + } } } else { let source = preprocess::preprocess(&contents, &defines, &imports); - let shader_info = Self::new(&shader_name, source.clone(), "main")?; - info.insert(shader_name.to_string(), shader_info); + match Self::new(&shader_name, source, "main") { + Ok(shader_info) => { + info.insert(shader_name.to_string(), shader_info); + } + Err(e) => { + errors.push(e); + } + } } } } } - Ok(info) + if !errors.is_empty() { + Err(ErrorVec(errors)) + } else { + Ok(info) + } } }