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