1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::borrow::Cow;
use std::error;
use std::ffi::c_void;
use std::fmt;
use spinoso_exception::Fatal;
use crate::core::{ClassRegistry, Eval, TryConvertMut};
use crate::error::{Error, RubyException};
use crate::extn;
use crate::ffi;
use crate::gc::{MrbGarbageCollection, State as GcState};
use crate::release_metadata::ReleaseMetadata;
use crate::state::State;
use crate::sys;
use crate::Artichoke;
pub fn interpreter() -> Result<Artichoke, Error> {
let release_meta = ReleaseMetadata::new();
interpreter_with_config(release_meta)
}
pub fn interpreter_with_config(config: ReleaseMetadata<'_>) -> Result<Artichoke, Error> {
let state = State::new()?;
let state = Box::new(state);
let alloc_ud = Box::into_raw(state).cast::<c_void>();
let raw = unsafe { sys::mrb_open_allocf(Some(sys::mrb_default_allocf), alloc_ud) };
let mut interp = unsafe { ffi::from_user_data(raw).map_err(|_| InterpreterAllocError::new())? };
if let Some(ref mut state) = interp.state {
if let Some(mrb) = unsafe { raw.as_mut() } {
state.try_init_parser(mrb);
}
}
let prior_gc_state = interp.disable_gc()?;
extn::init(&mut interp, config)?;
let mut arena = interp.create_arena_savepoint()?;
unsafe {
arena.interp().with_ffi_boundary(|mrb| sys::mrb_init_mrbgems(mrb))?;
}
arena.restore();
interp.create_arena_savepoint()?.interp().eval(&[])?;
if let GcState::Enabled = prior_gc_state {
interp.enable_gc()?;
interp.full_gc()?;
}
Ok(interp)
}
#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct InterpreterAllocError {
_private: (),
}
impl InterpreterAllocError {
#[must_use]
pub const fn new() -> Self {
Self { _private: () }
}
}
impl fmt::Display for InterpreterAllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Failed to allocate Artichoke interpreter")
}
}
impl error::Error for InterpreterAllocError {}
impl RubyException for InterpreterAllocError {
fn message(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(b"Failed to allocate Artichoke Ruby interpreter")
}
fn name(&self) -> Cow<'_, str> {
"fatal".into()
}
fn vm_backtrace(&self, interp: &mut Artichoke) -> Option<Vec<Vec<u8>>> {
let _ = interp;
None
}
fn as_mrb_value(&self, interp: &mut Artichoke) -> Option<sys::mrb_value> {
let message = interp.try_convert_mut(self.message()).ok()?;
let value = interp.new_instance::<Fatal>(&[message]).ok().flatten()?;
Some(value.inner())
}
}
impl From<InterpreterAllocError> for Error {
fn from(exception: InterpreterAllocError) -> Self {
let err: Box<dyn RubyException> = Box::new(exception);
Self::from(err)
}
}
#[cfg(test)]
mod tests {
#[test]
fn open_close() {
let interp = super::interpreter().unwrap();
interp.close();
}
}