summaryrefslogtreecommitdiffstats
path: root/third_party/rust/naga/src/valid/compose.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/naga/src/valid/compose.rs')
-rw-r--r--third_party/rust/naga/src/valid/compose.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/third_party/rust/naga/src/valid/compose.rs b/third_party/rust/naga/src/valid/compose.rs
new file mode 100644
index 0000000000..e77d538255
--- /dev/null
+++ b/third_party/rust/naga/src/valid/compose.rs
@@ -0,0 +1,138 @@
+#[cfg(feature = "validate")]
+use crate::{
+ arena::{Arena, UniqueArena},
+ proc::TypeResolution,
+};
+
+use crate::arena::Handle;
+
+#[derive(Clone, Debug, thiserror::Error)]
+#[cfg_attr(test, derive(PartialEq))]
+pub enum ComposeError {
+ #[error("Composing of type {0:?} can't be done")]
+ Type(Handle<crate::Type>),
+ #[error("Composing expects {expected} components but {given} were given")]
+ ComponentCount { given: u32, expected: u32 },
+ #[error("Composing {index}'s component type is not expected")]
+ ComponentType { index: u32 },
+}
+
+#[cfg(feature = "validate")]
+pub fn validate_compose(
+ self_ty_handle: Handle<crate::Type>,
+ constant_arena: &Arena<crate::Constant>,
+ type_arena: &UniqueArena<crate::Type>,
+ component_resolutions: impl ExactSizeIterator<Item = TypeResolution>,
+) -> Result<(), ComposeError> {
+ use crate::TypeInner as Ti;
+
+ match type_arena[self_ty_handle].inner {
+ // vectors are composed from scalars or other vectors
+ Ti::Vector { size, kind, width } => {
+ let mut total = 0;
+ for (index, comp_res) in component_resolutions.enumerate() {
+ total += match *comp_res.inner_with(type_arena) {
+ Ti::Scalar {
+ kind: comp_kind,
+ width: comp_width,
+ } if comp_kind == kind && comp_width == width => 1,
+ Ti::Vector {
+ size: comp_size,
+ kind: comp_kind,
+ width: comp_width,
+ } if comp_kind == kind && comp_width == width => comp_size as u32,
+ ref other => {
+ log::error!("Vector component[{}] type {:?}", index, other);
+ return Err(ComposeError::ComponentType {
+ index: index as u32,
+ });
+ }
+ };
+ }
+ if size as u32 != total {
+ return Err(ComposeError::ComponentCount {
+ expected: size as u32,
+ given: total,
+ });
+ }
+ }
+ // matrix are composed from column vectors
+ Ti::Matrix {
+ columns,
+ rows,
+ width,
+ } => {
+ let inner = Ti::Vector {
+ size: rows,
+ kind: crate::ScalarKind::Float,
+ width,
+ };
+ if columns as usize != component_resolutions.len() {
+ return Err(ComposeError::ComponentCount {
+ expected: columns as u32,
+ given: component_resolutions.len() as u32,
+ });
+ }
+ for (index, comp_res) in component_resolutions.enumerate() {
+ if comp_res.inner_with(type_arena) != &inner {
+ log::error!("Matrix component[{}] type {:?}", index, comp_res);
+ return Err(ComposeError::ComponentType {
+ index: index as u32,
+ });
+ }
+ }
+ }
+ Ti::Array {
+ base,
+ size: crate::ArraySize::Constant(handle),
+ stride: _,
+ } => {
+ let count = constant_arena[handle].to_array_length().unwrap();
+ if count as usize != component_resolutions.len() {
+ return Err(ComposeError::ComponentCount {
+ expected: count,
+ given: component_resolutions.len() as u32,
+ });
+ }
+ for (index, comp_res) in component_resolutions.enumerate() {
+ let base_inner = &type_arena[base].inner;
+ let comp_res_inner = comp_res.inner_with(type_arena);
+ // We don't support arrays of pointers, but it seems best not to
+ // embed that assumption here, so use `TypeInner::equivalent`.
+ if !base_inner.equivalent(comp_res_inner, type_arena) {
+ log::error!("Array component[{}] type {:?}", index, comp_res);
+ return Err(ComposeError::ComponentType {
+ index: index as u32,
+ });
+ }
+ }
+ }
+ Ti::Struct { ref members, .. } => {
+ if members.len() != component_resolutions.len() {
+ return Err(ComposeError::ComponentCount {
+ given: component_resolutions.len() as u32,
+ expected: members.len() as u32,
+ });
+ }
+ for (index, (member, comp_res)) in members.iter().zip(component_resolutions).enumerate()
+ {
+ let member_inner = &type_arena[member.ty].inner;
+ let comp_res_inner = comp_res.inner_with(type_arena);
+ // We don't support pointers in structs, but it seems best not to embed
+ // that assumption here, so use `TypeInner::equivalent`.
+ if !comp_res_inner.equivalent(member_inner, type_arena) {
+ log::error!("Struct component[{}] type {:?}", index, comp_res);
+ return Err(ComposeError::ComponentType {
+ index: index as u32,
+ });
+ }
+ }
+ }
+ ref other => {
+ log::error!("Composing of {:?}", other);
+ return Err(ComposeError::Type(self_ty_handle));
+ }
+ }
+
+ Ok(())
+}