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
use std::{
ffi::CString,
sync::atomic::{AtomicBool, Ordering},
};
#[cfg(windows)]
use rb_sys::rb_w32_sysinit;
use rb_sys::{
ruby_cleanup, ruby_exec_node, ruby_executable_node, ruby_options, ruby_set_script_name,
ruby_setup,
};
use crate::r_string::RString;
pub struct Cleanup();
impl Drop for Cleanup {
fn drop(&mut self) {
unsafe {
ruby_cleanup(0);
}
}
}
#[inline(always)]
pub unsafe fn init() -> Cleanup {
init_options(&["-e", ""])
}
#[inline(always)]
unsafe fn init_options(opts: &[&str]) -> Cleanup {
static INIT: AtomicBool = AtomicBool::new(false);
match INIT.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) {
Ok(false) => {
#[cfg(windows)]
{
let mut argc = 0;
let mut argv: [*mut std::os::raw::c_char; 0] = [];
let mut argv = argv.as_mut_ptr();
rb_w32_sysinit(&mut argc, &mut argv);
}
if ruby_setup() != 0 {
panic!("Failed to setup Ruby");
};
let cleanup = Cleanup();
let mut argv = vec![CString::new("ruby").unwrap()];
argv.extend(opts.iter().map(|s| CString::new(*s).unwrap()));
let mut argv = argv
.iter()
.map(|cs| cs.as_ptr() as *mut _)
.collect::<Vec<_>>();
let node = ruby_options(argv.len() as i32, argv.as_mut_ptr());
let mut status = 0;
if ruby_executable_node(node, &mut status) == 0 {
panic!("Ruby init code not executable");
}
if ruby_exec_node(node) != 0 {
panic!("Ruby init code failed");
};
cleanup
}
Err(true) => panic!("Ruby already initialized"),
r => panic!("unexpected INIT state {:?}", r),
}
}
pub fn ruby_script<T>(name: T)
where
T: Into<RString>,
{
let name = name.into();
unsafe { ruby_set_script_name(name.as_rb_value()) };
}