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