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
//! FFI glue between the Rust trampolines and the mruby C interpreter.

use std::ffi::CStr;

use crate::extn::prelude::*;
use crate::extn::stdlib::securerandom::{self, trampoline};

const SECURE_RANDOM_CSTR: &CStr = qed::const_cstr_from_str!("SecureRandom\0");

pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
    interp.def_file_for_type::<_, SecureRandomFile>("securerandom.rb")?;
    Ok(())
}

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct SecureRandomFile {
    // Ensure this type is not constructable
    _private: (),
}

impl File for SecureRandomFile {
    type Artichoke = Artichoke;
    type Error = Error;

    fn require(interp: &mut Self::Artichoke) -> Result<(), Self::Error> {
        if interp.is_module_defined::<securerandom::SecureRandom>() {
            return Ok(());
        }

        let spec = module::Spec::new(interp, "SecureRandom", SECURE_RANDOM_CSTR, None)?;
        module::Builder::for_spec(interp, &spec)
            .add_self_method("alphanumeric", securerandom_alphanumeric, sys::mrb_args_opt(1))?
            .add_self_method("base64", securerandom_base64, sys::mrb_args_opt(1))?
            .add_self_method("urlsafe_base64", securerandom_urlsafe_base64, sys::mrb_args_opt(2))?
            .add_self_method("hex", securerandom_hex, sys::mrb_args_opt(1))?
            .add_self_method("random_bytes", securerandom_random_bytes, sys::mrb_args_opt(1))?
            .add_self_method("random_number", securerandom_random_number, sys::mrb_args_opt(1))?
            .add_self_method("uuid", securerandom_uuid, sys::mrb_args_none())?
            .define()?;
        interp.def_module::<securerandom::SecureRandom>(spec)?;

        Ok(())
    }
}

unsafe extern "C" fn securerandom_alphanumeric(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let len = mrb_get_args!(mrb, optional = 1);
    unwrap_interpreter!(mrb, to => guard);
    let len = len.map(Value::from).and_then(|len| guard.convert(len));
    let result = trampoline::alphanumeric(&mut guard, len);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_base64(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let len = mrb_get_args!(mrb, optional = 1);
    unwrap_interpreter!(mrb, to => guard);
    let len = len.map(Value::from).and_then(|len| guard.convert(len));
    let result = trampoline::base64(&mut guard, len);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_urlsafe_base64(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let (len, padding) = mrb_get_args!(mrb, optional = 2);
    unwrap_interpreter!(mrb, to => guard);
    let len = len.map(Value::from).and_then(|len| guard.convert(len));
    let padding = padding.map(Value::from).and_then(|padding| guard.convert(padding));
    let result = trampoline::urlsafe_base64(&mut guard, len, padding);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_hex(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let len = mrb_get_args!(mrb, optional = 1);
    unwrap_interpreter!(mrb, to => guard);
    let len = len.map(Value::from).and_then(|len| guard.convert(len));
    let result = trampoline::hex(&mut guard, len);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_random_bytes(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let len = mrb_get_args!(mrb, optional = 1);
    unwrap_interpreter!(mrb, to => guard);
    let len = len.map(Value::from).and_then(|len| guard.convert(len));
    let result = trampoline::random_bytes(&mut guard, len);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_random_number(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    let max = mrb_get_args!(mrb, optional = 1);
    unwrap_interpreter!(mrb, to => guard);
    let max = max.map(Value::from).and_then(|max| guard.convert(max));
    let result = trampoline::random_number(&mut guard, max);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}

unsafe extern "C" fn securerandom_uuid(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
    mrb_get_args!(mrb, none);
    unwrap_interpreter!(mrb, to => guard);
    let result = trampoline::uuid(&mut guard);
    match result {
        Ok(value) => value.inner(),
        Err(exception) => error::raise(guard, exception),
    }
}