1use 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
13pub(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#[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#[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#[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#[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#[derive(Debug)]
158#[non_exhaustive]
159pub enum BorrowError {
160 AlreadyBorrowed,
162 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
177pub(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}