use std::cell::RefCell;
use std::ffi::{CStr, CString, NulError};
use std::os::raw::{c_char, c_int};
use std::ptr::null;
use std::slice;
thread_local! {
static BYOND_RETURN: RefCell<Option<CString>> = {
RefCell::new(None)
};
}
pub fn return_to_byond<T: AsRef<[u8]>>(string: T) -> Result<*const c_char, NulError> {
let cstr = CString::new(string.as_ref())?;
let ptr = cstr.as_ptr();
BYOND_RETURN.with(|f| {
*f.borrow_mut() = Some(cstr);
});
Ok(ptr)
}
pub unsafe fn from_byond_args(n: c_int, v: *const *const c_char) -> Vec<String> {
let mut args = Vec::new();
let slice = slice::from_raw_parts(v, n as usize);
for ptr in slice {
let cstr = CStr::from_ptr(*ptr);
let string = String::from_utf8_lossy(cstr.to_bytes()).into_owned();
args.push(string);
}
args
}
pub fn test_byond_call(
func: unsafe extern "C" fn(i32, *const *const c_char) -> *const c_char,
) -> String {
unsafe {
let ptr = func(0, null());
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
pub fn test_byond_call_args<P>(
func: unsafe extern "C" fn(i32, *const *const c_char) -> *const c_char,
args: &[P],
) -> String
where
P: AsRef<[u8]>,
{
let mut cstrs = Vec::with_capacity(args.len());
let mut ptrs = Vec::with_capacity(args.len());
for arg in args {
let arg = arg.as_ref();
let cstr = CString::new(arg).unwrap();
let ptr = cstr.as_ptr();
cstrs.push(cstr);
ptrs.push(ptr);
}
unsafe {
let ptr = func(ptrs.len() as i32, ptrs.as_slice().as_ptr());
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}