Skip to content

Commit

Permalink
add embed::setup to expose minimal setup
Browse files Browse the repository at this point in the history
setup may work in some cases where init doesn't
  • Loading branch information
matsadler committed Feb 9, 2023
1 parent 2c20249 commit 52eeaad
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 26 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
- `Value::funcall_public` calls a public method, returning an error for a
private or protected method.
- `error::Result<T>` is shorthand for `std::result::Result<T, Error>`.
- `embed::setup` to perform minimal initialisation of Ruby for environments
where `embed::init` doesn't work.

### Changed
- When converting Ruby values to `RArray` (or `Vec<T>`, `[T; 1]`, or `(T,)`),
Expand Down
82 changes: 57 additions & 25 deletions src/embed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ impl Drop for Cleanup {
}
}

/// Initialises the Ruby VM.
/// Performs basic initialisation of the Ruby VM.
///
/// This only initialises the core of Ruby's functionality, some features may
/// be missing or not work as expected. Generally [`init`] should be preferred,
/// but there may be some cases where it is not possible to run the full Ruby
/// initialisation sequence.
///
/// Calling this function is only required when embedding Ruby in Rust. It is
/// not required when embedding Rust in Ruby, e.g. in a Ruby Gem.
Expand All @@ -38,20 +43,15 @@ impl Drop for Cleanup {
///
/// # Panics
///
/// Panics if called more than once.
/// Panics if this or [`init`] are collectively called more than once.
///
/// # Examples
///
/// ```
/// let _cleanup = unsafe { magnus::embed::init() };
/// ```
#[inline(always)]
pub unsafe fn init() -> Cleanup {
init_options(&["-e", ""])
}

#[inline(always)]
unsafe fn init_options(opts: &[&str]) -> Cleanup {
pub unsafe fn setup() -> Cleanup {
static INIT: AtomicBool = AtomicBool::new(false);
match INIT.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) {
Ok(false) => {
Expand All @@ -66,29 +66,61 @@ unsafe fn init_options(opts: &[&str]) -> Cleanup {
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 mut node = 0 as _;
protect(|| {
node = ruby_process_options(argv.len() as i32, argv.as_mut_ptr());
QNIL
})
.unwrap();
if ruby_exec_node(node) != 0 {
panic!("Ruby init code failed");
};
cleanup
Cleanup()
}
Err(true) => panic!("Ruby already initialized"),
r => panic!("unexpected INIT state {:?}", r),
}
}

/// Initialises the Ruby VM.
///
/// See also [`setup`].
///
/// Calling this function is only required when embedding Ruby in Rust. It is
/// not required when embedding Rust in Ruby, e.g. in a Ruby Gem.
///
/// # Safety
///
/// Must be called in `main()`, or at least a function higher up the stack than
/// any code calling Ruby. Must not drop Cleanup until the very end of the
/// process, after all Ruby execution has finished.
///
/// # Panics
///
/// Panics if this or [`setup`] are collectively called more than once.
///
/// # Examples
///
/// ```
/// let _cleanup = unsafe { magnus::embed::init() };
/// ```
#[inline(always)]
pub unsafe fn init() -> Cleanup {
let cleanup = setup();
init_options(&["-e", ""]);
cleanup
}

#[inline(always)]
unsafe fn init_options(opts: &[&str]) {
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 mut node = 0 as _;
protect(|| {
node = ruby_process_options(argv.len() as i32, argv.as_mut_ptr());
QNIL
})
.unwrap();
if ruby_exec_node(node) != 0 {
panic!("Ruby init code failed");
};
}

impl RubyHandle {
pub fn script<T>(&self, name: T)
where
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1765,7 +1765,7 @@
// * `ruby_scan_oct`:
//! * `ruby_script`: Similar to [`embed::ruby_script`].
// * `ruby_setenv`:
//! * `ruby_setup`: See [`embed::init`].
//! * `ruby_setup`: [`embed::setup`].
// * `ruby_set_argv`:
//! * `ruby_set_script_name`: [`embed::ruby_script`].
// * `ruby_show_copyright`:
Expand Down

0 comments on commit 52eeaad

Please sign in to comment.