1use std::cell::RefCell;
3use std::ffi::{CStr, CString, NulError};
4use std::os::raw::{c_char, c_int};
5use std::ptr::null;
6use std::slice;
7
8thread_local! {
9 static BYOND_RETURN: RefCell<Option<CString>> = {
10 RefCell::new(None)
11 };
12}
13
14pub fn return_to_byond<T: AsRef<[u8]>>(string: T) -> Result<*const c_char, NulError> {
17 let cstr = CString::new(string.as_ref())?;
18 let ptr = cstr.as_ptr();
19
20 BYOND_RETURN.with(|f| {
21 *f.borrow_mut() = Some(cstr);
22 });
23
24 Ok(ptr)
25}
26
27pub unsafe fn from_byond_args(n: c_int, v: *const *const c_char) -> Vec<String> {
31 let mut args = Vec::new();
32 let slice = slice::from_raw_parts(v, n as usize);
33 for ptr in slice {
34 let cstr = CStr::from_ptr(*ptr);
35 let string = String::from_utf8_lossy(cstr.to_bytes()).into_owned();
36 args.push(string);
37 }
38 args
39}
40
41pub fn test_byond_call(
50 func: unsafe extern "C" fn(i32, *const *const c_char) -> *const c_char,
51) -> String {
52 unsafe {
53 let ptr = func(0, null());
54 CStr::from_ptr(ptr).to_string_lossy().into_owned()
55 }
56}
57
58pub fn test_byond_call_args<P>(
65 func: unsafe extern "C" fn(i32, *const *const c_char) -> *const c_char,
66 args: &[P],
67) -> String
68where
69 P: AsRef<[u8]>,
70{
71 let mut cstrs = Vec::with_capacity(args.len());
73 let mut ptrs = Vec::with_capacity(args.len());
74
75 for arg in args {
76 let arg = arg.as_ref();
77 let cstr = CString::new(arg).unwrap();
78 let ptr = cstr.as_ptr();
79 cstrs.push(cstr);
80 ptrs.push(ptr);
81 }
82
83 unsafe {
84 let ptr = func(ptrs.len() as i32, ptrs.as_slice().as_ptr());
85 CStr::from_ptr(ptr).to_string_lossy().into_owned()
86 }
87}