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[{index}] type {other:?}, building {scalar:?}"
36                        );
37                        return Err(ComposeError::ComponentType {
38                            index: index as u32,
39                        });
40                    }
41                };
42            }
43            if size as u32 != total {
44                return Err(ComposeError::ComponentCount {
45                    expected: size as u32,
46                    given: total,
47                });
48            }
49        }
50        // matrix are composed from column vectors
51        Ti::Matrix {
52            columns,
53            rows,
54            scalar,
55        } => {
56            let inner = Ti::Vector { size: rows, scalar };
57            if columns as usize != component_resolutions.len() {
58                return Err(ComposeError::ComponentCount {
59                    expected: columns as u32,
60                    given: component_resolutions.len() as u32,
61                });
62            }
63            for (index, comp_res) in component_resolutions.enumerate() {
64                if comp_res.inner_with(gctx.types) != &inner {
65                    log::error!("Matrix component[{index}] type {comp_res:?}");
66                    return Err(ComposeError::ComponentType {
67                        index: index as u32,
68                    });
69                }
70            }
71        }
72        Ti::Array {
73            base,
74            size: crate::ArraySize::Constant(count),
75            stride: _,
76        } => {
77            if count.get() as usize != component_resolutions.len() {
78                return Err(ComposeError::ComponentCount {
79                    expected: count.get(),
80                    given: component_resolutions.len() as u32,
81                });
82            }
83            for (index, comp_res) in component_resolutions.enumerate() {
84                if !gctx.compare_types(&TypeResolution::Handle(base), &comp_res) {
85                    log::error!("Array component[{index}] type {comp_res:?}");
86                    return Err(ComposeError::ComponentType {
87                        index: index as u32,
88                    });
89                }
90            }
91        }
92        Ti::Struct { ref members, .. } => {
93            if members.len() != component_resolutions.len() {
94                return Err(ComposeError::ComponentCount {
95                    given: component_resolutions.len() as u32,
96                    expected: members.len() as u32,
97                });
98            }
99            for (index, (member, comp_res)) in members.iter().zip(component_resolutions).enumerate()
100            {
101                if !gctx.compare_types(&TypeResolution::Handle(member.ty), &comp_res) {
102                    log::error!("Struct component[{index}] type {comp_res:?}");
103                    return Err(ComposeError::ComponentType {
104                        index: index as u32,
105                    });
106                }
107            }
108        }
109        ref other => {
110            log::error!("Composing of {other:?}");
111            return Err(ComposeError::Type(self_ty_handle));
112        }
113    }
114
115    Ok(())
116}