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