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    ExpectedNumeric(Robj),
69    ExpectedAltrep(Robj),
70    ExpectedDataframe(Robj),
71
72    OutOfRange(Robj),
73    MustNotBeNA(Robj),
74    ExpectedWholeNumber(Robj, ConversionError),
75    ExpectedNonZeroLength(Robj),
76    OutOfLimits(Robj),
77    TypeMismatch(Robj),
78    NamespaceNotFound(Robj),
79    NoGraphicsDevices(Robj),
80
81    ExpectedExternalPtrType(Robj, String),
82    ExpectedExternalNonNullPtr(Robj),
83    ExpectedExternalPtrReference,
84    Other(String),
85
86    #[cfg(feature = "ndarray")]
87    NDArrayShapeError(ndarray::ShapeError),
88
89    #[cfg(feature = "either")]
90    EitherError(Box<Error>, Box<Error>),
91}
92
93impl std::fmt::Display for Error {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        match self {
96            Error::Panic(robj) => write!(f, "Panic detected {:?}.", robj),
97            Error::NotFound(robj) => write!(f, "Not found. {:?}", robj),
98            Error::EvalError(robj) => write!(f, "Evaluation error in {:?}.", robj),
99            Error::ParseError(code) => write!(f, "Parse error in {:?}.", code),
100            Error::NamesLengthMismatch(robj) => {
101                write!(f, "Length of names does not match vector. {:?}", robj)
102            }
103
104            Error::ExpectedNull(robj) => write!(f, "Expected Null got {:?}", robj.rtype()),
105            Error::ExpectedSymbol(robj) => write!(f, "Expected Symbol got {:?}", robj.rtype()),
106            Error::ExpectedPairlist(robj) => write!(f, "Expected Pairlist got {:?}", robj.rtype()),
107            Error::ExpectedFunction(robj) => write!(f, "Expected Function got {:?}", robj.rtype()),
108            Error::ExpectedEnvironment(robj) => {
109                write!(f, "Expected Environment got {:?}", robj.rtype())
110            }
111            Error::ExpectedPromise(robj) => write!(f, "Expected Promise got {:?}", robj.rtype()),
112            Error::ExpectedLanguage(robj) => write!(f, "Expected Language got {:?}", robj.rtype()),
113            Error::ExpectedSpecial(robj) => write!(f, "Expected Special got {:?}", robj.rtype()),
114            Error::ExpectedBuiltin(robj) => write!(f, "Expected Builtin got {:?}", robj.rtype()),
115            Error::ExpectedRstr(robj) => {
116                write!(f, "Expected Rstr got {:?}", robj.rtype())
117            }
118            Error::ExpectedLogical(robj) => write!(f, "Expected Logicals got {:?}", robj.rtype()),
119            Error::ExpectedInteger(robj) => write!(f, "Expected Integers got {:?}", robj.rtype()),
120            Error::ExpectedReal(robj) => write!(f, "Expected Doubles got {:?}", robj.rtype()),
121            Error::ExpectedComplex(robj) => write!(f, "Expected Complexes got {:?}", robj.rtype()),
122            Error::ExpectedString(robj) => write!(f, "Expected Strings got {:?}", robj.rtype()),
123            Error::ExpectedDot(robj) => write!(f, "Expected Dot got {:?}", robj.rtype()),
124            Error::ExpectedAny(robj) => write!(f, "Expected Any got {:?}", robj.rtype()),
125            Error::ExpectedList(robj) => write!(f, "Expected List got {:?}", robj.rtype()),
126            Error::ExpectedExpression(robj) => {
127                write!(f, "Expected Expression got {:?}", robj.rtype())
128            }
129            Error::ExpectedBytecode(robj) => write!(f, "Expected Bytecode got {:?}", robj.rtype()),
130            Error::ExpectedExternalPtr(robj) => {
131                write!(f, "Expected ExternalPtr got {:?}", robj.rtype())
132            }
133            Error::ExpectedWeakRef(robj) => write!(f, "Expected WeakRef got {:?}", robj.rtype()),
134            Error::ExpectedRaw(robj) => write!(f, "Expected Raw got {:?}", robj.rtype()),
135            Error::ExpectedS4(robj) => write!(f, "Expected S4 got {:?}", robj.rtype()),
136            Error::ExpectedPrimitive(robj) => {
137                write!(f, "Expected Primitive got {:?}", robj.rtype())
138            }
139
140            Error::ExpectedScalar(robj) => write!(f, "Expected Scalar, got {:?}", robj.rtype()),
141            Error::ExpectedVector(robj) => write!(f, "Expected Vector, got {:?}", robj.rtype()),
142            Error::ExpectedMatrix(robj) => write!(f, "Expected Matrix, got {:?}", robj.rtype()),
143            Error::ExpectedMatrix3D(robj) => write!(f, "Expected Matrix3D, got {:?}", robj.rtype()),
144            Error::ExpectedNumeric(robj) => write!(f, "Expected Numeric, got {:?}", robj.rtype()),
145            Error::ExpectedAltrep(robj) => write!(f, "Expected Altrep, got {:?}", robj.rtype()),
146            Error::ExpectedDataframe(robj) => {
147                write!(f, "Expected Dataframe, got {:?}", robj.rtype())
148            }
149
150            Error::OutOfRange(_robj) => write!(f, "Out of range."),
151            Error::MustNotBeNA(_robj) => write!(f, "Must not be NA."),
152            Error::ExpectedNonZeroLength(_robj) => write!(f, "Expected non zero length"),
153            Error::OutOfLimits(robj) => write!(f, "The value is too big: {:?}", robj),
154            Error::TypeMismatch(_robj) => write!(f, "Type mismatch"),
155
156            Error::NamespaceNotFound(robj) => write!(f, "Namespace {:?} not found", robj),
157            Error::ExpectedExternalPtrType(_robj, type_name) => {
158                write!(f, "Incorrect external pointer type {}", type_name)
159            }
160            Error::ExpectedExternalNonNullPtr(robj) => {
161                write!(
162                    f,
163                    "expected non-null pointer in externalptr, instead {:?}",
164                    robj
165                )
166            }
167            Error::ExpectedExternalPtrReference => {
168                write!(f, "It is only possible to return a reference to self.")
169            }
170            Error::NoGraphicsDevices(_robj) => write!(f, "No graphics devices active."),
171            Error::Other(str) => write!(f, "{}", str),
172
173            Error::ExpectedWholeNumber(robj, conversion_error) => {
174                write!(
175                    f,
176                    "Failed to convert a float to a whole number: {}. Actual value received: {:?}",
177                    conversion_error, robj
178                )
179            }
180
181            #[cfg(feature = "ndarray")]
182            Error::NDArrayShapeError(shape_error) => {
183                write!(f, "NDArray failed with error: {}.", shape_error)
184            }
185
186            #[cfg(feature = "either")]
187            Error::EitherError(left_err, right_err) => {
188                write!(
189                    f,
190                    "Both cases of Either errored. Left: '{}'; Right: '{}'.",
191                    left_err, right_err
192                )
193            }
194        }
195    }
196}
197pub type Result<T> = std::result::Result<T, Error>;
198
199// impl std::fmt::Display for Error {
200//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201//         write!(f, "{:?}", self)
202//     }
203// }
204
205impl std::error::Error for Error {
206    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
207        None
208    }
209}
210
211impl From<Box<dyn std::error::Error>> for Error {
212    fn from(err: Box<dyn std::error::Error>) -> Error {
213        Error::Other(format!("{}", err))
214    }
215}
216
217impl From<&str> for Error {
218    fn from(err: &str) -> Error {
219        Error::Other(err.to_string())
220    }
221}
222
223impl From<String> for Error {
224    fn from(err: String) -> Error {
225        Error::Other(err)
226    }
227}
228
229// NoneError is unstable.
230//
231// impl From<std::option::NoneError> for Error {
232//     fn from(err: std::option::NoneError) -> Error {
233//         Error::None
234//     }
235// }
236
237impl From<Infallible> for Error {
238    fn from(_: Infallible) -> Self {
239        Error::Other("".to_string())
240    }
241}