use crate::sys;
use std::ffi::CStr;
use std::os::raw::c_void;
pub type EventCallbackFn = Box<dyn Fn(&str, &str) + Send + Sync>;
unsafe extern "C" fn event_callback_trampoline(
_handle: *mut c_void,
msg: *const std::os::raw::c_char,
details: *const std::os::raw::c_char,
trans_arg: *mut c_void,
) {
if trans_arg.is_null() {
return;
}
let callback = unsafe { &*(trans_arg as *const EventCallbackFn) };
let msg_str = if !msg.is_null() {
unsafe { CStr::from_ptr(msg).to_string_lossy() }
} else {
std::borrow::Cow::Borrowed("")
};
let details_str = if !details.is_null() {
unsafe { CStr::from_ptr(details).to_string_lossy() }
} else {
std::borrow::Cow::Borrowed("")
};
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
callback(&msg_str, &details_str);
}));
if let Err(_) = result {
eprintln!("MaaFramework Rust Binding: Panic caught in event callback");
}
}
pub struct EventCallback {
_ptr: *mut c_void,
}
impl EventCallback {
pub fn new(
cb: impl Fn(&str, &str) + Send + Sync + 'static,
) -> (sys::MaaEventCallback, *mut c_void) {
let boxed: EventCallbackFn = Box::new(cb);
let ptr = Box::into_raw(Box::new(boxed)) as *mut c_void;
(Some(event_callback_trampoline), ptr)
}
pub unsafe fn drop_callback(ptr: *mut c_void) {
if !ptr.is_null() {
let _ = unsafe { Box::from_raw(ptr as *mut EventCallbackFn) };
}
}
pub fn new_sink(
handle: crate::common::MaaId,
sink: Box<dyn crate::event_sink::EventSink>,
) -> (sys::MaaEventCallback, *mut c_void) {
let wrapper = Box::new(EventSinkWrapper { handle, sink });
let ptr = Box::into_raw(wrapper) as *mut c_void;
(Some(event_sink_trampoline), ptr)
}
pub unsafe fn drop_sink(ptr: *mut c_void) {
if !ptr.is_null() {
let _ = unsafe { Box::from_raw(ptr as *mut EventSinkWrapper) };
}
}
}
struct EventSinkWrapper {
handle: crate::common::MaaId,
sink: Box<dyn crate::event_sink::EventSink>,
}
unsafe extern "C" fn event_sink_trampoline(
_handle: *mut c_void,
_msg: *const std::os::raw::c_char,
_detail: *const std::os::raw::c_char,
callback_arg: *mut c_void,
) {
if callback_arg.is_null() {
return;
}
let wrapper = unsafe { &*(callback_arg as *const EventSinkWrapper) };
let msg_str = if !_msg.is_null() {
unsafe { CStr::from_ptr(_msg).to_string_lossy() }
} else {
std::borrow::Cow::Borrowed("")
};
let detail_str = if !_detail.is_null() {
unsafe { CStr::from_ptr(_detail).to_string_lossy() }
} else {
std::borrow::Cow::Borrowed("")
};
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let event = crate::notification::MaaEvent::from_json(&msg_str, &detail_str);
wrapper.sink.on_event(wrapper.handle, &event);
}));
if let Err(_) = result {
eprintln!("MaaFramework Rust Binding: Panic caught in event sink callback");
}
}