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 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 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 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 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}