use std::{ffi::CString, os::raw::c_void}; use thiserror::Error; use crate::{ sys::{JavaVMInitArgs, JavaVMOption}, JNIVersion, }; /// Errors that can occur when invoking a [`JavaVM`](super::vm::JavaVM) with the /// [Invocation API](https://docs.oracle.com/en/java/javase/12/docs/specs/jni/invocation.html). #[derive(Debug, Error)] pub enum JvmError { /// An internal `0` byte was found when constructing a string. #[error("internal null in option: {0}")] NullOptString(String), } /// Builder for JavaVM InitArgs. /// /// *This API requires "invocation" feature to be enabled, /// see ["Launching JVM from Rust"](struct.JavaVM.html#launching-jvm-from-rust).* #[derive(Debug)] pub struct InitArgsBuilder { opts: Vec, ignore_unrecognized: bool, version: JNIVersion, } impl Default for InitArgsBuilder { fn default() -> Self { InitArgsBuilder { opts: vec![], ignore_unrecognized: false, version: JNIVersion::V8, } } } impl InitArgsBuilder { /// Create a new default InitArgsBuilder pub fn new() -> Self { Default::default() } /// Add an option to the init args /// /// The `vfprintf`, `abort`, and `exit` options are unsupported at this time. pub fn option(self, opt_string: &str) -> Self { let mut s = self; match opt_string { "vfprintf" | "abort" | "exit" => return s, _ => {} } s.opts.push(opt_string.into()); s } /// Set JNI version for the init args /// /// Default: V8 pub fn version(self, version: JNIVersion) -> Self { let mut s = self; s.version = version; s } /// Set the `ignoreUnrecognized` init arg flag /// /// If ignoreUnrecognized is true, JavaVM::new ignores all unrecognized option strings that /// begin with "-X" or "_". If ignoreUnrecognized is false, JavaVM::new returns Err as soon as /// it encounters any unrecognized option strings. /// /// Default: `false` pub fn ignore_unrecognized(self, ignore: bool) -> Self { let mut s = self; s.ignore_unrecognized = ignore; s } /// Build the `InitArgs` /// /// This will check for internal nulls in the option strings and will return /// an error if one is found. pub fn build(self) -> Result { let mut opts = Vec::with_capacity(self.opts.len()); for opt in self.opts { let option_string = CString::new(opt.as_str()).map_err(|_| JvmError::NullOptString(opt))?; let jvm_opt = JavaVMOption { optionString: option_string.into_raw(), extraInfo: ::std::ptr::null_mut(), }; opts.push(jvm_opt); } Ok(InitArgs { inner: JavaVMInitArgs { version: self.version.into(), ignoreUnrecognized: self.ignore_unrecognized as _, options: opts.as_ptr() as _, nOptions: opts.len() as _, }, opts, }) } /// Returns collected options pub fn options(&self) -> Vec { self.opts.clone() } } /// JavaVM InitArgs. /// /// *This API requires "invocation" feature to be enabled, /// see ["Launching JVM from Rust"](struct.JavaVM.html#launching-jvm-from-rust).* pub struct InitArgs { inner: JavaVMInitArgs, opts: Vec, } impl InitArgs { pub(crate) fn inner_ptr(&self) -> *mut c_void { &self.inner as *const _ as _ } } impl Drop for InitArgs { fn drop(&mut self) { for opt in self.opts.iter() { unsafe { CString::from_raw(opt.optionString) }; } } }