diff options
| author | HampusM <hampus@hampusmat.com> | 2026-07-19 16:30:58 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-07-19 16:30:58 +0200 |
| commit | 65bce20d43670d23f433ac11f49f10d2011474b6 (patch) | |
| tree | 5a1ccf1f32c41b8a69874777e8af951c3150bba0 /engine/src/rendering/shader/cursor.rs | |
| parent | 6a608c1791d39857b9894462643dc925dbd39067 (diff) | |
feat(engine): add location path to shader binding validation error
Diffstat (limited to 'engine/src/rendering/shader/cursor.rs')
| -rw-r--r-- | engine/src/rendering/shader/cursor.rs | 103 |
1 files changed, 90 insertions, 13 deletions
diff --git a/engine/src/rendering/shader/cursor.rs b/engine/src/rendering/shader/cursor.rs index 32dee00..ba8bed7 100644 --- a/engine/src/rendering/shader/cursor.rs +++ b/engine/src/rendering/shader/cursor.rs @@ -1,5 +1,9 @@ +use std::borrow::Cow; +use std::fmt::Display; use std::hint::cold_path; +use circular_buffer::FixedCircularBuffer; + use crate::color::Color; use crate::data_types::matrix::Matrix; use crate::data_types::vector::Vec3; @@ -18,6 +22,7 @@ pub struct Cursor<'a> { type_layout: TypeLayout<'a>, binding_location: BindingLocation, + location_path: LocationPath, } impl<'a> Cursor<'a> @@ -33,12 +38,16 @@ impl<'a> Cursor<'a> Self { type_layout: var_layout.type_layout().unwrap(), binding_location, + location_path: LocationPath::default(), } } - pub fn field(&self, name: &str) -> Self + pub fn field(&self, name: impl Into<Cow<'static, str>>) -> Self { - let Some(field_var_layout) = self.type_layout.get_field_by_name(name) else { + let name = name.into(); + + let Some(field_var_layout) = self.type_layout.get_field_by_name(name.as_ref()) + else { panic!("Field '{name}' does not exist"); }; @@ -59,6 +68,10 @@ impl<'a> Cursor<'a> type_kind => unimplemented!("Type kind {type_kind:?} is not yet supported"), }; + let mut location_path = self.location_path.clone(); + + location_path.push(Location::Field(name)); + Self { type_layout: field_var_layout.type_layout().unwrap(), binding_location: BindingLocation { @@ -76,6 +89,7 @@ impl<'a> Cursor<'a> byte_offset: self.binding_location.byte_offset + field_var_layout.offset(), }, + location_path, } } @@ -87,19 +101,14 @@ impl<'a> Cursor<'a> self.type_layout = element_type_layout; - self - } - - pub fn with_field(self, name: &str, func: impl FnOnce(Self) -> Self) -> Self - { - let _ = func(self.field(name)); + self.location_path.push(Location::Element(index)); self } pub fn binding(self, value: BindingValue) -> Result<Binding, BindingError> { - value.validate_for_shader_type(self.type_layout)?; + value.validate_for_shader_type(self.type_layout, self.location_path)?; Ok(Binding { location: self.binding_location, @@ -113,6 +122,66 @@ impl<'a> Cursor<'a> } } +/// Shader cursor location. +#[derive(Debug, Clone, Default)] +pub struct LocationPath +{ + locations: FixedCircularBuffer<Location, 16>, + is_truncated: bool, +} + +impl LocationPath +{ + fn push(&mut self, location: Location) + { + if self.locations.push_back(location).is_some() { + self.is_truncated = true; + } + } +} + +impl Display for LocationPath +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + if self.is_truncated { + write!(formatter, "(...)")?; + } + + for location in &self.locations { + match location { + Location::Field(field) => { + write!(formatter, ".{field}")?; + } + Location::Element(element) => { + write!(formatter, "[{element}]")?; + } + } + } + + Ok(()) + } +} + +/// Shader cursor location. +#[derive(Debug, Clone)] +pub enum Location +{ + Field(Cow<'static, str>), + Element(usize), +} + +impl Display for Location +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + match self { + Self::Field(field) => <Cow<'static, str> as Display>::fmt(field, formatter), + Self::Element(element) => <usize as Display>::fmt(element, formatter), + } + } +} + #[derive(Debug, Clone)] pub struct BindingLocation { @@ -135,7 +204,11 @@ pub enum BindingValue impl BindingValue { - fn validate_for_shader_type(&self, ty: TypeLayout<'_>) -> Result<(), BindingError> + fn validate_for_shader_type( + &self, + ty: TypeLayout<'_>, + location_path: LocationPath, + ) -> Result<(), BindingError> { match ( self, @@ -205,7 +278,10 @@ impl BindingValue } _ => { cold_path(); - Err(BindingError::IncorrectValueType { value: self.clone() }) + Err(BindingError::IncorrectValueType { + value: self.clone(), + location_path, + }) } } } @@ -271,9 +347,10 @@ pub struct Binding #[non_exhaustive] pub enum BindingError { - #[error("Value {value:?} has incorrect type for shader binding location")] + #[error("Value {value:?} has incorrect type for value at {location_path} in shader")] IncorrectValueType { - value: BindingValue + value: BindingValue, + location_path: LocationPath, }, } |
