naga/valid/
compose.rs

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