1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// use std::panic::{catch_unwind, AssertUnwindSafe};
// use cxx::SharedPtr;
// use crate::nuitrack_bridge::hand_tracker::ffi::{self as ht_ffi, c_void, BridgedHandTrackerData, HandTracker as FFIHandTracker};
// use crate::nuitrack::shared_types::error::{NuitrackError, Result as NuitrackResult};
// use crate::nuitrack::shared_types::hand_frame::HandFrame;
// pub type BlockingHandFrameCallback = Box<dyn FnMut(NuitrackResult<HandFrame>) + Send + 'static>;
// struct BlockingCallbackHolder {
// callback: BlockingHandFrameCallback,
// }
// pub struct BlockingHandTracker {
// ptr: SharedPtr<FFIHandTracker>,
// handler_id: Option<u64>,
// // Stores the Boxed callback data to keep it alive and manage its lifetime.
// callback_data_ptr: Option<*mut BlockingCallbackHolder>, // Pointer to the Box's content
// }
// impl BlockingHandTracker {
// pub(crate) fn new_blocking() -> NuitrackResult<Self> {
// let tracker_ptr = ht_ffi::create_hand_tracker().map_err(|e| {
// NuitrackError::ModuleCreationFailed(format!("BlockingHandTracker FFI create: {}", e))
// })?;
// Ok(Self {
// ptr: tracker_ptr,
// handler_id: None,
// callback_data_ptr: None,
// })
// }
// pub fn connect_on_update(
// &mut self,
// user_callback: BlockingHandFrameCallback,
// ) -> NuitrackResult<u64> {
// if self.handler_id.is_some() {
// return Err(NuitrackError::OperationFailed(
// "Callback already registered for this BlockingHandTracker".into(),
// ));
// }
// // Box the holder for the user's callback to get a stable heap pointer.
// let callback_holder = Box::new(BlockingCallbackHolder { callback: user_callback });
// // Convert the Box into a raw pointer to pass as `user_data`.
// let user_data_raw_ptr = Box::into_raw(callback_holder);
// self.callback_data_ptr = Some(user_data_raw_ptr); // Store for later cleanup
// let handler_id = unsafe {
// // Call the FFI function dedicated to blocking callbacks that uses the correct C++ wrapper
// // which in turn calls `rust_blocking_hand_tracker_trampoline`.
// ht_ffi::connect_on_update_for_blocking(&self.ptr, user_data_raw_ptr as *mut c_void)
// }
// .map_err(|e| {
// // If FFI call fails, reclaim the Box immediately.
// if let Some(raw_ptr) = self.callback_data_ptr.take() {
// unsafe { drop(Box::from_raw(raw_ptr)); }
// }
// NuitrackError::OperationFailed(format!("FFI connect_blocking_callback: {}", e))
// })?;
// self.handler_id = Some(handler_id);
// Ok(handler_id)
// }
// pub fn disconnect_on_update(&mut self) -> NuitrackResult<()> {
// if let Some(handler_id) = self.handler_id.take() {
// let disconnect_result = ht_ffi::disconnect_on_update(&self.ptr, handler_id)
// .map_err(|e| {
// NuitrackError::OperationFailed(format!("FFI disconnect_on_update: {}", e))
// });
// // Reclaim the Boxed callback data *after* attempting disconnect.
// if let Some(raw_ptr) = self.callback_data_ptr.take() {
// unsafe { drop(Box::from_raw(raw_ptr)); } // This drops the Box<BlockingCallbackHolder>
// }
// disconnect_result
// } else {
// Ok(())
// }
// }
// }
// impl Drop for BlockingHandTracker {
// fn drop(&mut self) {
// if self.handler_id.is_some() {
// if let Err(e) = self.disconnect_on_update() {
// }
// } else if let Some(raw_ptr) = self.callback_data_ptr.take() {
// unsafe { drop(Box::from_raw(raw_ptr)); }
// }
// }
// }
// #[unsafe(no_mangle)]
// pub unsafe extern "C" fn rust_blocking_hand_tracker_trampoline(
// raw_ffi_data: SharedPtr<BridgedHandTrackerData>,
// user_data: *mut c_void,
// ) {
// if user_data.is_null() {
// return;
// }
// // Reinterpret user_data as a mutable reference to our CallbackHolder.
// // This is safe as long as user_data actually points to a valid Box<CallbackHolder>
// // and BlockingHandTracker manages its lifetime correctly.
// let callback_holder = &mut *(user_data as *mut BlockingCallbackHolder);
// // Attempt to convert FFI data to Rust HandFrame.
// let frame_result = HandFrame::new(raw_ffi_data)
// .ok_or_else(|| NuitrackError::OperationFailed(
// "BlockingCallback: Failed to create HandFrame from FFI (BridgedHandTrackerData was null or invalid)".into()
// ));
// if frame_result.is_err() {
// }
// // Call the user's closure, catching potential panics.
// let panic_result = catch_unwind(AssertUnwindSafe(|| {
// (callback_holder.callback)(frame_result);
// }));
// if panic_result.is_err() {
// //error!(target: "nuitrack_rs::blocking_callback", "User-provided blocking HandTracker callback panicked!");
// // Depending on library policy, you might want to consider automatically disconnecting
// // a panicking callback, but that adds complexity. For now, logging is essential.
// }
// }