artichoke_backend/extn/core/exception/
mod.rs1use std::borrow::Cow;
24
25#[doc(inline)]
26pub use spinoso_exception::core::*;
27
28use crate::extn::prelude::*;
29
30pub(in crate::extn) mod mruby;
31
32macro_rules! ruby_exception_impl {
42 ($exc:ty) => {
43 impl From<$exc> for Error {
44 fn from(exception: $exc) -> Error {
45 let err: Box<dyn RubyException> = Box::new(exception);
46 Self::from(err)
47 }
48 }
49
50 impl RubyException for $exc {
51 fn message(&self) -> Cow<'_, [u8]> {
52 Cow::Borrowed(Self::message(self))
53 }
54
55 fn name(&self) -> Cow<'_, str> {
56 Cow::Borrowed(Self::name(self))
57 }
58
59 fn vm_backtrace(&self, interp: &mut Artichoke) -> Option<Vec<Vec<u8>>> {
60 let _ = interp;
61 None
62 }
63
64 fn as_mrb_value(&self, interp: &mut Artichoke) -> Option<sys::mrb_value> {
65 let message = interp.try_convert_mut(self.message()).ok()?;
66 let value = interp.new_instance::<Self>(&[message]).ok().flatten()?;
67 Some(value.inner())
68 }
69 }
70 };
71}
72
73ruby_exception_impl!(Exception);
74ruby_exception_impl!(NoMemoryError);
75ruby_exception_impl!(ScriptError);
76ruby_exception_impl!(LoadError);
77ruby_exception_impl!(NotImplementedError);
78ruby_exception_impl!(SyntaxError);
79ruby_exception_impl!(SecurityError);
80ruby_exception_impl!(SignalException);
81ruby_exception_impl!(Interrupt);
82ruby_exception_impl!(StandardError);
84ruby_exception_impl!(ArgumentError);
85ruby_exception_impl!(UncaughtThrowError);
86ruby_exception_impl!(EncodingError);
87ruby_exception_impl!(FiberError);
88ruby_exception_impl!(IOError);
89ruby_exception_impl!(EOFError);
90ruby_exception_impl!(IndexError);
91ruby_exception_impl!(KeyError);
92ruby_exception_impl!(StopIteration);
93ruby_exception_impl!(LocalJumpError);
94ruby_exception_impl!(NameError);
95ruby_exception_impl!(NoMethodError);
96ruby_exception_impl!(RangeError);
97ruby_exception_impl!(FloatDomainError);
98ruby_exception_impl!(RegexpError);
99ruby_exception_impl!(RuntimeError);
101ruby_exception_impl!(FrozenError);
102ruby_exception_impl!(SystemCallError);
103ruby_exception_impl!(ThreadError);
105ruby_exception_impl!(TypeError);
106ruby_exception_impl!(ZeroDivisionError);
107ruby_exception_impl!(SystemExit);
108ruby_exception_impl!(SystemStackError);
109ruby_exception_impl!(Fatal);
111
112#[cfg(test)]
113mod tests {
114 use bstr::ByteSlice;
115
116 use crate::test::prelude::*;
117
118 struct Run;
119
120 unsafe extern "C-unwind" fn run_run(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
121 unwrap_interpreter!(mrb, to => guard);
122 let exc = RuntimeError::with_message("something went wrong");
123 unsafe { error::raise(guard, exc) }
125 }
126
127 impl File for Run {
128 type Artichoke = Artichoke;
129
130 type Error = Error;
131
132 fn require(interp: &mut Artichoke) -> Result<(), Self::Error> {
133 let spec = class::Spec::new("Run", c"Run", None, None).unwrap();
134 class::Builder::for_spec(interp, &spec)
135 .add_self_method("run", run_run, sys::mrb_args_none())?
136 .define()?;
137 interp.def_class::<Self>(spec)?;
138 Ok(())
139 }
140 }
141
142 #[test]
143 fn raise() {
144 let mut interp = interpreter();
145 Run::require(&mut interp).unwrap();
146 let err = interp.eval(b"Run.run").unwrap_err();
147 assert_eq!("RuntimeError", err.name().as_ref());
148 assert_eq!(b"something went wrong".as_bstr(), err.message().as_ref().as_bstr());
149 let expected_backtrace = b"(eval):1:in run\n(eval):1".to_vec();
150 let actual_backtrace = bstr::join("\n", err.vm_backtrace(&mut interp).unwrap());
151 assert_eq!(expected_backtrace.as_bstr(), actual_backtrace.as_bstr());
152 }
153}