rustr/
error.rs

1//! Error Type
2//!
3//!
4use std::result::Result;
5use ::rdll::*;
6use std::error::*;
7use std::result::Result::Err;
8pub type RResult<T> = Result<T, RError>;
9pub type SEXPResult = RResult<SEXP>;
10use self::REKind::*;
11use std::fmt;
12use std::convert::From;
13use util::*;
14use ::protect::stackp::*;
15
16use ::traits::*;
17
18use ::rtype::*;
19
20
21#[derive(Debug)]
22pub struct RError {
23    pub kind: REKind,
24}
25
26macro_rules! gen_fmt {
27    ($($x:ident),*) => (
28
29    impl fmt::Display for RError{
30        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
31                match *self.kind() {
32                    UnknownError(ref info) => write!(fmt,"UnknownError: {}",info),
33                    UnreachableError(ref info) => write!(fmt,"UnreachableError: {}",info),
34                    ForceStopError(ref info) => write!(fmt,"ForceStopError: {}",info),
35                    Other(ref c) =>  write!(fmt, "rustr error: {}",c.to_string()),
36                    $($x(ref c) => write!(fmt, "{}: {}", stringify!($x), c.to_string()))
37                        ,*
38
39                }
40
41        }
42    }
43
44	impl RError {
45        pub fn kind_info(&self) -> &str {
46	        match *self.kind() {
47	            UnknownError(..) => "UnknownError",
48	            UnreachableError(..) => "UnreachableError",
49	            ForceStopError(..) => "ForceStopError",
50	            Other(ref c) =>  c.description(),
51	            $($x(..) => stringify!($x))
52	                ,*
53	        }
54	    }
55	}
56
57    impl Error for RError {
58
59        fn description(&self) -> &str {
60            match *self.kind() {
61                UnknownError(..) => "UnknownError",
62                UnreachableError(..) => "UnreachableError",
63                ForceStopError(..) => "ForceStopError",
64                Other(ref c) => c.description(),
65                $($x(ref c) => c.description())
66                    ,*
67
68            }
69
70        }
71
72    fn cause(&self) -> Option<&dyn Error> {
73        match *self.kind() {
74            UnknownError(..) => None,
75            UnreachableError(..) => None,
76            ForceStopError(..) => None,
77            Other(ref c) => c.source(),
78            $($x(ref c))
79                    |* => c.source(),
80        }
81
82    }
83    }
84
85    #[derive(Debug)]
86    pub enum REKind{
87        $($x(Box<dyn Error+Send+Sync>)),*
88        ,UnknownError(String), UnreachableError(String), ForceStopError(String),Other(Box<dyn Error+Send+Sync>)
89
90    }
91    )
92}
93
94gen_fmt!(Interrupted,
95         NotAMatrix,
96         IndexOutOfBounds,
97         ParseError,
98         NotS4,
99         NotReference,
100         NotInitialized,
101         NoSuchSlot,
102         NoSuchField,
103         NotAClosure,
104         NoSuchFunction,
105         UnevaluatedPromise,
106         NoSuchEnv,
107         FileIoError,
108         FileNotFound,
109         FileExists,
110         NotCompatible,
111         S4CreationError,
112         ReferenceCreationError,
113         NoSuchBinding,
114         BindingNotFound,
115         BindingIsLocked,
116         NoSuchNamespace,
117         FunctionNotExported,
118         EvalError);
119
120
121impl From<::std::ffi::NulError> for RError {
122    fn from(x: ::std::ffi::NulError) -> Self {
123        RError::new(REKind::Other(x.into()))
124    }
125}
126
127
128impl RError {
129    /// Creates a new RError from a known kind of error as well as an
130    /// arbitrary error payload.
131    ///
132    /// # Examples
133    ///
134    /// ```txt
135    /// use rustr::error::{RError, REKind};
136    ///
137    /// ```
138    #[inline]
139    pub fn new(kind_: REKind) -> RError {
140        RError { kind: kind_ }
141    }
142    #[inline]
143    pub fn unknown(x: String) -> RError {
144        RError { kind: REKind::UnknownError(x) }
145    }
146    #[inline]
147    pub fn forcestop(x: String) -> RError {
148        RError { kind: REKind::ForceStopError(x) }
149    }
150    #[inline]
151    pub fn unreachable(x: String) -> RError {
152        RError { kind: REKind::UnreachableError(x) }
153    }
154    #[inline]
155    pub fn other<E>(x: E) -> RError
156        where E: Into<Box<dyn Error + Send + Sync>>
157    {
158        RError { kind: REKind::Other(x.into()) }
159    }
160    pub fn kind(&self) -> &REKind {
161        &(self.kind)
162    }
163}
164
165
166#[inline]
167pub fn rraise<T, E>(error: E) -> RResult<T>
168    where E: Into<Box<dyn Error + Send + Sync>>
169{
170
171    Err(RError::other(error))
172
173}
174
175#[inline]
176pub fn rerror<T>(kind_: REKind) -> RResult<T> {
177    Err(RError { kind: kind_ })
178}
179
180#[inline]
181pub fn rerr<T, E>(x: E) -> RResult<T>
182    where E: Into<Box<dyn Error + Send + Sync>>
183{
184    Err(RError { kind: REKind::Other(x.into()) })
185}
186
187pub fn get_current_call() -> SEXP {
188    unsafe {
189        let sys_calls_symbol = Rf_install(c_str("sys.calls").as_ptr());
190        let sys_calls_expr = Shield::new(Rf_lang1(sys_calls_symbol));
191        let calls = Shield::new(Rf_eval(sys_calls_expr.s(), R_GlobalEnv));
192        let mut res = calls.s();
193        while CDR(res) != R_NilValue {
194            res = CDR(res);
195        }
196        CAR(res)
197    }
198
199}
200
201pub fn get_exception_classes(ex: &RError) -> SEXP {
202    unsafe {
203
204        let kind_info_c = c_str(ex.kind_info());
205
206        let res = Shield::new(Rf_allocVector(STRSXP as ::std::os::raw::c_uint, 4));
207        SET_STRING_ELT(res.s(), 0, Rf_mkChar(kind_info_c.as_ptr()));
208        SET_STRING_ELT(res.s(), 1, Rf_mkChar(c_str("RustError").as_ptr()));
209        SET_STRING_ELT(res.s(), 2, Rf_mkChar(c_str("error").as_ptr()));
210        SET_STRING_ELT(res.s(), 3, Rf_mkChar(c_str("condition").as_ptr()));
211        res.s()
212    }
213
214}
215
216pub fn error_to_r_condition(x: RError) -> SEXP {
217    // todo
218    unsafe {
219        let class_sym = Shield::new(get_exception_classes(&x));
220
221        let cond = Shield::new(Rf_allocVector(VECSXP as ::std::os::raw::c_uint, 2));
222
223        let mess_c = c_str(format!("{}", x).as_ref());
224
225        let message = Shield::new(Rf_mkString(mess_c.as_ptr()));
226
227        SET_VECTOR_ELT(cond.s(), 0, message.s());
228        SET_VECTOR_ELT(cond.s(), 1, get_current_call());
229
230        let names = Shield::new(Rf_allocVector(STRSXP, 2));
231
232        SET_STRING_ELT(names.s(), 0, Rf_mkChar(c_str("message").as_ptr()));
233        SET_STRING_ELT(names.s(), 1, Rf_mkChar(c_str("call").as_ptr()));
234
235        Rf_setAttrib(cond.s(), R_NamesSymbol, names.s());
236        Rf_setAttrib(cond.s(), R_ClassSymbol, class_sym.s());
237
238        cond.s()
239    }
240
241}
242
243pub fn forward_exception_to_r(ex: RError) -> SEXP {
244    unsafe {
245
246        let stop_sym = cstr_sym("stop");
247        let condition = Shield::new(error_to_r_condition(ex));
248
249        let expr = Shield::new(Rf_lang2(stop_sym, condition.s()));
250
251        Rf_eval(expr.s(), R_GlobalEnv);
252        R_NilValue
253    }
254}
255
256
257// other error kind ///////////////////////
258
259
260impl From<::std::ffi::IntoStringError> for RError {
261    fn from(x: ::std::ffi::IntoStringError) -> RError {
262        RError::new(REKind::Other(x.into()))
263    }
264}