extendr_api/
error.rs

1//! Error handling in Rust called from R.
2
3use std::convert::Infallible;
4
5use crate::conversions::try_into_int::ConversionError;
6use crate::robj::Types;
7use crate::{throw_r_error, Robj};
8
9/// Throw an R error if a result is an error.
10#[doc(hidden)]
11pub fn unwrap_or_throw<T>(r: std::result::Result<T, &'static str>) -> T {
12    match r {
13        Err(e) => {
14            throw_r_error(e);
15        }
16        Ok(v) => v,
17    }
18}
19
20#[doc(hidden)]
21pub fn unwrap_or_throw_error<T>(r: std::result::Result<T, Error>) -> T {
22    match r {
23        Err(e) => {
24            throw_r_error(e.to_string());
25        }
26        Ok(v) => v,
27    }
28}
29
30#[derive(Debug, PartialEq)]
31pub enum Error {
32    Panic(Robj),
33    NotFound(Robj),
34    EvalError(Robj),
35    ParseError(Robj),
36    NamesLengthMismatch(Robj),
37
38    ExpectedNull(Robj),
39    ExpectedSymbol(Robj),
40    ExpectedPairlist(Robj),
41    ExpectedFunction(Robj),
42    ExpectedEnvironment(Robj),
43    ExpectedPromise(Robj),
44    ExpectedLanguage(Robj),
45    ExpectedSpecial(Robj),
46    ExpectedBuiltin(Robj),
47    ExpectedRstr(Robj),
48    ExpectedLogical(Robj),
49    ExpectedInteger(Robj),
50    ExpectedReal(Robj),
51    ExpectedComplex(Robj),
52    ExpectedString(Robj),
53    ExpectedDot(Robj),
54    ExpectedAny(Robj),
55    ExpectedList(Robj),
56    ExpectedExpression(Robj),
57    ExpectedBytecode(Robj),
58    ExpectedExternalPtr(Robj),
59    ExpectedWeakRef(Robj),
60    ExpectedRaw(Robj),
61    ExpectedS4(Robj),
62    ExpectedPrimitive(Robj),
63
64    ExpectedScalar(Robj),
65    ExpectedVector(Robj),
66    ExpectedMatrix(Robj),
67    ExpectedMatrix3D(Robj),
68    ExpectedMatrix4D(Robj),
69    ExpectedMatrix5D(Robj),
70    ExpectedNumeric(Robj),
71    ExpectedAltrep(Robj),
72    ExpectedDataframe(Robj),
73
74    OutOfRange(Robj),
75    MustNotBeNA(Robj),
76    ExpectedWholeNumber(Robj, ConversionError),
77    ExpectedNonZeroLength(Robj),
78    ExpectedLength(usize),
79    OutOfLimits(Robj),
80    TypeMismatch(Robj),
81    NamespaceNotFound(Robj),
82    NoGraphicsDevices(Robj),
83
84    ExpectedExternalPtrType(Robj, String),
85    ExpectedExternalNonNullPtr(Robj),
86    ExpectedExternalPtrReference,
87    Other(String),
88
89    #[cfg(feature = "ndarray")]
90    NDArrayShapeError(ndarray::ShapeError),
91
92    #[cfg(feature = "either")]
93    EitherError(Box<Error>, Box<Error>),
94    /// See [`std::array::TryFromSliceError`]
95    TryFromSliceError(String),
96}
97
98impl std::fmt::Display for Error {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        match self {
101            Error::Panic(robj) => write!(f, "Panic detected {:?}.", robj),
102            Error::NotFound(robj) => write!(f, "Not found. {:?}", robj),
103            Error::EvalError(robj) => write!(f, "Evaluation error in {:?}.", robj),
104            Error::ParseError(code) => write!(f, "Parse error in {:?}.", code),
105            Error::NamesLengthMismatch(robj) => {
106                write!(f, "Length of names does not match vector. {:?}", robj)
107            }
108
109            Error::ExpectedNull(robj) => write!(f, "Expected Null got {:?}", robj.rtype()),
110            Error::ExpectedSymbol(robj) => write!(f, "Expected Symbol got {:?}", robj.rtype()),
111            Error::ExpectedPairlist(robj) => write!(f, "Expected Pairlist got {:?}", robj.rtype()),
112            Error::ExpectedFunction(robj) => write!(f, "Expected Function got {:?}", robj.rtype()),
113            Error::ExpectedEnvironment(robj) => {
114                write!(f, "Expected Environment got {:?}", robj.rtype())
115            }
116            Error::ExpectedPromise(robj) => write!(f, "Expected Promise got {:?}", robj.rtype()),
117            Error::ExpectedLanguage(robj) => write!(f, "Expected Language got {:?}", robj.rtype()),
118            Error::ExpectedSpecial(robj) => write!(f, "Expected Special got {:?}", robj.rtype()),
119            Error::ExpectedBuiltin(robj) => write!(f, "Expected Builtin got {:?}", robj.rtype()),
120            Error::ExpectedRstr(robj) => {
121                write!(f, "Expected Rstr got {:?}", robj.rtype())
122            }
123            Error::ExpectedLogical(robj) => write!(f, "Expected Logicals got {:?}", robj.rtype()),
124            Error::ExpectedInteger(robj) => write!(f, "Expected Integers got {:?}", robj.rtype()),
125            Error::ExpectedReal(robj) => write!(f, "Expected Doubles got {:?}", robj.rtype()),
126            Error::ExpectedComplex(robj) => write!(f, "Expected Complexes got {:?}", robj.rtype()),
127            Error::ExpectedString(robj) => write!(f, "Expected Strings got {:?}", robj.rtype()),
128            Error::ExpectedDot(robj) => write!(f, "Expected Dot got {:?}", robj.rtype()),
129            Error::ExpectedAny(robj) => write!(f, "Expected Any got {:?}", robj.rtype()),
130            Error::ExpectedList(robj) => write!(f, "Expected List got {:?}", robj.rtype()),
131            Error::ExpectedExpression(robj) => {
132                write!(f, "Expected Expression got {:?}", robj.rtype())
133            }
134            Error::ExpectedBytecode(robj) => write!(f, "Expected Bytecode got {:?}", robj.rtype()),
135            Error::ExpectedExternalPtr(robj) => {
136                write!(f, "Expected ExternalPtr got {:?}", robj.rtype())
137            }
138            Error::ExpectedWeakRef(robj) => write!(f, "Expected WeakRef got {:?}", robj.rtype()),
139            Error::ExpectedRaw(robj) => write!(f, "Expected Raw got {:?}", robj.rtype()),
140            Error::ExpectedS4(robj) => write!(f, "Expected S4 got {:?}", robj.rtype()),
141            Error::ExpectedPrimitive(robj) => {
142                write!(f, "Expected Primitive got {:?}", robj.rtype())
143            }
144
145            Error::ExpectedScalar(robj) => write!(f, "Expected Scalar, got {:?}", robj.rtype()),
146            Error::ExpectedVector(robj) => write!(f, "Expected Vector, got {:?}", robj.rtype()),
147            Error::ExpectedMatrix(robj) => write!(f, "Expected Matrix, got {:?}", robj.rtype()),
148            Error::ExpectedMatrix3D(robj) => write!(f, "Expected Matrix3D, got {:?}", robj.rtype()),
149            Error::ExpectedMatrix4D(robj) => write!(f, "Expected Matrix4D, got {:?}", robj.rtype()),
150            Error::ExpectedMatrix5D(robj) => write!(f, "Expected Matrix5D, got {:?}", robj.rtype()),
151            Error::ExpectedNumeric(robj) => write!(f, "Expected Numeric, got {:?}", robj.rtype()),
152            Error::ExpectedAltrep(robj) => write!(f, "Expected Altrep, got {:?}", robj.rtype()),
153            Error::ExpectedDataframe(robj) => {
154                write!(f, "Expected Dataframe, got {:?}", robj.rtype())
155            }
156
157            Error::OutOfRange(_robj) => write!(f, "Out of range."),
158            Error::MustNotBeNA(_robj) => write!(f, "Must not be NA."),
159            Error::ExpectedNonZeroLength(_robj) => write!(f, "Expected non zero length"),
160            Error::ExpectedLength(len) => write!(f, "Expected length: {len}"),
161            Error::OutOfLimits(robj) => write!(f, "The value is too big: {:?}", robj),
162            Error::TypeMismatch(_robj) => write!(f, "Type mismatch"),
163
164            Error::NamespaceNotFound(robj) => write!(f, "Namespace {:?} not found", robj),
165            Error::ExpectedExternalPtrType(_robj, type_name) => {
166                write!(f, "Incorrect external pointer type {}", type_name)
167            }
168            Error::ExpectedExternalNonNullPtr(robj) => {
169                write!(
170                    f,
171                    "expected non-null pointer in externalptr, instead {:?}",
172                    robj
173                )
174            }
175            Error::ExpectedExternalPtrReference => {
176                write!(f, "It is only possible to return a reference to self.")
177            }
178            Error::NoGraphicsDevices(_robj) => write!(f, "No graphics devices active."),
179            // this is very unlikely to occur, and it would just say: Rust error: could not convert slice to array
180            Error::TryFromSliceError(std_error) => write!(f, "Rust error: {}", std_error),
181            Error::Other(str) => write!(f, "{}", str),
182
183            Error::ExpectedWholeNumber(robj, conversion_error) => {
184                write!(
185                    f,
186                    "Failed to convert a float to a whole number: {}. Actual value received: {:?}",
187                    conversion_error, robj
188                )
189            }
190
191            #[cfg(feature = "ndarray")]
192            Error::NDArrayShapeError(shape_error) => {
193                write!(f, "NDArray failed with error: {}.", shape_error)
194            }
195
196            #[cfg(feature = "either")]
197            Error::EitherError(left_err, right_err) => {
198                write!(
199                    f,
200                    "Both cases of Either errored. Left: '{}'; Right: '{}'.",
201                    left_err, right_err
202                )
203            }
204        }
205    }
206}
207pub type Result<T> = std::result::Result<T, Error>;
208
209// impl std::fmt::Display for Error {
210//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211//         write!(f, "{:?}", self)
212//     }
213// }
214
215impl std::error::Error for Error {
216    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
217        None
218    }
219}
220
221impl From<Box<dyn std::error::Error>> for Error {
222    fn from(err: Box<dyn std::error::Error>) -> Error {
223        Error::Other(format!("{}", err))
224    }
225}
226
227impl From<&str> for Error {
228    fn from(err: &str) -> Error {
229        Error::Other(err.to_string())
230    }
231}
232
233impl From<String> for Error {
234    fn from(err: String) -> Error {
235        Error::Other(err)
236    }
237}
238
239// NoneError is unstable.
240//
241// impl From<std::option::NoneError> for Error {
242//     fn from(err: std::option::NoneError) -> Error {
243//         Error::None
244//     }
245// }
246
247impl From<Infallible> for Error {
248    fn from(_: Infallible) -> Self {
249        Error::Other("".to_string())
250    }
251}