1 use std::{ffi::CString, os::raw::c_void}; 2 3 use thiserror::Error; 4 5 use crate::{ 6 sys::{JavaVMInitArgs, JavaVMOption}, 7 JNIVersion, 8 }; 9 10 /// Errors that can occur when invoking a [`JavaVM`](super::vm::JavaVM) with the 11 /// [Invocation API](https://docs.oracle.com/en/java/javase/12/docs/specs/jni/invocation.html). 12 #[derive(Debug, Error)] 13 pub enum JvmError { 14 /// An internal `0` byte was found when constructing a string. 15 #[error("internal null in option: {0}")] 16 NullOptString(String), 17 } 18 19 /// Builder for JavaVM InitArgs. 20 /// 21 /// *This API requires "invocation" feature to be enabled, 22 /// see ["Launching JVM from Rust"](struct.JavaVM.html#launching-jvm-from-rust).* 23 #[derive(Debug)] 24 pub struct InitArgsBuilder { 25 opts: Vec<String>, 26 ignore_unrecognized: bool, 27 version: JNIVersion, 28 } 29 30 impl Default for InitArgsBuilder { default() -> Self31 fn default() -> Self { 32 InitArgsBuilder { 33 opts: vec![], 34 ignore_unrecognized: false, 35 version: JNIVersion::V8, 36 } 37 } 38 } 39 40 impl InitArgsBuilder { 41 /// Create a new default InitArgsBuilder new() -> Self42 pub fn new() -> Self { 43 Default::default() 44 } 45 46 /// Add an option to the init args 47 /// 48 /// The `vfprintf`, `abort`, and `exit` options are unsupported at this time. option(self, opt_string: &str) -> Self49 pub fn option(self, opt_string: &str) -> Self { 50 let mut s = self; 51 52 match opt_string { 53 "vfprintf" | "abort" | "exit" => return s, 54 _ => {} 55 } 56 57 s.opts.push(opt_string.into()); 58 59 s 60 } 61 62 /// Set JNI version for the init args 63 /// 64 /// Default: V8 version(self, version: JNIVersion) -> Self65 pub fn version(self, version: JNIVersion) -> Self { 66 let mut s = self; 67 s.version = version; 68 s 69 } 70 71 /// Set the `ignoreUnrecognized` init arg flag 72 /// 73 /// If ignoreUnrecognized is true, JavaVM::new ignores all unrecognized option strings that 74 /// begin with "-X" or "_". If ignoreUnrecognized is false, JavaVM::new returns Err as soon as 75 /// it encounters any unrecognized option strings. 76 /// 77 /// Default: `false` ignore_unrecognized(self, ignore: bool) -> Self78 pub fn ignore_unrecognized(self, ignore: bool) -> Self { 79 let mut s = self; 80 s.ignore_unrecognized = ignore; 81 s 82 } 83 84 /// Build the `InitArgs` 85 /// 86 /// This will check for internal nulls in the option strings and will return 87 /// an error if one is found. build(self) -> Result<InitArgs, JvmError>88 pub fn build(self) -> Result<InitArgs, JvmError> { 89 let mut opts = Vec::with_capacity(self.opts.len()); 90 for opt in self.opts { 91 let option_string = 92 CString::new(opt.as_str()).map_err(|_| JvmError::NullOptString(opt))?; 93 let jvm_opt = JavaVMOption { 94 optionString: option_string.into_raw(), 95 extraInfo: ::std::ptr::null_mut(), 96 }; 97 opts.push(jvm_opt); 98 } 99 100 Ok(InitArgs { 101 inner: JavaVMInitArgs { 102 version: self.version.into(), 103 ignoreUnrecognized: self.ignore_unrecognized as _, 104 options: opts.as_ptr() as _, 105 nOptions: opts.len() as _, 106 }, 107 opts, 108 }) 109 } 110 111 /// Returns collected options options(&self) -> Vec<String>112 pub fn options(&self) -> Vec<String> { 113 self.opts.clone() 114 } 115 } 116 117 /// JavaVM InitArgs. 118 /// 119 /// *This API requires "invocation" feature to be enabled, 120 /// see ["Launching JVM from Rust"](struct.JavaVM.html#launching-jvm-from-rust).* 121 pub struct InitArgs { 122 inner: JavaVMInitArgs, 123 opts: Vec<JavaVMOption>, 124 } 125 126 impl InitArgs { inner_ptr(&self) -> *mut c_void127 pub(crate) fn inner_ptr(&self) -> *mut c_void { 128 &self.inner as *const _ as _ 129 } 130 } 131 132 impl Drop for InitArgs { drop(&mut self)133 fn drop(&mut self) { 134 for opt in self.opts.iter() { 135 unsafe { CString::from_raw(opt.optionString) }; 136 } 137 } 138 } 139