numpy/
error.rs

1//! Defines error types.
2
3use std::error::Error;
4use std::fmt;
5
6use pyo3::{
7    conversion::IntoPyObject, exceptions::PyTypeError, Bound, Py, PyErr, PyErrArguments, PyObject,
8    Python,
9};
10
11use crate::dtype::PyArrayDescr;
12
13/// Array dimensionality should be limited by [`NPY_MAXDIMS`][NPY_MAXDIMS] which is currently 32.ยด
14///
15/// [NPY_MAXDIMS]: https://github.com/numpy/numpy/blob/4c60b3263ac50e5e72f6a909e156314fc3c9cba0/numpy/core/include/numpy/ndarraytypes.h#L40
16pub(crate) const MAX_DIMENSIONALITY_ERR: &str = "unexpected dimensionality: NumPy is expected to limit arrays to 32 or fewer dimensions.\nPlease report a bug against the `rust-numpy` crate.";
17
18pub(crate) const DIMENSIONALITY_MISMATCH_ERR: &str = "inconsistent dimensionalities: The dimensionality expected by `PyArray` does not match that given by NumPy.\nPlease report a bug against the `rust-numpy` crate.";
19
20macro_rules! impl_pyerr {
21    ($err_type:ty) => {
22        impl Error for $err_type {}
23
24        impl PyErrArguments for $err_type {
25            fn arguments<'py>(self, py: Python<'py>) -> PyObject {
26                self.to_string()
27                    .into_pyobject(py)
28                    .unwrap()
29                    .into_any()
30                    .unbind()
31            }
32        }
33
34        impl From<$err_type> for PyErr {
35            fn from(err: $err_type) -> PyErr {
36                PyTypeError::new_err(err)
37            }
38        }
39    };
40}
41
42/// Represents that dimensionalities of the given arrays do not match.
43#[derive(Debug)]
44pub struct DimensionalityError {
45    from: usize,
46    to: usize,
47}
48
49impl DimensionalityError {
50    pub(crate) fn new(from: usize, to: usize) -> Self {
51        Self { from, to }
52    }
53}
54
55impl fmt::Display for DimensionalityError {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(
58            f,
59            "dimensionality mismatch:\n from={}, to={}",
60            self.from, self.to
61        )
62    }
63}
64
65impl_pyerr!(DimensionalityError);
66
67/// Represents that types of the given arrays do not match.
68#[derive(Debug)]
69pub struct TypeError<'py> {
70    from: Bound<'py, PyArrayDescr>,
71    to: Bound<'py, PyArrayDescr>,
72}
73
74impl<'py> TypeError<'py> {
75    pub(crate) fn new(from: Bound<'py, PyArrayDescr>, to: Bound<'py, PyArrayDescr>) -> Self {
76        Self { from, to }
77    }
78}
79
80impl fmt::Display for TypeError<'_> {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        write!(f, "type mismatch:\n from={}, to={}", self.from, self.to)
83    }
84}
85
86impl Error for TypeError<'_> {}
87
88struct TypeErrorArguments {
89    from: Py<PyArrayDescr>,
90    to: Py<PyArrayDescr>,
91}
92
93impl PyErrArguments for TypeErrorArguments {
94    fn arguments<'py>(self, py: Python<'py>) -> PyObject {
95        let err = TypeError {
96            from: self.from.into_bound(py),
97            to: self.to.into_bound(py),
98        };
99
100        err.to_string()
101            .into_pyobject(py)
102            .unwrap()
103            .into_any()
104            .unbind()
105    }
106}
107
108impl From<TypeError<'_>> for PyErr {
109    fn from(err: TypeError<'_>) -> PyErr {
110        let args = TypeErrorArguments {
111            from: err.from.into(),
112            to: err.to.into(),
113        };
114
115        PyTypeError::new_err(args)
116    }
117}
118
119/// Represents that given `Vec` cannot be treated as an array.
120#[derive(Debug)]
121pub struct FromVecError {
122    len: usize,
123    exp_len: usize,
124}
125
126impl FromVecError {
127    pub(crate) fn new(len: usize, exp_len: usize) -> Self {
128        Self { len, exp_len }
129    }
130}
131
132impl fmt::Display for FromVecError {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        write!(
135            f,
136            "invalid length: {}, but expected {}",
137            self.len, self.exp_len
138        )
139    }
140}
141
142impl_pyerr!(FromVecError);
143
144/// Represents that the given array is not contiguous.
145#[derive(Debug)]
146pub struct NotContiguousError;
147
148impl fmt::Display for NotContiguousError {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        write!(f, "The given array is not contiguous")
151    }
152}
153
154impl_pyerr!(NotContiguousError);
155
156/// Inidcates why borrowing an array failed.
157#[derive(Debug)]
158#[non_exhaustive]
159pub enum BorrowError {
160    /// The given array is already borrowed
161    AlreadyBorrowed,
162    /// The given array is not writeable
163    NotWriteable,
164}
165
166impl fmt::Display for BorrowError {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        match self {
169            Self::AlreadyBorrowed => write!(f, "The given array is already borrowed"),
170            Self::NotWriteable => write!(f, "The given array is not writeable"),
171        }
172    }
173}
174
175impl_pyerr!(BorrowError);
176
177/// An internal type used to ignore certain error conditions
178///
179/// This is beneficial when those errors will never reach a public API anyway
180/// but dropping them will improve performance.
181pub(crate) struct IgnoreError;
182
183impl<E> From<E> for IgnoreError
184where
185    PyErr: From<E>,
186{
187    fn from(_err: E) -> Self {
188        Self
189    }
190}