#![allow(unused_macros)]
use std::ffi::{c_void, CString, c_long};
use std::sync::Once;
use crate::bindings::*;
use aes_types::*;
use crate::server_interface::ServerInterface;
static INIT: Once = Once::new();
pub(crate) static mut CLIENT_DATA: Option<ClientData> = None;
#[repr(C)]
#[repr(align(8))]
pub(crate) struct ClientData {
pub(crate) server: SoHServer,
pub(crate) server_interface: *mut SoServerInterface,
}
unsafe impl Send for ClientData {}
unsafe impl Sync for ClientData {}
impl Clone for ClientData {
fn clone(&self) -> Self {
ClientData {
server: self.server,
server_interface: self.server_interface,
}
}
}
#[macro_export]
macro_rules! es_function {
($name:ident, $expected_argc:expr, $body:expr) => {
#[no_mangle]
pub extern "C" fn $name(argv: *mut TaggedData, argc: c_long, retval: *mut TaggedData) -> c_long {
if !validate_args(argv, argc, $expected_argc) {
return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, retval);
}
unsafe {
let args = std::slice::from_raw_parts(argv, argc as usize);
$body(args, retval)
}
}
};
}
#[macro_export]
macro_rules! get_string_arg {
($args:expr, $index:expr, $retval:expr) => {
match { get_string_from_tagged_data(&$args[$index]) } {
Some(s) => s,
None => return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, $retval)
}
};
}
#[macro_export]
macro_rules! get_integer_arg {
($args:expr, $index:expr, $retval:expr) => {
match { get_integer_from_tagged_data(&$args[$index]) } {
Some(i) => i,
None => return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, $retval)
}
};
}
#[macro_export]
macro_rules! get_bool_arg {
($args:expr, $index:expr, $retval:expr) => {
match { get_bool_from_tagged_data(&$args[$index]) } {
Some(b) => b,
None => return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, $retval)
}
};
}
#[macro_export]
macro_rules! get_live_object_arg {
($args:expr, $index:expr, $retval:expr) => {
match { get_live_object_from_tagged_data(&$args[$index]) } {
Some(obj) => obj,
None => return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, $retval)
}
};
}
#[macro_export]
macro_rules! get_live_object_from_data {
($data:expr, $retval:expr) => {
match { get_live_object_from_tagged_data($data) } {
Some(obj) => obj,
None => return make_error_result(ES_ERR_BAD_ARGUMENT_LIST, $retval)
}
};
}
#[macro_export]
macro_rules! get_client_data {
() => {
match { CLIENT_DATA.as_ref() } {
Some(data) => data,
None => return make_error_result(ES_ERR_NO_MEMORY, retval)
}
};
}
#[macro_export]
macro_rules! get_server_interface {
($retval:expr) => {
match { CLIENT_DATA.as_ref().and_then(|data| data.server_interface.as_ref()) } {
Some(interface) => interface,
None => return make_error_result(ES_ERR_NO_MEMORY, $retval)
}
};
}
#[macro_export]
macro_rules! get_server {
($retval:expr) => {
match { CLIENT_DATA.as_ref() } {
Some(data) => data.server,
None => return make_error_result(ES_ERR_NO_MEMORY, $retval)
}
};
}
#[macro_export]
macro_rules! call_server_interface {
($interface:expr, $func:ident, $($arg:expr),*) => {
($interface.$func)($($arg),*)
};
}
#[macro_export]
macro_rules! tagged_data_free {
($server:expr, $interface:expr, $data:expr) => {
let _ = call_server_interface!($interface, taggedDataFree, $server, $data);
};
}
pub unsafe fn get_string_from_tagged_data(data: &TaggedData) -> Option<String> {
if data.type_ == TYPE_STRING as c_long {
let c_str = std::ffi::CStr::from_ptr(data.data.string);
c_str.to_str().ok().map(|s| s.to_string())
} else {
None
}
}
pub unsafe fn get_bool_from_tagged_data(data: &TaggedData) -> Option<bool> {
if data.type_ == TYPE_BOOL as c_long {
Some(data.data.intval != 0)
} else {
None
}
}
pub unsafe fn get_integer_from_tagged_data(data: &TaggedData) -> Option<i32> {
if data.type_ == TYPE_INTEGER as c_long {
Some(data.data.intval)
} else {
None
}
}
pub unsafe fn get_double_from_tagged_data(data: &TaggedData) -> Option<f64> {
if data.type_ == TYPE_DOUBLE as c_long {
Some(data.data.fltval)
} else {
None
}
}
pub unsafe fn get_live_object_from_tagged_data(data: &TaggedData) -> Option<*mut c_long> {
println!("data.type_ = {}", data.type_);
if data.type_ == TYPE_LIVE_OBJECT as c_long || data.type_ == TYPE_LIVE_OBJECT_RELEASE as c_long {
Some(data.data.hObject)
} else {
None
}
}
unsafe fn get_client_data<T>(h_object: SoHObject) -> Option<&'static mut T> {
let mut ptr: *mut c_void = std::ptr::null_mut();
let client_data = CLIENT_DATA.as_ref()?;
let server_interface = client_data.server_interface.as_ref()?;
if (server_interface.getClientData)(h_object, &mut ptr) != ES_ERR_OK {
return None;
}
if ptr.is_null() {
return None;
}
Some(&mut *(ptr as *mut T))
}
pub fn make_error_result(error: i32, retval: *mut TaggedData) -> c_long {
unsafe {
*retval = TaggedData::new_undefined();
}
error as c_long
}
pub fn make_success_result<T: Into<TaggedData>>(value: T, retval: *mut TaggedData) -> c_long {
unsafe {
*retval = value.into();
}
ES_ERR_OK as c_long
}
pub fn validate_args(argv: *mut TaggedData, argc: c_long, expected_argc: c_long) -> bool {
!argv.is_null() && argc == expected_argc
}
pub unsafe fn eval_script(script: &str, retval: *mut TaggedData) -> c_long {
*retval = TaggedData::new_script(script);
ES_ERR_OK as c_long
}
pub fn get_server_interface() -> Option<ServerInterface<'static>> {
unsafe {
CLIENT_DATA.as_ref().map(|data| {
ServerInterface::new(
data.server_interface.as_ref().unwrap(),
data.server
)
})
}
}