viewport_lib/error.rs
1//! Error types for the viewport library.
2
3/// Errors that can occur during mesh upload and manipulation.
4#[derive(Debug, Clone, thiserror::Error)]
5#[non_exhaustive]
6pub enum ViewportError {
7 /// Mesh data has empty positions or indices.
8 #[error("empty mesh: {positions} positions, {indices} indices")]
9 EmptyMesh {
10 /// Number of positions provided.
11 positions: usize,
12 /// Number of indices provided.
13 indices: usize,
14 },
15
16 /// Positions and normals arrays have different lengths.
17 #[error("mesh length mismatch: {positions} positions vs {normals} normals")]
18 MeshLengthMismatch {
19 /// Number of positions provided.
20 positions: usize,
21 /// Number of normals provided.
22 normals: usize,
23 },
24
25 /// Mesh index is out of bounds for the mesh storage.
26 #[error("mesh index {index} out of bounds (mesh count: {count})")]
27 MeshIndexOutOfBounds {
28 /// The requested mesh index.
29 index: usize,
30 /// The number of meshes currently stored.
31 count: usize,
32 },
33
34 /// An index buffer entry references a vertex that does not exist.
35 #[error("invalid vertex index {vertex_index} (vertex count: {vertex_count})")]
36 InvalidVertexIndex {
37 /// The offending index value.
38 vertex_index: u32,
39 /// Total number of vertices.
40 vertex_count: usize,
41 },
42
43 /// Volume scalar data length does not match the declared grid dimensions.
44 #[error("volume data length {actual} does not match dims {dims:?} (expected {expected})")]
45 VolumeDataLengthMismatch {
46 /// Number of scalar values provided.
47 actual: usize,
48 /// Expected length, equal to `dims[0] * dims[1] * dims[2]`.
49 expected: usize,
50 /// Grid dimensions `[nx, ny, nz]`.
51 dims: [u32; 3],
52 },
53
54 /// Texture RGBA data has an unexpected size.
55 #[error("invalid texture data: expected {expected} bytes, got {actual}")]
56 InvalidTextureData {
57 /// Expected byte count (width * height * 4).
58 expected: usize,
59 /// Actual byte count provided.
60 actual: usize,
61 },
62
63 /// Attempted to access or replace a mesh slot that is empty (previously removed).
64 #[error("mesh slot {index} is empty")]
65 MeshSlotEmpty {
66 /// The slot index that was accessed.
67 index: usize,
68 },
69
70 /// Named scalar attribute not found on the given mesh.
71 #[error("attribute '{name}' not found on mesh {mesh_id}")]
72 AttributeNotFound {
73 /// The mesh index that was accessed.
74 mesh_id: usize,
75 /// The attribute name that was requested.
76 name: String,
77 },
78
79 /// Attribute data length does not match the existing buffer.
80 ///
81 /// `replace_attribute` requires the same vertex count as the original upload.
82 #[error("attribute length mismatch: expected {expected} f32 elements, got {got}")]
83 AttributeLengthMismatch {
84 /// Expected number of f32 elements (original attribute length).
85 expected: usize,
86 /// Actual number of f32 elements provided.
87 got: usize,
88 },
89
90 /// A buffer required for GPU marching cubes upload exceeds the device's
91 /// `max_buffer_size` limit. The caller should fall back to CPU marching cubes.
92 #[error("GPU MC buffer '{buffer}' needs {needed} bytes but device limit is {limit}")]
93 McBufferTooLarge {
94 /// Short name identifying which buffer exceeded the limit (e.g. `"vertex_buf"`).
95 buffer: &'static str,
96 /// Bytes required for the allocation.
97 needed: u64,
98 /// The device's `max_buffer_size` limit.
99 limit: u64,
100 },
101
102 /// Gaussian splat data is malformed or empty.
103 #[error("invalid gaussian splat data: {reason}")]
104 InvalidGaussianSplatData {
105 /// Short description of what is wrong.
106 reason: &'static str,
107 },
108
109 /// A background upload worker panicked or dropped its channel before
110 /// sending a result.
111 #[error("upload worker did not complete: {reason}")]
112 JobWorkerLost {
113 /// Short description of how the worker was lost.
114 reason: &'static str,
115 },
116
117 /// `upload_result_*` was called before the corresponding job reached the
118 /// `Ready` state. Poll `upload_status` and retry on the next frame.
119 #[error("upload job is not yet ready to take its result")]
120 JobNotReady,
121
122 /// `upload_result_*` was called with a `JobId` that does not belong to
123 /// the matching upload type, has already been taken, or was never
124 /// issued.
125 #[error("upload job has no result available: {reason}")]
126 JobResultMissing {
127 /// Short description of why the result is unavailable.
128 reason: &'static str,
129 },
130}
131
132/// Convenience alias for `Result<T, ViewportError>`.
133pub type ViewportResult<T> = Result<T, ViewportError>;