rb_sys/utils.rs
1//! Internal utility functions.
2
3/// Check if the Ruby VM is globally available.
4///
5/// Unfortunately there is no public API for this check, but there's a hidden
6/// `ruby_current_vm_ptr` symbol in libruby 2.5 - 3.2 which we can use to
7/// determine if the VM has been initialized, or shut down.
8///
9/// # Notes
10///
11/// Ruby 2.4 and below don't have a global VM pointer, so we can't check if it's
12/// null. Ruby 2.4 is EOL, and support will be dropped soon anyway.
13//
14/// In Ruby 3.3, the global VM pointer is no longer exported, so there's no
15/// simple way to check the global VM pointer, so instead we check if known
16/// static value is non-zero.
17///
18/// On Ruby < 3.3, we also need to check if the global VM pointer is null to
19/// ensure the VM hasn't stopped, which makes the function name a bit of a
20/// misnomer... but in actuality this function can only guarantee that the
21/// VM is started, not that it's still running.
22#[allow(dead_code)]
23pub(crate) unsafe fn is_ruby_vm_started() -> bool {
24 #[cfg(ruby_engine = "mri")]
25 let ret = {
26 #[cfg(all(ruby_gt_2_4, ruby_lte_3_2))]
27 let ret = !crate::hidden::ruby_current_vm_ptr.is_null();
28
29 #[cfg(any(ruby_lte_2_4, ruby_gt_3_2))]
30 let ret = crate::rb_cBasicObject != 0;
31
32 ret
33 };
34
35 #[cfg(ruby_engine = "truffleruby")]
36 let ret = crate::rb_cBasicObject != 0;
37
38 ret
39}
40
41/// Macro for conditionally asserting type checks in Ruby, only active when RUBY_DEBUG is enabled.
42/// This matches Ruby's behavior of only checking types in debug mode.
43#[macro_export]
44macro_rules! debug_ruby_assert_type {
45 ($obj:expr, $type:expr, $message:expr) => {
46 #[cfg(ruby_ruby_debug = "true")]
47 {
48 #[allow(clippy::macro_metavars_in_unsafe)]
49 unsafe {
50 assert!(
51 !$crate::SPECIAL_CONST_P($obj) && $crate::RB_BUILTIN_TYPE($obj) == $type,
52 $message
53 );
54 }
55 }
56 #[cfg(not(ruby_ruby_debug = "true"))]
57 {
58 let _ = ($obj, $type, $message); // Prevent unused variable warnings
59 }
60 };
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use rusty_fork::rusty_fork_test;
67
68 rusty_fork_test! {
69 #[test]
70 fn test_is_ruby_vm_started() {
71 assert!(!unsafe { is_ruby_vm_started() });
72
73 #[cfg(windows)]
74 {
75 let mut argc = 0;
76 let mut argv: [*mut std::os::raw::c_char; 0] = [];
77 let mut argv = argv.as_mut_ptr();
78 unsafe { rb_sys::rb_w32_sysinit(&mut argc, &mut argv) };
79 }
80
81 match unsafe { crate::ruby_setup() } {
82 0 => {}
83 code => panic!("Failed to setup Ruby (error code: {})", code),
84 };
85
86 assert!(unsafe { is_ruby_vm_started() });
87 }
88 }
89}