maa_framework/
callback.rs1use crate::sys;
4use std::ffi::CStr;
5use std::os::raw::c_void;
6
7pub type EventCallbackFn = Box<dyn Fn(&str, &str) + Send + Sync>;
8
9unsafe extern "C" fn event_callback_trampoline(
10 _handle: *mut c_void,
11 msg: *const std::os::raw::c_char,
12 details: *const std::os::raw::c_char,
13 trans_arg: *mut c_void,
14) {
15 if trans_arg.is_null() {
16 return;
17 }
18 let callback = &*(trans_arg as *const EventCallbackFn);
19
20 let msg_str = if !msg.is_null() {
21 CStr::from_ptr(msg).to_string_lossy()
22 } else {
23 std::borrow::Cow::Borrowed("")
24 };
25
26 let details_str = if !details.is_null() {
27 CStr::from_ptr(details).to_string_lossy()
28 } else {
29 std::borrow::Cow::Borrowed("")
30 };
31
32 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
33 callback(&msg_str, &details_str);
34 }));
35
36 if let Err(_) = result {
37 eprintln!("MaaFramework Rust Binding: Panic caught in event callback");
38 }
39}
40
41pub struct EventCallback {
42 _ptr: *mut c_void,
43}
44
45impl EventCallback {
46 pub fn new(
47 cb: impl Fn(&str, &str) + Send + Sync + 'static,
48 ) -> (sys::MaaEventCallback, *mut c_void) {
49 let boxed: EventCallbackFn = Box::new(cb);
50 let ptr = Box::into_raw(Box::new(boxed)) as *mut c_void;
51 (Some(event_callback_trampoline), ptr)
52 }
53
54 pub unsafe fn drop_callback(ptr: *mut c_void) {
55 if !ptr.is_null() {
56 let _ = Box::from_raw(ptr as *mut EventCallbackFn);
57 }
58 }
59
60 pub fn new_sink(
61 handle: crate::common::MaaId,
62 sink: Box<dyn crate::event_sink::EventSink>,
63 ) -> (sys::MaaEventCallback, *mut c_void) {
64 let wrapper = Box::new(EventSinkWrapper { handle, sink });
65 let ptr = Box::into_raw(wrapper) as *mut c_void;
66 (Some(event_sink_trampoline), ptr)
67 }
68
69 pub unsafe fn drop_sink(ptr: *mut c_void) {
70 if !ptr.is_null() {
71 let _ = Box::from_raw(ptr as *mut EventSinkWrapper);
72 }
73 }
74}
75
76struct EventSinkWrapper {
81 handle: crate::common::MaaId,
82 sink: Box<dyn crate::event_sink::EventSink>,
83}
84
85unsafe extern "C" fn event_sink_trampoline(
94 _handle: *mut c_void,
95 _msg: *const std::os::raw::c_char,
96 _detail: *const std::os::raw::c_char,
97 callback_arg: *mut c_void,
98) {
99 if callback_arg.is_null() {
100 return;
101 }
102 let wrapper = &*(callback_arg as *const EventSinkWrapper);
103
104 let msg_str = if !_msg.is_null() {
105 CStr::from_ptr(_msg).to_string_lossy()
106 } else {
107 std::borrow::Cow::Borrowed("")
108 };
109
110 let detail_str = if !_detail.is_null() {
111 CStr::from_ptr(_detail).to_string_lossy()
112 } else {
113 std::borrow::Cow::Borrowed("")
114 };
115
116 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
117 let event = crate::notification::MaaEvent::from_json(&msg_str, &detail_str);
118 wrapper.sink.on_event(wrapper.handle, &event);
119 }));
120
121 if let Err(_) = result {
122 eprintln!("MaaFramework Rust Binding: Panic caught in event sink callback");
123 }
124}