1use std::{
9 ptr::NonNull,
10 sync::mpsc::{Receiver, Sender},
11};
12use visa_sys as vs;
13
14use crate::{
15 enums::event,
16 session::{AsRawSs, BorrowedSs, FromRawSs},
17 Instrument, Result, SUCCESS,
18};
19
20pub trait Callback: Send {
26 type Output: Send;
27 fn call(&mut self, instr: &Instrument, event: &event::Event) -> Self::Output;
28}
29
30impl<F, Out> Callback for F
31where
32 F: FnMut(&Instrument, &event::Event) -> Out + Send,
33 Out: Send,
34{
35 type Output = Out;
36 fn call(&mut self, instr: &Instrument, event: &event::Event) -> Self::Output {
37 self(instr, event)
38 }
39}
40
41struct CallbackPack<F: Callback> {
42 sender: Sender<F::Output>,
43 core: F,
44}
45
46impl<F: Callback> CallbackPack<F> {
47 fn from_callback(f: F) -> (Self, Receiver<F::Output>) {
48 let (sender, receiver) = std::sync::mpsc::channel();
49 (Self { sender, core: f }, receiver)
50 }
51 fn call(&mut self, instr: &Instrument, event: &event::Event) -> vs::ViStatus {
52 self.sender
54 .send(self.core.call(instr, event))
55 .expect("receiver side should be valid");
56 SUCCESS
57 }
58}
59
60struct CallbackWrapper<F: Callback> {
61 f: NonNull<CallbackPack<F>>,
62 hold: unsafe extern "system" fn(
64 vs::ViSession,
65 vs::ViEventType,
66 vs::ViEvent,
67 *mut std::ffi::c_void,
68 ) -> vs::ViStatus,
69}
70fn split_pack<C: Callback>(
71 pack: CallbackPack<C>,
72) -> (
73 std::ptr::NonNull<CallbackPack<C>>,
74 unsafe extern "system" fn(
75 vs::ViSession,
76 vs::ViEventType,
77 vs::ViEvent,
78 *mut std::ffi::c_void,
79 ) -> vs::ViStatus,
80) {
81 use std::ffi::c_void;
82 let data = Box::into_raw(Box::new(pack));
83 unsafe extern "system" fn trampoline<T: Callback>(
84 instr: vs::ViSession,
85 event_type: vs::ViEventType,
86 event: vs::ViEvent,
87 user_data: *mut c_void,
88 ) -> vs::ViStatus {
89 let ret = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
93 let pack: &mut CallbackPack<T> = &mut *(user_data as *mut CallbackPack<T>);
94 let instr = std::mem::ManuallyDrop::new(Instrument::from_raw_ss(instr));
95 let event = std::mem::ManuallyDrop::new(event::Event::new(event, event_type));
96 pack.call(&instr, &event)
97 }));
98 match ret {
99 Ok(ret) => ret,
100 Err(_) => {
101 log::error!("panic in visa event handler, ignored");
102 SUCCESS
103 }
104 }
105 }
106
107 (
108 NonNull::new(data).expect("impossible to pass in a null ptr"),
109 trampoline::<C>,
110 )
111}
112impl<F: Callback> CallbackWrapper<F> {
113 pub(crate) fn new(f: F) -> (Self, Receiver<F::Output>) {
114 let (pack, receiver) = CallbackPack::from_callback(f);
115 let (data, fun) = split_pack(pack);
116 (Self { f: data, hold: fun }, receiver)
117 }
118}
119
120pub struct Handler<'b, F: Callback> {
124 instr: BorrowedSs<'b>,
125 rec: Receiver<F::Output>,
126 event_kind: event::EventKind,
127 callback: CallbackWrapper<F>,
128}
129
130impl<'b, F: Callback> Handler<'b, F> {
131 pub(crate) fn new(
132 instr: BorrowedSs<'b>,
133 event_kind: event::EventKind,
134 callback: F,
135 ) -> Result<Self> {
136 let (callback, rec) = CallbackWrapper::new(callback);
137 super::wrap_raw_error_in_unsafe!(vs::viInstallHandler(
138 instr.as_raw_ss(),
139 event_kind as _,
140 Some(callback.hold),
141 callback.f.as_ptr() as _
142 ))?;
143 Ok(Self {
144 instr,
145 rec,
146 event_kind,
147 callback,
148 })
149 }
150}
151
152impl<'b, F: Callback> Drop for Handler<'b, F> {
153 fn drop(&mut self) {
154 unsafe {
155 vs::viUninstallHandler(
156 self.instr.as_raw_ss(),
157 self.event_kind as _,
158 Some(self.callback.hold),
159 self.callback.f.as_ptr() as _,
160 );
161 drop(Box::from_raw(self.callback.f.as_ptr()));
162 }
163 }
164}
165
166impl<'b, F: Callback> Handler<'b, F> {
167 pub fn uninstall(self) {}
168}
169
170impl<'b, F: Callback> AsRef<Receiver<F::Output>> for Handler<'b, F> {
171 fn as_ref(&self) -> &Receiver<F::Output> {
172 &self.rec
173 }
174}
175
176impl<'b, F: Callback> Handler<'b, F> {
177 pub fn receiver(&self) -> &Receiver<F::Output> {
178 self.as_ref()
179 }
180}