naga/valid/
compose.rs

1#[cfg(feature = "validate")]
2use crate::proc::TypeResolution;
3
4use crate::arena::Handle;
5
6#[derive(Clone, Debug, thiserror::Error)]
7#[cfg_attr(test, derive(PartialEq))]
8pub enum ComposeError {
9    #[error("Composing of type {0:?} can't be done")]
10    Type(Handle<crate::Type>),
11    #[error("Composing expects {expected} components but {given} were given")]
12    ComponentCount { given: u32, expected: u32 },
13    #[error("Composing {index}'s component type is not expected")]
14    ComponentType { index: u32 },
15}
16
17#[cfg(feature = "validate")]
18pub fn validate_compose(
19    self_ty_handle: Handle<crate::Type>,
20    gctx: crate::proc::GlobalCtx,
21    component_resolutions: impl ExactSizeIterator<Item = TypeResolution>,
22) -> Result<(), ComposeError> {
23    use crate::TypeInner as Ti;
24
25    match gctx.types[self_ty_handle].inner {
26        // vectors are composed from scalars or other vectors
27        Ti::Vector { size, kind, width } => {
28            let mut total = 0;
29            for (index, comp_res) in component_resolutions.enumerate() {
30                total += match *comp_res.inner_with(gctx.types) {
31                    Ti::Scalar {
32                        kind: comp_kind,
33                        width: comp_width,
34                    } if comp_kind == kind && comp_width == width => 1,
35                    Ti::Vector {
36                        size: comp_size,
37                        kind: comp_kind,
38                        width: comp_width,
39                    } if comp_kind == kind && comp_width == width => comp_size as u32,
40                    ref other => {
41                        log::error!("Vector component[{}] type {:?}", index, other);
42                        return Err(ComposeError::ComponentType {
43                            index: index as u32,
44                        });
45                    }
46                };
47            }
48            if size as u32 != total {
49                return Err(ComposeError::ComponentCount {
50                    expected: size as u32,
51                    given: total,
52                });
53            }
54        }
55        // matrix are composed from column vectors
56        Ti::Matrix {
57            columns,
58            rows,
59            width,
60        } => {
61            let inner = Ti::Vector {
62                size: rows,
63                kind: crate::ScalarKind::Float,
64                width,
65            };
66            if columns as usize != component_resolutions.len() {
67                return Err(ComposeError::ComponentCount {
68                    expected: columns as u32,
69                    given: component_resolutions.len() as u32,
70                });
71            }
72            for (index, comp_res) in component_resolutions.enumerate() {
73                if comp_res.inner_with(gctx.types) != &inner {
74                    log::error!("Matrix component[{}] type {:?}", index, comp_res);
75                    return Err(ComposeError::ComponentType {
76                        index: index as u32,
77                    });
78                }
79            }
80        }
81        Ti::Array {
82            base,
83            size: crate::ArraySize::Constant(count),
84            stride: _,
85        } => {
86            if count.get() as usize != component_resolutions.len() {
87                return Err(ComposeError::ComponentCount {
88                    expected: count.get(),
89                    given: component_resolutions.len() as u32,
90                });
91            }
92            for (index, comp_res) in component_resolutions.enumerate() {
93                let base_inner = &gctx.types[base].inner;
94                let comp_res_inner = comp_res.inner_with(gctx.types);
95                // We don't support arrays of pointers, but it seems best not to
96                // embed that assumption here, so use `TypeInner::equivalent`.
97                if !base_inner.equivalent(comp_res_inner, gctx.types) {
98                    log::error!("Array component[{}] type {:?}", index, comp_res);
99                    return Err(ComposeError::ComponentType {
100                        index: index as u32,
101                    });
102                }
103            }
104        }
105        Ti::Struct { ref members, .. } => {
106            if members.len() != component_resolutions.len() {
107                return Err(ComposeError::ComponentCount {
108                    given: component_resolutions.len() as u32,
109                    expected: members.len() as u32,
110                });
111            }
112            for (index, (member, comp_res)) in members.iter().zip(component_resolutions).enumerate()
113            {
114                let member_inner = &gctx.types[member.ty].inner;
115                let comp_res_inner = comp_res.inner_with(gctx.types);
116                // We don't support pointers in structs, but it seems best not to embed
117                // that assumption here, so use `TypeInner::equivalent`.
118                if !comp_res_inner.equivalent(member_inner, gctx.types) {
119                    log::error!("Struct component[{}] type {:?}", index, comp_res);
120                    return Err(ComposeError::ComponentType {
121                        index: index as u32,
122                    });
123                }
124            }
125        }
126        ref other => {
127            log::error!("Composing of {:?}", other);
128            return Err(ComposeError::Type(self_ty_handle));
129        }
130    }
131
132    Ok(())
133}