oxmera_core/error.rs
1//! The error taxonomy.
2//!
3//! The design rule: invalid states are unrepresentable where the type
4//! system can afford it, and every representable failure is typed — no
5//! stringly errors on any seam.
6
7use crate::device::Device;
8use crate::dtype::DType;
9use crate::shape::Shape;
10
11/// Any failure an oxmera operation can report.
12#[derive(Debug, thiserror::Error)]
13#[non_exhaustive]
14pub enum Error {
15 /// Two shapes were required to match and did not.
16 #[error("shape mismatch: expected {expected:?}, got {got:?} in {op}")]
17 ShapeMismatch {
18 /// The shape the operation required.
19 expected: Shape,
20 /// The shape it received.
21 got: Shape,
22 /// The operation reporting the mismatch.
23 op: &'static str,
24 },
25
26 /// Two shapes cannot broadcast together.
27 #[error("cannot broadcast {lhs:?} with {rhs:?}")]
28 BroadcastIncompatible {
29 /// Left operand shape.
30 lhs: Shape,
31 /// Right operand shape.
32 rhs: Shape,
33 },
34
35 /// Two dtypes were required to match and did not.
36 #[error("dtype mismatch: expected {expected:?}, got {got:?} in {op}")]
37 DTypeMismatch {
38 /// The dtype the operation required.
39 expected: DType,
40 /// The dtype it received.
41 got: DType,
42 /// The operation reporting the mismatch.
43 op: &'static str,
44 },
45
46 /// An operation does not support a dtype at all.
47 #[error("dtype {dtype:?} is not supported by {op}")]
48 UnsupportedDType {
49 /// The offending dtype.
50 dtype: DType,
51 /// The operation that cannot carry it.
52 op: &'static str,
53 },
54
55 /// Operands live on different devices.
56 #[error("device mismatch: {lhs:?} vs {rhs:?} in {op}")]
57 DeviceMismatch {
58 /// Left operand device.
59 lhs: Device,
60 /// Right operand device.
61 rhs: Device,
62 /// The operation reporting the mismatch.
63 op: &'static str,
64 },
65
66 /// A logical index was outside a tensor's bounds.
67 #[error("index {index:?} out of bounds for shape {shape:?}")]
68 IndexOutOfBounds {
69 /// The offending index.
70 index: Vec<usize>,
71 /// The shape it was applied to.
72 shape: Shape,
73 },
74
75 /// An index had the wrong number of dimensions for the shape.
76 #[error("rank mismatch: index of rank {index_rank} against shape of rank {shape_rank}")]
77 RankMismatch {
78 /// Rank of the supplied index.
79 index_rank: usize,
80 /// Rank of the shape it was applied to.
81 shape_rank: usize,
82 },
83
84 /// No backend is registered for a device.
85 #[error("no backend available for device {device:?}")]
86 BackendUnavailable {
87 /// The device with no backend.
88 device: Device,
89 },
90
91 /// An argument was structurally invalid for the operation.
92 #[error("invalid argument to {op}: {detail}")]
93 InvalidArgument {
94 /// The operation.
95 op: &'static str,
96 /// What was wrong with the argument.
97 detail: String,
98 },
99
100 /// A backend failed internally (driver error, shader compilation, …).
101 #[error("backend failure in {op}: {detail}")]
102 Backend {
103 /// The operation.
104 op: &'static str,
105 /// The backend's own description of the failure.
106 detail: String,
107 },
108
109 /// An I/O failure while loading or saving tensors.
110 #[error("io failure in {op}: {detail}")]
111 Io {
112 /// The operation.
113 op: &'static str,
114 /// The underlying error, rendered.
115 detail: String,
116 },
117
118 /// The operation is not implemented for a combination of inputs.
119 #[error("{op} is not implemented for {detail}")]
120 NotImplemented {
121 /// The operation.
122 op: &'static str,
123 /// What combination is unsupported.
124 detail: String,
125 },
126}
127
128/// The result type every fallible oxmera API returns.
129pub type Result<T> = std::result::Result<T, Error>;