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