Skip to main content

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