rten_tensor/
errors.rs

1//! Error types that are reported by various tensor operations.
2
3use std::error::Error;
4use std::fmt::{Display, Formatter};
5
6use crate::slice_range::SliceRange;
7
8/// Error in a tensor operation if the dimension count is incorrect.
9#[derive(Debug, PartialEq)]
10pub struct DimensionError {
11    /// Actual number of dimensions the tensor has.
12    pub actual: usize,
13
14    /// Expected number of dimensions.
15    pub expected: usize,
16}
17
18impl Display for DimensionError {
19    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
20        write!(
21            f,
22            "tensor has {} dims but expected {}",
23            self.actual, self.expected
24        )
25    }
26}
27
28impl Error for DimensionError {}
29
30/// Errors that can occur when constructing a tensor from existing data.
31#[derive(Debug, PartialEq)]
32pub enum FromDataError {
33    /// Some indices will map to offsets that are beyond the end of the storage.
34    StorageTooShort,
35
36    /// The storage length was expected to exactly match the product of the
37    /// shape, and it did not.
38    StorageLengthMismatch,
39
40    /// Some indices will map to the same offset within the storage.
41    ///
42    /// This error can only occur when the storage is mutable.
43    MayOverlap,
44}
45
46impl Display for FromDataError {
47    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
48        match self {
49            FromDataError::StorageTooShort => write!(f, "data too short"),
50            FromDataError::StorageLengthMismatch => write!(f, "data length mismatch"),
51            FromDataError::MayOverlap => write!(f, "may have internal overlap"),
52        }
53    }
54}
55
56impl Error for FromDataError {}
57
58/// Errors that can occur when slicing a tensor.
59#[derive(Clone, Debug, PartialEq)]
60pub enum SliceError {
61    /// The slice spec has more dimensions than the tensor being sliced.
62    TooManyDims {
63        /// Number of axes in the tensor.
64        ndim: usize,
65        /// Number of items in the slice spec.
66        range_ndim: usize,
67    },
68
69    /// The slice spec specified an axis that is equal to or greater than the
70    /// dimension count.
71    InvalidAxis { axis: usize },
72
73    /// An index in the slice spec is out of bounds for the corresponding tensor
74    /// dimension.
75    InvalidIndex {
76        /// Axis that the error applies to.
77        axis: usize,
78        /// Index in the slice range.
79        index: isize,
80        /// Size of the dimension.
81        size: usize,
82    },
83
84    /// A range in the slice spec is out of bounds for the corresponding tensor
85    /// dimension.
86    InvalidRange {
87        /// Axis that the error applies to.
88        axis: usize,
89
90        /// The range item.
91        range: SliceRange,
92
93        /// Size of the dimension.
94        size: usize,
95    },
96
97    /// The step in a slice range is negative, in a context where this is not
98    /// supported.
99    InvalidStep {
100        /// Axis that the error applies to.
101        axis: usize,
102
103        /// Size of the dimension.
104        step: isize,
105    },
106
107    /// There is a mismatch between the actual and expected number of axes
108    /// in the output slice.
109    OutputDimsMismatch { actual: usize, expected: usize },
110}
111
112impl Display for SliceError {
113    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114        match self {
115            SliceError::TooManyDims { ndim, range_ndim } => {
116                write!(
117                    f,
118                    "slice range has {} items but tensor has only {} dims",
119                    range_ndim, ndim
120                )
121            }
122            SliceError::InvalidAxis { axis } => write!(f, "slice axis {} is invalid", axis),
123            SliceError::InvalidIndex { axis, index, size } => write!(
124                f,
125                "slice index {} is invalid for axis ({}) of size {}",
126                index, axis, size
127            ),
128            SliceError::InvalidRange { axis, range, size } => write!(
129                f,
130                "slice range {:?} is invalid for axis ({}) of size {}",
131                range, axis, size
132            ),
133            SliceError::InvalidStep { axis, step } => {
134                write!(f, "slice step {} is invalid for axis {}", step, axis)
135            }
136            SliceError::OutputDimsMismatch { actual, expected } => {
137                write!(
138                    f,
139                    "slice output dims {} does not match expected dims {}",
140                    actual, expected
141                )
142            }
143        }
144    }
145}
146
147impl Error for SliceError {}
148
149/// Errors that can occur while reshaping a layout or tensor.
150#[derive(Clone, Debug, PartialEq)]
151pub enum ReshapeError {
152    /// Attempted to reshape a tensor without copying data, but the layout
153    /// is not contiguous.
154    NotContiguous,
155
156    /// The reshaped layout would have a different length than the current
157    /// layout.
158    LengthMismatch,
159}
160
161impl std::fmt::Display for ReshapeError {
162    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
163        match self {
164            ReshapeError::NotContiguous => write!(f, "view is not contiguous"),
165            ReshapeError::LengthMismatch => write!(f, "new shape has a different length"),
166        }
167    }
168}
169
170/// Errors that can occur while expanding a tensor.
171#[derive(Clone, Debug, PartialEq)]
172pub enum ExpandError {
173    /// The shape of the source and destination tensor do not match, excluding
174    /// the dimensions along which expansion is happening.
175    ShapeMismatch,
176
177    /// The tensor cannot be resized without copying into a new buffer.
178    InsufficientCapacity,
179}
180
181impl std::fmt::Display for ExpandError {
182    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
183        match self {
184            ExpandError::ShapeMismatch => {
185                write!(
186                    f,
187                    "non-expanding dimensions of source and destination do not match"
188                )
189            }
190            ExpandError::InsufficientCapacity => {
191                write!(f, "insufficient capacity for new dimension size")
192            }
193        }
194    }
195}