use crate::{raw, AtmiError, AtmiResult, NstdError, TypedBuffer, TypedUbf, UbfError};
use core::ffi::{c_char, c_int, c_long};
#[cfg(feature = "ctx-send")]
use std::cell::Cell;
use std::{
ffi::{CStr, CString},
marker::PhantomData,
ptr,
};
#[cfg(not(feature = "ctx-send"))]
type CtxMarker = std::rc::Rc<()>;
#[cfg(feature = "ctx-send")]
type CtxMarker = Cell<()>;
#[cfg(feature = "ctx-send")]
type CtxHandle = raw::TPCONTEXT_T;
#[derive(Debug)]
pub struct AtmiCtx {
_marker: PhantomData<CtxMarker>,
#[cfg(feature = "ctx-send")]
handle: Cell<CtxHandle>,
}
impl AtmiCtx {
pub fn new() -> Result<Self, AtmiError> {
#[cfg(not(feature = "ctx-send"))]
{
Ok(AtmiCtx {
_marker: PhantomData,
})
}
#[cfg(feature = "ctx-send")]
{
unsafe {
let handle = raw::tpnewctxt(0, 0);
if handle.is_null() {
return Err(AtmiError::new(
raw::TPESYSTEM,
"failed to allocate ATMI context",
));
}
Ok(AtmiCtx {
_marker: PhantomData,
handle: Cell::new(handle),
})
}
}
}
pub fn tpinit(&self) -> AtmiResult<()> {
let rc = unsafe { raw::tpinit(ptr::null_mut()) };
if rc == raw::EXSUCCEED as c_int {
Ok(())
} else {
Err(self.atmi_last_error())
}
}
pub fn tpterm(&self) -> AtmiResult<()> {
let rc = unsafe { raw::tpterm() };
if rc == raw::EXSUCCEED as c_int {
Ok(())
} else {
Err(self.atmi_last_error())
}
}
pub fn atmi_last_error(&self) -> AtmiError {
unsafe {
let err_ptr = raw::_exget_tperrno_addr(); let code = *err_ptr;
let msg_ptr = raw::tpstrerror(code); let message = CStr::from_ptr(msg_ptr).to_string_lossy().into_owned();
AtmiError::new(code as u32, message)
}
}
pub fn ubf_last_error(&self) -> UbfError {
unsafe {
let err_ptr = self.ndrx_bget_ferror_addr();
let code = *err_ptr;
let msg_ptr = self.bstrerror(code);
let message = CStr::from_ptr(msg_ptr).to_string_lossy().into_owned();
UbfError::new(code as u32, message)
}
}
pub fn nstd_last_error(&self) -> NstdError {
unsafe {
let err_ptr = raw::_Nget_Nerror_addr(); let code = *err_ptr;
let msg_ptr = raw::Nstrerror(code); let message = CStr::from_ptr(msg_ptr).to_string_lossy().into_owned();
NstdError::new(code as u32, message)
}
}
pub fn tpalloc<'ctx>(
&'ctx self,
type_: &str,
subtype: &str,
size: usize,
) -> AtmiResult<TypedBuffer<'ctx>> {
let type_c = CString::new(type_)
.map_err(|_| AtmiError::new(raw::TPEINVAL, "type_ contains NUL byte"))?;
let subtype_c = CString::new(subtype)
.map_err(|_| AtmiError::new(raw::TPEINVAL, "subtype contains NUL byte"))?;
let ptr = unsafe {
raw::tpalloc(
type_c.as_ptr() as *mut c_char,
subtype_c.as_ptr() as *mut c_char,
size as c_long,
)
};
if ptr.is_null() {
Err(self.atmi_last_error())
} else {
let buf = unsafe { TypedBuffer::from_raw(self, ptr) };
Ok(buf)
}
}
pub fn tpalloc_ubf<'ctx>(&'ctx self, size: usize) -> AtmiResult<TypedUbf<'ctx>> {
let type_c = CString::new("UBF").unwrap();
let subtype_c = CString::new("").unwrap();
let raw_ptr = unsafe {
raw::tpalloc(
type_c.as_ptr() as *mut c_char,
subtype_c.as_ptr() as *mut c_char,
size as c_long,
)
};
if raw_ptr.is_null() {
Err(self.atmi_last_error())
} else {
let ubf = unsafe { TypedUbf::from_raw(self, raw_ptr) };
Ok(ubf)
}
}
#[cfg(feature = "ctx-send")]
#[inline]
pub(crate) fn c_ctx_ptr(&self) -> *mut raw::TPCONTEXT_T {
self.handle.as_ptr()
}
}
impl Drop for AtmiCtx {
fn drop(&mut self) {
#[cfg(not(feature = "ctx-send"))]
unsafe {
raw::tpterm();
}
#[cfg(feature = "ctx-send")]
unsafe {
let handle = self.handle.get();
if !handle.is_null() {
raw::tpfreectxt(handle);
self.handle.set(ptr::null_mut());
}
}
}
}