extern crate libloading as libl;
use std::collections::HashMap;
use std::ffi::CString;
use std::io;
use std::os::raw::{c_char, c_int, c_uint, c_void};
fn to_c_str<T: Into<Vec<u8>>>(t: T) -> *const c_char {
CString::new(t).unwrap().as_ptr() as *const c_char
}
type CoreClrInitializeFn = unsafe extern fn(
*const c_char,
*const c_char,
c_int,
*const *const c_char,
*const *const c_char,
*const *const c_void,
*const c_uint) -> c_int;
type CoreClrShutdownFn = unsafe extern fn(*const c_void, c_uint) -> c_int;
type CoreClrShutdown2Fn = unsafe extern fn(*const c_void, c_uint, *const c_int) -> c_int;
type CoreClrCreateDelegateFn = unsafe extern fn(
*const c_void,
c_uint,
*const c_char,
*const c_char,
*const c_char,
*const *const c_void) -> c_int;
pub struct UnixCoreClr {
host_handle: *const c_void,
domain_id: c_uint
}
impl UnixCoreClr {
fn library() -> libl::Result<libl::Library> {
libl::Library::new("/usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/libcoreclr.dylib")
}
pub fn init(
exe_path: &str,
app_domain_friendly_name: &str,
properties_option: Option<HashMap<&str, &str>>) -> libl::Result<UnixCoreClr>
{
let host_handle = 0 as *const c_void;
let host_handle_ref = &host_handle as *const *const c_void;
let domain_id = 0 as c_uint;
let domain_id_ref = &domain_id as *const c_uint;
let exe_path_raw = to_c_str(exe_path);
let app_domain_friendly_name_raw = to_c_str(app_domain_friendly_name);
let properties = properties_option.unwrap_or_else(HashMap::new);
let properties_count = properties.len() as c_int;
let properties_keys: Vec<*const c_char> = properties.keys()
.map(|&k| to_c_str(k))
.collect();
let properties_values: Vec<*const c_char> = properties.values()
.map(|&v| to_c_str(v))
.collect();
let properties_keys_ref = properties_keys.as_ptr();
let properties_values_ref = properties_values.as_ptr();
unsafe {
let coreclr_library = UnixCoreClr::library()?;
let coreclr_initialize: libl::Symbol<CoreClrInitializeFn> = coreclr_library.get(b"coreclr_initialize")?;
match coreclr_initialize(
exe_path_raw,
app_domain_friendly_name_raw,
properties_count,
properties_keys_ref,
properties_values_ref,
host_handle_ref,
domain_id_ref)
{
0 => Ok(UnixCoreClr {
host_handle: host_handle,
domain_id: domain_id
}),
code => panic!("Failed to initialize ({:X}). Host handle: {:?}, domain id: {:?}.", code, host_handle, domain_id)
}
}
}
pub fn shutdown(self: Self) -> io::Result<()> {
unsafe {
let coreclr_library = UnixCoreClr::library()?;
let coreclr_shutdown: libl::Symbol<CoreClrShutdownFn> = coreclr_library.get(b"coreclr_shutdown")?;
match coreclr_shutdown(self.host_handle, self.domain_id) {
0 => Ok(()),
_ => panic!("Failed to shutdown")
}
}
}
pub fn shutdown_2(self: Self) -> io::Result<c_int> {
let latched_exit_code = -1 as c_int;
let latched_exit_code_ref = &latched_exit_code as *const c_int;
unsafe {
let coreclr_library = UnixCoreClr::library()?;
let coreclr_shutdown_2: libl::Symbol<CoreClrShutdown2Fn> = coreclr_library.get(b"coreclr_shutdown_2")?;
match coreclr_shutdown_2(self.host_handle, self.domain_id, latched_exit_code_ref) {
0 => Ok(latched_exit_code),
_ => panic!("Failed to shutdown")
}
}
}
pub fn create_raw_delegate(
self: &Self,
entry_point_assembly_name: &str,
entry_point_type_name: &str,
entry_point_method_name: &str) -> io::Result<*const c_void>
{
let coreclr_delegate = 0 as *const c_void;
let coreclr_delegate_ref = &coreclr_delegate as *const *const c_void;
unsafe {
let coreclr_library = UnixCoreClr::library()?;
let coreclr_create_delegate: libl::Symbol<CoreClrCreateDelegateFn> = coreclr_library.get(b"coreclr_create_delegate")?;
match coreclr_create_delegate(
self.host_handle,
self.domain_id,
to_c_str(entry_point_assembly_name),
to_c_str(entry_point_type_name),
to_c_str(entry_point_method_name),
coreclr_delegate_ref)
{
0 => Ok(coreclr_delegate),
_ => panic!("Failed to shutdown")
}
}
}
}