use std::ffi::c_void;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_char;
use crate::Interpreter;
use crate::ObjectType;
use crate::RawObject;
pub(crate) static mut ALLOC: Option<extern "C" fn(usize) -> *mut c_void> = None;
pub(crate) static mut REALLOC: Option<extern "C" fn(*mut c_void, usize) -> *mut c_void> = None;
pub(crate) static mut FREE: Option<extern "C" fn(*mut c_void)> = None;
pub(crate) static mut NEW_OBJ: Option<extern "C" fn() -> *mut RawObject> = None;
pub(crate) static mut DUPLICATE_OBJ: Option<extern "C" fn(*mut RawObject) -> *mut RawObject> = None;
pub(crate) static mut INCR_REF_COUNT: Option<extern "C" fn(*mut RawObject)> = None;
pub(crate) static mut DECR_REF_COUNT: Option<extern "C" fn(*mut RawObject)> = None;
pub(crate) static mut IS_SHARED: Option<extern "C" fn(*mut RawObject) -> i32> = None;
pub(crate) static mut INVALIDATE_STRING_REP: Option<extern "C" fn(*mut RawObject)> = None;
pub(crate) static mut GET_STRING: Option<extern "C" fn(*mut RawObject) -> *mut c_char> = None;
pub(crate) static mut GET_OBJ_TYPE: Option<extern "C" fn(*const c_char) -> *const ObjectType> =
None;
pub(crate) static mut CONVERT_TO_TYPE: Option<
extern "C" fn(*const Interpreter, *mut RawObject, *const ObjectType) -> i32,
> = None;
pub(crate) static mut NEW_STRING_OBJ: Option<
extern "C" fn(*const c_char, usize) -> *mut RawObject,
> = None;
pub(crate) static mut SET_STRING_OBJ: Option<extern "C" fn(*mut RawObject, *const c_char, usize)> =
None;
pub struct TclBuf {
ptr: *mut u8,
len: usize,
}
impl TclBuf {
pub(crate) unsafe fn from_raw_parts(ptr: *mut u8, len: usize) -> Self {
Self { ptr, len }
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn into_raw_parts(self) -> (*mut c_char, usize) {
let md = ManuallyDrop::new(self);
(md.ptr as *mut c_char, md.len)
}
}
impl Drop for TclBuf {
fn drop(&mut self) {
unsafe { FREE.expect("module must have been initialized")(self.ptr as *mut c_void) }
}
}
impl Deref for TclBuf {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl DerefMut for TclBuf {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) }
}
}
unsafe impl Send for TclBuf {}
pub fn tcl_string(rust_str: &str) -> TclBuf {
let alloc_len = rust_str.len() + 1; unsafe {
let ptr = ALLOC.expect("module not initialized")(alloc_len) as *mut u8;
let slice = std::slice::from_raw_parts_mut(ptr, alloc_len);
slice[..rust_str.len()].copy_from_slice(rust_str.as_bytes());
*slice.last_mut().expect("alloc_len is always >= 1") = 0;
TclBuf::from_raw_parts(ptr, rust_str.len())
}
}