naga/valid/
compose.rs

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