artichoke_backend/extn/core/kernel/
mruby.rs

1use std::ffi::CStr;
2
3use crate::extn::core::artichoke;
4use crate::extn::core::kernel::{self, trampoline};
5use crate::extn::prelude::*;
6
7const KERNEL_CSTR: &CStr = c"Kernel";
8static KERNEL_RUBY_SOURCE: &[u8] = include_bytes!("kernel.rb");
9
10pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
11    if interp.is_module_defined::<kernel::Kernel>() {
12        return Ok(());
13    }
14
15    let spec = module::Spec::new(interp, "Kernel", KERNEL_CSTR, None)?;
16    module::Builder::for_spec(interp, &spec)
17        .add_method("require", kernel_require, sys::mrb_args_rest())?
18        .add_method("require_relative", kernel_require_relative, sys::mrb_args_rest())?
19        .add_method("load", kernel_load, sys::mrb_args_rest())?
20        .add_method("p", kernel_p, sys::mrb_args_rest())?
21        .add_method("print", kernel_print, sys::mrb_args_rest())?
22        .add_method("puts", kernel_puts, sys::mrb_args_rest())?
23        .define()?;
24    interp.def_module::<kernel::Kernel>(spec)?;
25    interp.eval(KERNEL_RUBY_SOURCE)?;
26
27    // Some `Kernel` functions are implemented with methods in the
28    // `Artichoke::Kernel` module. These functions are delegated to by Ruby
29    // implementations of the `Kernel` methods that marshal arguments and handle
30    // exceptions.
31    let scope = interp
32        .module_spec::<artichoke::Artichoke>()?
33        .map(EnclosingRubyScope::module)
34        .ok_or_else(|| NotDefinedError::module("Artichoke"))?;
35    let spec = module::Spec::new(interp, "Kernel", KERNEL_CSTR, Some(scope))?;
36    module::Builder::for_spec(interp, &spec)
37        .add_method("Integer", kernel_integer, sys::mrb_args_req_and_opt(1, 1))?
38        .add_self_method("Integer", kernel_integer, sys::mrb_args_req_and_opt(1, 1))?
39        .define()?;
40    interp.def_module::<artichoke::Kernel>(spec)?;
41
42    Ok(())
43}
44
45unsafe extern "C-unwind" fn kernel_integer(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
46    let (arg, base) = mrb_get_args!(mrb, required = 1, optional = 1);
47    unwrap_interpreter!(mrb, to => guard);
48    let arg = Value::from(arg);
49    let base = base.map(Value::from);
50    let result = trampoline::integer(&mut guard, arg, base);
51    match result {
52        Ok(value) => value.inner(),
53        Err(exception) => {
54            // SAFETY: only Copy objects remain on the stack
55            unsafe { error::raise(guard, exception) }
56        }
57    }
58}
59
60unsafe extern "C-unwind" fn kernel_load(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
61    let file = mrb_get_args!(mrb, required = 1);
62    unwrap_interpreter!(mrb, to => guard);
63    let file = Value::from(file);
64    let result = trampoline::load(&mut guard, file);
65    match result {
66        Ok(value) => value.inner(),
67        Err(exception) => {
68            // SAFETY: only Copy objects remain on the stack
69            unsafe { error::raise(guard, exception) }
70        }
71    }
72}
73
74unsafe extern "C-unwind" fn kernel_p(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
75    let args = mrb_get_args!(mrb, *args);
76    unwrap_interpreter!(mrb, to => guard);
77    let args = args.iter().copied().map(Value::from);
78    let result = trampoline::p(&mut guard, args);
79    match result {
80        Ok(value) => value.inner(),
81        Err(exception) => {
82            // SAFETY: only Copy objects remain on the stack
83            unsafe { error::raise(guard, exception) }
84        }
85    }
86}
87
88unsafe extern "C-unwind" fn kernel_print(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
89    let args = mrb_get_args!(mrb, *args);
90    unwrap_interpreter!(mrb, to => guard);
91    let args = args.iter().copied().map(Value::from);
92    let result = trampoline::print(&mut guard, args);
93    match result {
94        Ok(value) => value.inner(),
95        Err(exception) => {
96            // SAFETY: only Copy objects remain on the stack
97            unsafe { error::raise(guard, exception) }
98        }
99    }
100}
101
102unsafe extern "C-unwind" fn kernel_puts(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
103    let args = mrb_get_args!(mrb, *args);
104    unwrap_interpreter!(mrb, to => guard);
105    let args = args.iter().copied().map(Value::from);
106    let result = trampoline::puts(&mut guard, args);
107    match result {
108        Ok(value) => value.inner(),
109        Err(exception) => {
110            // SAFETY: only Copy objects remain on the stack
111            unsafe { error::raise(guard, exception) }
112        }
113    }
114}
115
116unsafe extern "C-unwind" fn kernel_require(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
117    let file = mrb_get_args!(mrb, required = 1);
118    unwrap_interpreter!(mrb, to => guard);
119    let file = Value::from(file);
120    let result = trampoline::require(&mut guard, file);
121    match result {
122        Ok(value) => value.inner(),
123        Err(exception) => {
124            // SAFETY: only Copy objects remain on the stack
125            unsafe { error::raise(guard, exception) }
126        }
127    }
128}
129
130unsafe extern "C-unwind" fn kernel_require_relative(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
131    let file = mrb_get_args!(mrb, required = 1);
132    unwrap_interpreter!(mrb, to => guard);
133    let file = Value::from(file);
134    let result = trampoline::require_relative(&mut guard, file);
135    match result {
136        Ok(value) => value.inner(),
137        Err(exception) => {
138            // SAFETY: only Copy objects remain on the stack
139            unsafe { error::raise(guard, exception) }
140        }
141    }
142}