artichoke_backend/extn/core/env/
mruby.rs

1//! FFI glue between the Rust trampolines and the mruby C interpreter.
2
3use std::ffi::CStr;
4
5use crate::extn::core::artichoke;
6use crate::extn::core::env::{self, trampoline};
7use crate::extn::prelude::*;
8
9const ENVIRON_CSTR: &CStr = c"Environ";
10static ENV_RUBY_SOURCE: &[u8] = include_bytes!("env.rb");
11
12pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
13    if interp.is_class_defined::<env::Environ>() {
14        return Ok(());
15    }
16
17    let scope = interp
18        .module_spec::<artichoke::Artichoke>()?
19        .map(EnclosingRubyScope::module)
20        .ok_or_else(|| NotDefinedError::module("Artichoke"))?;
21    let spec = class::Spec::new(
22        "Environ",
23        ENVIRON_CSTR,
24        Some(scope),
25        Some(def::box_unbox_free::<env::Environ>),
26    )?;
27    class::Builder::for_spec(interp, &spec)
28        .value_is_rust_object()
29        .add_method("[]", env_element_reference, sys::mrb_args_req(1))?
30        .add_method("[]=", env_element_assignment, sys::mrb_args_req(2))?
31        .add_method("initialize", env_initialize, sys::mrb_args_none())?
32        .add_method("to_h", env_to_h, sys::mrb_args_none())?
33        .define()?;
34    interp.def_class::<env::Environ>(spec)?;
35    interp.eval(ENV_RUBY_SOURCE)?;
36
37    Ok(())
38}
39
40unsafe extern "C-unwind" fn env_initialize(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
41    mrb_get_args!(mrb, none);
42    unwrap_interpreter!(mrb, to => guard);
43    let slf = Value::from(slf);
44    let result = trampoline::initialize(&mut guard, slf);
45    match result {
46        Ok(value) => value.inner(),
47        Err(exception) => {
48            // SAFETY: only Copy objects remain on the stack
49            unsafe { error::raise(guard, exception) }
50        }
51    }
52}
53
54unsafe extern "C-unwind" fn env_element_reference(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
55    let name = mrb_get_args!(mrb, required = 1);
56    unwrap_interpreter!(mrb, to => guard);
57    let obj = Value::from(slf);
58    let name = Value::from(name);
59    let result = trampoline::element_reference(&mut guard, obj, name);
60    match result {
61        Ok(value) => value.inner(),
62        Err(exception) => {
63            // SAFETY: only Copy objects remain on the stack
64            unsafe { error::raise(guard, exception) }
65        }
66    }
67}
68
69unsafe extern "C-unwind" fn env_element_assignment(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
70    let (name, value) = mrb_get_args!(mrb, required = 2);
71    unwrap_interpreter!(mrb, to => guard);
72    let obj = Value::from(slf);
73    let name = Value::from(name);
74    let value = Value::from(value);
75    let result = trampoline::element_assignment(&mut guard, obj, name, value);
76    match result {
77        Ok(value) => value.inner(),
78        Err(exception) => {
79            // SAFETY: only Copy objects remain on the stack
80            unsafe { error::raise(guard, exception) }
81        }
82    }
83}
84
85unsafe extern "C-unwind" fn env_to_h(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
86    mrb_get_args!(mrb, none);
87    unwrap_interpreter!(mrb, to => guard);
88    let obj = Value::from(slf);
89    let result = trampoline::to_h(&mut guard, obj);
90    match result {
91        Ok(value) => value.inner(),
92        Err(exception) => {
93            // SAFETY: only Copy objects remain on the stack
94            unsafe { error::raise(guard, exception) }
95        }
96    }
97}