mirage_engine/mesh/
set.rs1use core::hash::Hash;
4
5use crate::Catalog;
6use crate::assets::Assets;
7use crate::holds::Sealed;
8use crate::mesh::Built;
9
10pub trait Meshes: Sealed + Catalog + Hash + Eq + Clone + 'static {
17 #[doc(hidden)]
20 fn build(&self, assets: &Assets) -> Built;
21}
22
23#[derive(Clone, Debug, Eq, Hash, PartialEq)]
36pub enum NoMeshes {}
37
38impl Sealed for NoMeshes {}
39
40impl Catalog for NoMeshes {
41 fn catalog() -> Vec<Self> {
42 Vec::new()
43 }
44}
45
46impl Meshes for NoMeshes {
47 fn build(&self, _assets: &Assets) -> Built {
48 match *self {}
49 }
50}
51
52#[macro_export]
70macro_rules! meshes {
71 ($(#[$attribute:meta])* $vis:vis enum $set:ident { $($mesh:ident),+ $(,)? }) => {
72 $(#[$attribute])*
73 #[derive(Clone, Eq, Hash, PartialEq)]
74 $vis enum $set {
75 $($mesh($mesh)),+
76 }
77
78 $(
79 impl ::core::convert::From<$mesh> for $set {
80 fn from(mesh: $mesh) -> Self {
81 Self::$mesh(mesh)
82 }
83 }
84
85 impl $crate::Holds<$mesh> for $set {}
86 )+
87
88 impl $crate::Holds<$set> for $set {}
89
90 impl $crate::Sealed for $set {}
91
92 impl $crate::Catalog for $set {
93 fn catalog() -> ::std::vec::Vec<Self> {
94 let mut all = ::std::vec::Vec::new();
95 $(all.extend(<$mesh as $crate::Catalog>::catalog().into_iter().map(Self::$mesh));)+
96 all
97 }
98 }
99
100 impl $crate::Meshes for $set {
101 fn build(&self, assets: &$crate::Assets) -> $crate::mesh::Built {
102 match self {
103 $(
104 Self::$mesh(mesh) => $crate::Mesh::build(mesh, assets)
105 .erased(::core::stringify!($mesh))
106 ),+
107 }
108 }
109 }
110 };
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::mesh::{Cube, Mesh, MeshData, Sphere};
117
118 meshes! {
119 #[derive(Debug)]
120 enum Shape { Cube, Sphere }
121 }
122
123 meshes! {
124 enum Shapes { Wedge }
125 }
126
127 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
130 struct Wedge;
131
132 impl Catalog for Wedge {
133 fn catalog() -> Vec<Self> {
134 vec![Self]
135 }
136 }
137
138 impl Mesh for Wedge {
139 fn build(&self, _assets: &Assets) -> MeshData {
140 MeshData::new(Vec::new(), vec![0])
141 }
142 }
143
144 #[test]
145 fn a_set_catalogs_every_value_of_every_type_it_names() {
146 let catalog = Shape::catalog();
147
148 assert_eq!(catalog.len(), 1 + Sphere::catalog().len());
149 assert_eq!(catalog[0], Shape::Cube(Cube));
150 assert!(matches!(catalog[1], Shape::Sphere(_)));
151 }
152
153 #[test]
154 fn a_set_value_builds_the_mesh_it_wraps_under_its_types_name() {
155 let assets = Assets::default();
156 let cube = Shape::from(Cube).build(&assets);
157
158 assert_eq!(cube.geometry.part_count(), 1);
159 assert!(
160 cube.unresolved.is_empty(),
161 "nothing is wrong with a cube: {:?}",
162 cube.unresolved
163 );
164
165 let wedge = Shapes::from(Wedge).build(&assets);
166 assert_eq!(
167 wedge
168 .unresolved
169 .error()
170 .expect("the index reaches past the corners")
171 .to_string(),
172 "the game's assets did not resolve: the mesh `Wedge` has the index 0 past its 0 \
173 vertices",
174 "and a value of the set names its own type in what it did not get"
175 );
176 }
177
178 #[test]
179 fn the_set_of_no_meshes_catalogs_nothing() {
180 assert!(NoMeshes::catalog().is_empty());
181 }
182}