artichoke_backend/extn/stdlib/securerandom/
mruby.rs

1//! FFI glue between the Rust trampolines and the mruby C interpreter.
2
3use std::ffi::CStr;
4
5use crate::extn::prelude::*;
6use crate::extn::stdlib::securerandom::{self, trampoline};
7
8const SECURE_RANDOM_CSTR: &CStr = c"SecureRandom";
9
10pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
11    interp.def_file_for_type::<_, SecureRandomFile>("securerandom.rb")?;
12    Ok(())
13}
14
15#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
16struct SecureRandomFile {
17    // Ensure this type is not constructable
18    _private: (),
19}
20
21impl File for SecureRandomFile {
22    type Artichoke = Artichoke;
23    type Error = Error;
24
25    fn require(interp: &mut Self::Artichoke) -> Result<(), Self::Error> {
26        if interp.is_module_defined::<securerandom::SecureRandom>() {
27            return Ok(());
28        }
29
30        let spec = module::Spec::new(interp, "SecureRandom", SECURE_RANDOM_CSTR, None)?;
31        module::Builder::for_spec(interp, &spec)
32            .add_self_method("alphanumeric", securerandom_alphanumeric, sys::mrb_args_opt(1))?
33            .add_self_method("base64", securerandom_base64, sys::mrb_args_opt(1))?
34            .add_self_method("urlsafe_base64", securerandom_urlsafe_base64, sys::mrb_args_opt(2))?
35            .add_self_method("hex", securerandom_hex, sys::mrb_args_opt(1))?
36            .add_self_method("random_bytes", securerandom_random_bytes, sys::mrb_args_opt(1))?
37            .add_self_method("random_number", securerandom_random_number, sys::mrb_args_opt(1))?
38            .add_self_method("uuid", securerandom_uuid, sys::mrb_args_none())?
39            .define()?;
40        interp.def_module::<securerandom::SecureRandom>(spec)?;
41
42        Ok(())
43    }
44}
45
46unsafe extern "C-unwind" fn securerandom_alphanumeric(
47    mrb: *mut sys::mrb_state,
48    _slf: sys::mrb_value,
49) -> sys::mrb_value {
50    let len = mrb_get_args!(mrb, optional = 1);
51    unwrap_interpreter!(mrb, to => guard);
52    let len = len.map(Value::from).and_then(|len| guard.convert(len));
53    let result = trampoline::alphanumeric(&mut guard, len);
54    match result {
55        Ok(value) => value.inner(),
56        Err(exception) => {
57            // SAFETY: only Copy objects remain on the stack
58            unsafe { error::raise(guard, exception) }
59        }
60    }
61}
62
63unsafe extern "C-unwind" fn securerandom_base64(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
64    let len = mrb_get_args!(mrb, optional = 1);
65    unwrap_interpreter!(mrb, to => guard);
66    let len = len.map(Value::from).and_then(|len| guard.convert(len));
67    let result = trampoline::base64(&mut guard, len);
68    match result {
69        Ok(value) => value.inner(),
70        Err(exception) => {
71            // SAFETY: only Copy objects remain on the stack
72            unsafe { error::raise(guard, exception) }
73        }
74    }
75}
76
77unsafe extern "C-unwind" fn securerandom_urlsafe_base64(
78    mrb: *mut sys::mrb_state,
79    _slf: sys::mrb_value,
80) -> sys::mrb_value {
81    let (len, padding) = mrb_get_args!(mrb, optional = 2);
82    unwrap_interpreter!(mrb, to => guard);
83    let len = len.map(Value::from).and_then(|len| guard.convert(len));
84    let padding = padding.map(Value::from).and_then(|padding| guard.convert(padding));
85    let result = trampoline::urlsafe_base64(&mut guard, len, padding);
86    match result {
87        Ok(value) => value.inner(),
88        Err(exception) => {
89            // SAFETY: only Copy objects remain on the stack
90            unsafe { error::raise(guard, exception) }
91        }
92    }
93}
94
95unsafe extern "C-unwind" fn securerandom_hex(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
96    let len = mrb_get_args!(mrb, optional = 1);
97    unwrap_interpreter!(mrb, to => guard);
98    let len = len.map(Value::from).and_then(|len| guard.convert(len));
99    let result = trampoline::hex(&mut guard, len);
100    match result {
101        Ok(value) => value.inner(),
102        Err(exception) => {
103            // SAFETY: only Copy objects remain on the stack
104            unsafe { error::raise(guard, exception) }
105        }
106    }
107}
108
109unsafe extern "C-unwind" fn securerandom_random_bytes(
110    mrb: *mut sys::mrb_state,
111    _slf: sys::mrb_value,
112) -> sys::mrb_value {
113    let len = mrb_get_args!(mrb, optional = 1);
114    unwrap_interpreter!(mrb, to => guard);
115    let len = len.map(Value::from).and_then(|len| guard.convert(len));
116    let result = trampoline::random_bytes(&mut guard, len);
117    match result {
118        Ok(value) => value.inner(),
119        Err(exception) => {
120            // SAFETY: only Copy objects remain on the stack
121            unsafe { error::raise(guard, exception) }
122        }
123    }
124}
125
126unsafe extern "C-unwind" fn securerandom_random_number(
127    mrb: *mut sys::mrb_state,
128    _slf: sys::mrb_value,
129) -> sys::mrb_value {
130    let max = mrb_get_args!(mrb, optional = 1);
131    unwrap_interpreter!(mrb, to => guard);
132    let max = max.map(Value::from).and_then(|max| guard.convert(max));
133    let result = trampoline::random_number(&mut guard, max);
134    match result {
135        Ok(value) => value.inner(),
136        Err(exception) => {
137            // SAFETY: only Copy objects remain on the stack
138            unsafe { error::raise(guard, exception) }
139        }
140    }
141}
142
143unsafe extern "C-unwind" fn securerandom_uuid(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
144    mrb_get_args!(mrb, none);
145    unwrap_interpreter!(mrb, to => guard);
146    let result = trampoline::uuid(&mut guard);
147    match result {
148        Ok(value) => value.inner(),
149        Err(exception) => {
150            // SAFETY: only Copy objects remain on the stack
151            unsafe { error::raise(guard, exception) }
152        }
153    }
154}