Skip to main content

scena/diagnostics/
display.rs

1use std::error;
2use std::fmt;
3
4use super::{
5    AnimationError, AssetError, BuildError, Error, ImportError, InstantiateError, LookupError,
6    NotPreparedReason, PrepareError, RenderError,
7};
8
9impl fmt::Display for Error {
10    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
11        match self {
12            Self::Build(error) => error.fmt(formatter),
13            Self::Asset(error) => error.fmt(formatter),
14            Self::Import(error) => error.fmt(formatter),
15            Self::Instantiate(error) => error.fmt(formatter),
16            Self::Prepare(error) => error.fmt(formatter),
17            Self::Render(error) => error.fmt(formatter),
18            Self::Lookup(error) => error.fmt(formatter),
19            Self::Animation(error) => error.fmt(formatter),
20        }
21    }
22}
23
24impl fmt::Display for BuildError {
25    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Self::InvalidTargetSize { width, height } => {
28                write!(formatter, "invalid render target size {width}x{height}")
29            }
30            Self::AsyncSurfaceRequired { backend } => {
31                write!(
32                    formatter,
33                    "attached surface initialization for {backend:?} requires async construction"
34                )
35            }
36            Self::CreateSurface { backend } => {
37                write!(formatter, "failed to create GPU surface for {backend:?}")
38            }
39            Self::NoAdapter { backend } => {
40                write!(formatter, "no compatible GPU adapter found for {backend:?}")
41            }
42            Self::RequestDevice { backend } => {
43                write!(formatter, "failed to request GPU device for {backend:?}")
44            }
45            Self::SurfaceUnsupported { backend } => {
46                write!(
47                    formatter,
48                    "no compatible surface configuration found for {backend:?}"
49                )
50            }
51            Self::UnsupportedBackend { backend } => {
52                write!(
53                    formatter,
54                    "backend {backend:?} is not supported on this target"
55                )
56            }
57        }
58    }
59}
60
61impl fmt::Display for AssetError {
62    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Self::NotFound { path } => write!(formatter, "asset was not found: {path}"),
65            Self::Io { path, reason } => {
66                write!(formatter, "failed to read asset {path}: {reason}")
67            }
68            Self::Parse { path, reason } => {
69                write!(formatter, "failed to parse asset {path}: {reason}")
70            }
71            Self::UnsupportedRequiredExtension { path, extension } => write!(
72                formatter,
73                "asset {path} requires unsupported extension {extension}"
74            ),
75            Self::UnsupportedOptionalExtensionUsed {
76                path,
77                extension,
78                help,
79            } => write!(
80                formatter,
81                "asset {path} uses unsupported optional extension {extension}: {help}"
82            ),
83            Self::MissingTexture {
84                path,
85                material_slot,
86                texture_index,
87                help,
88            } => write!(
89                formatter,
90                "asset {path} references missing texture index {texture_index} in material slot {material_slot}: {help}"
91            ),
92            Self::UnsupportedTextureFormat { path, help } => {
93                write!(
94                    formatter,
95                    "texture {path} uses an unsupported format: {help}"
96                )
97            }
98            Self::Cancelled { path, help } => {
99                write!(formatter, "asset load for {path} was cancelled: {help}")
100            }
101            Self::UnsupportedEnvironmentFormat { path, help } => {
102                write!(
103                    formatter,
104                    "environment {path} uses an unsupported format: {help}"
105                )
106            }
107            Self::ReloadRequiresRetain { path, help } => {
108                write!(formatter, "asset {path} cannot be reloaded: {help}")
109            }
110            Self::GeometryHandleNotFound { geometry } => {
111                write!(
112                    formatter,
113                    "geometry handle {geometry:?} was not found in Assets"
114                )
115            }
116            Self::MaterialHandleNotFound { material } => {
117                write!(
118                    formatter,
119                    "material handle {material:?} was not found in Assets"
120                )
121            }
122            Self::TextureHandleNotFound { texture } => {
123                write!(
124                    formatter,
125                    "texture handle {texture:?} was not found in Assets"
126                )
127            }
128            Self::EnvironmentHandleNotFound { environment } => {
129                write!(
130                    formatter,
131                    "environment handle {environment:?} was not found in Assets"
132                )
133            }
134        }
135    }
136}
137
138impl fmt::Display for ImportError {
139    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
140        match self {
141            Self::Asset(error) => error.fmt(formatter),
142            Self::Instantiate(error) => error.fmt(formatter),
143        }
144    }
145}
146
147impl From<AssetError> for ImportError {
148    fn from(error: AssetError) -> Self {
149        Self::Asset(error)
150    }
151}
152
153impl From<InstantiateError> for ImportError {
154    fn from(error: InstantiateError) -> Self {
155        Self::Instantiate(error)
156    }
157}
158
159impl fmt::Display for InstantiateError {
160    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
161        match self {
162            Self::InvalidChildIndex { parent, child } => write!(
163                formatter,
164                "glTF node {parent} references invalid child node index {child}"
165            ),
166            Self::InvalidSkinIndex { node, skin } => {
167                write!(
168                    formatter,
169                    "glTF node {node} references invalid skin index {skin}"
170                )
171            }
172            Self::InvalidSkinJointIndex { skin, joint } => write!(
173                formatter,
174                "glTF skin {skin} references invalid joint node index {joint}"
175            ),
176            Self::InvalidAnchorExtras { node, reason } => {
177                write!(
178                    formatter,
179                    "glTF node {node} has invalid anchor extras: {reason}"
180                )
181            }
182            Self::UnsupportedCoordinateSystem {
183                coordinate_system,
184                reason,
185            } => write!(
186                formatter,
187                "source coordinate system {coordinate_system:?} is not supported for this import: {reason}"
188            ),
189        }
190    }
191}
192
193impl fmt::Display for PrepareError {
194    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
195        match self {
196            Self::InvalidTargetSize { width, height } => {
197                write!(formatter, "invalid render target size {width}x{height}")
198            }
199            Self::AssetsRequired { node } => {
200                write!(
201                    formatter,
202                    "node {node:?} references asset handles; call prepare_with_assets"
203                )
204            }
205            Self::GeometryNotFound { node, geometry } => {
206                write!(
207                    formatter,
208                    "node {node:?} references missing geometry handle {geometry:?}"
209                )
210            }
211            Self::MaterialNotFound { node, material } => {
212                write!(
213                    formatter,
214                    "node {node:?} references missing material handle {material:?}"
215                )
216            }
217            Self::TextureNotFound {
218                node,
219                material,
220                texture,
221                slot,
222            } => {
223                write!(
224                    formatter,
225                    "node {node:?} material {material:?} references missing texture handle {texture:?} in slot {slot}"
226                )
227            }
228            Self::EnvironmentAssetsRequired { environment } => {
229                write!(
230                    formatter,
231                    "environment handle {environment:?} requires prepare_with_assets"
232                )
233            }
234            Self::EnvironmentNotFound { environment } => {
235                write!(
236                    formatter,
237                    "active environment handle {environment:?} was not found in assets"
238                )
239            }
240            Self::UnsupportedGeometryTopology { node, topology } => {
241                write!(
242                    formatter,
243                    "node {node:?} uses unsupported geometry topology {topology:?}"
244                )
245            }
246            Self::UnsupportedMaterialKind { node, kind } => {
247                write!(
248                    formatter,
249                    "node {node:?} uses unsupported material kind {kind:?}"
250                )
251            }
252            Self::UnsupportedAlphaMode { node, alpha_mode } => {
253                write!(
254                    formatter,
255                    "node {node:?} uses unsupported alpha mode {alpha_mode:?}"
256                )
257            }
258            Self::UnsupportedModelNode { node } => {
259                write!(
260                    formatter,
261                    "node {node:?} is a model node; model preparation is not implemented"
262                )
263            }
264            Self::MultipleShadowedDirectionalLights { first, second } => write!(
265                formatter,
266                "only one shadowed directional light is supported; nodes {first:?} and {second:?} both cast shadows"
267            ),
268            Self::InvalidSkinGeometry { node, reason } => {
269                write!(
270                    formatter,
271                    "node {node:?} has invalid skin geometry: {reason}"
272                )
273            }
274            Self::BackendCapabilityMismatch {
275                feature,
276                backend,
277                help,
278            } => {
279                write!(
280                    formatter,
281                    "backend {backend:?} cannot provide required feature {feature}: {help}"
282                )
283            }
284            Self::GpuResourceUpload { backend, reason } => {
285                write!(
286                    formatter,
287                    "backend {backend:?} failed during explicit GPU resource upload: {reason}"
288                )
289            }
290        }
291    }
292}
293
294impl fmt::Display for RenderError {
295    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
296        match self {
297            Self::NotPrepared { reason } => write!(formatter, "renderer is not prepared: {reason}"),
298            Self::NoActiveCamera => write!(formatter, "scene has no active camera"),
299            Self::CameraNotFound(_) => write!(formatter, "camera key does not exist in the scene"),
300            Self::InvalidSurfaceSize { width, height } => {
301                write!(formatter, "invalid surface size {width}x{height}")
302            }
303            Self::SurfaceLost { recoverable } => {
304                write!(
305                    formatter,
306                    "render surface was lost; recoverable={recoverable}"
307                )
308            }
309            Self::ContextLost { recoverable } => {
310                write!(
311                    formatter,
312                    "render context was lost; recoverable={recoverable}"
313                )
314            }
315            Self::GpuDeviceLost { recoverable } => {
316                write!(formatter, "GPU device was lost; recoverable={recoverable}")
317            }
318            Self::GpuResourcesNotPrepared { backend } => {
319                write!(formatter, "GPU resources for {backend:?} were not prepared")
320            }
321            Self::GpuReadback { backend } => {
322                write!(formatter, "failed to read rendered output for {backend:?}")
323            }
324        }
325    }
326}
327
328impl fmt::Display for NotPreparedReason {
329    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
330        match self {
331            Self::NeverPrepared => write!(formatter, "prepare has not been called"),
332            Self::DifferentScene => write!(formatter, "prepare was called for a different scene"),
333            Self::SceneChanged {
334                prepared_revision,
335                current_revision,
336                change,
337            }
338            | Self::EnvironmentChanged {
339                prepared_revision,
340                current_revision,
341                change,
342            } => write!(
343                formatter,
344                "prepared state changed after prepare ({prepared_revision} -> {current_revision}, {change:?})"
345            ),
346            Self::TargetChanged {
347                prepared_revision,
348                current_revision,
349                change,
350            } => write!(
351                formatter,
352                "render target changed after prepare ({prepared_revision} -> {current_revision}, {change:?})"
353            ),
354            Self::RendererChanged {
355                prepared_revision,
356                current_revision,
357                change,
358            } => write!(
359                formatter,
360                "renderer setting changed after prepare ({prepared_revision} -> {current_revision}, {change:?}); call prepare again"
361            ),
362        }
363    }
364}
365
366impl fmt::Display for LookupError {
367    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
368        match self {
369            Self::NodeNotFound(_) => write!(formatter, "node key does not exist in the scene"),
370            Self::NodeNameNotFound { name } => {
371                write!(formatter, "imported scene has no node named '{name}'")
372            }
373            Self::AmbiguousNodeName { name, matches } => write!(
374                formatter,
375                "imported scene node name '{name}' is ambiguous across {} nodes",
376                matches.len()
377            ),
378            Self::AnchorNotFound { name } => {
379                write!(formatter, "imported scene has no anchor named '{name}'")
380            }
381            Self::AmbiguousAnchorName { name, hosts } => write!(
382                formatter,
383                "imported scene anchor name '{name}' is ambiguous across {} host nodes",
384                hosts.len()
385            ),
386            Self::ConnectorNotFound { name } => {
387                write!(formatter, "imported scene has no connector named '{name}'")
388            }
389            Self::AmbiguousConnectorName { name, hosts } => write!(
390                formatter,
391                "imported scene connector name '{name}' is ambiguous across {} host nodes",
392                hosts.len()
393            ),
394            Self::ClipNotFound { name } => {
395                write!(
396                    formatter,
397                    "imported scene has no animation clip named '{name}'"
398                )
399            }
400            Self::VariantNotFound { name } => write!(
401                formatter,
402                "imported scene has no KHR_materials_variants variant named '{name}'"
403            ),
404            Self::AmbiguousClipName { name, matches } => write!(
405                formatter,
406                "imported scene animation clip name '{name}' is ambiguous across {} clips",
407                matches.len()
408            ),
409            Self::PathNotFound { path } => {
410                write!(formatter, "imported scene path '{path}' was not found")
411            }
412            Self::InvalidViewport { width, height } => {
413                write!(
414                    formatter,
415                    "viewport {width}x{height} is invalid; width and height must be non-zero"
416                )
417            }
418            Self::ImportHasNoBounds => {
419                write!(
420                    formatter,
421                    "imported scene has no renderable bounds to frame"
422                )
423            }
424            Self::StaleImport => write!(formatter, "scene import has been invalidated"),
425            Self::NodeIsNotMesh { node } => write!(formatter, "node {node:?} is not a mesh node"),
426            Self::NonInvertibleParentTransform { node, parent } => write!(
427                formatter,
428                "node {node:?} cannot be placed in world space because parent {parent:?} has a non-invertible transform"
429            ),
430            Self::GeometryNotFound { node, .. } => {
431                write!(
432                    formatter,
433                    "geometry for mesh node {node:?} was not found in Assets"
434                )
435            }
436            Self::CameraNotFound(_) => write!(formatter, "camera key does not exist in the scene"),
437            Self::ClippingPlaneNotFound(_) => {
438                write!(formatter, "clipping plane key does not exist in the scene")
439            }
440            Self::InstanceSetNotFound(_) => {
441                write!(formatter, "instance set key does not exist in the scene")
442            }
443            Self::LabelNotFound(_) => write!(formatter, "label key does not exist in the scene"),
444        }
445    }
446}
447
448impl fmt::Display for AnimationError {
449    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
450        match self {
451            Self::ClipNotFound { name } => {
452                write!(
453                    formatter,
454                    "imported scene has no animation clip named '{name}'"
455                )
456            }
457            Self::MixerNotFound(_) => write!(formatter, "animation mixer key does not exist"),
458            Self::StaleMixer(_) => write!(
459                formatter,
460                "animation mixer is stale because its source import was replaced"
461            ),
462        }
463    }
464}
465
466impl error::Error for Error {}
467impl error::Error for BuildError {}
468impl error::Error for AssetError {}
469impl error::Error for ImportError {}
470impl error::Error for InstantiateError {}
471impl error::Error for PrepareError {}
472impl error::Error for RenderError {}
473impl error::Error for LookupError {}
474impl error::Error for AnimationError {}