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 {
22 type Output;
23 fn call(&mut self, instr: &Instrument, event: &event::Event) -> Self::Output;
24}
25
26impl<F, Out> Callback for F
27where
28 F: FnMut(&Instrument, &event::Event) -> Out,
29{
30 type Output = Out;
31 fn call(&mut self, instr: &Instrument, event: &event::Event) -> Self::Output {
32 self(instr, event)
33 }
34}
35
36struct CallbackPack<F: Callback> {
37 sender: Sender<F::Output>,
38 core: F,
39}
40
41impl<F: Callback> CallbackPack<F> {
42 fn from_callback(f: F) -> (Self, Receiver<F::Output>) {
43 let (sender, receiver) = std::sync::mpsc::channel();
44 (Self { sender, core: f }, receiver)
45 }
46 fn call(&mut self, instr: &Instrument, event: &event::Event) -> vs::ViStatus {
47 self.sender
49 .send(self.core.call(instr, event))
50 .expect("receiver side should be valid");
51 SUCCESS
52 }
53}
54
55struct CallbackWrapper<F: Callback> {
56 f: NonNull<CallbackPack<F>>,
57 hold: unsafe extern "system" fn(
59 vs::ViSession,
60 vs::ViEventType,
61 vs::ViEvent,
62 *mut std::ffi::c_void,
63 ) -> vs::ViStatus,
64}
65fn split_pack<C: Callback>(
66 pack: CallbackPack<C>,
67) -> (
68 std::ptr::NonNull<CallbackPack<C>>,
69 unsafe extern "system" fn(
70 vs::ViSession,
71 vs::ViEventType,
72 vs::ViEvent,
73 *mut std::ffi::c_void,
74 ) -> vs::ViStatus,
75) {
76 use std::ffi::c_void;
77 let data = Box::into_raw(Box::new(pack));
78 unsafe extern "system" fn trampoline<T: Callback>(
79 instr: vs::ViSession,
80 event_type: vs::ViEventType,
81 event: vs::ViEvent,
82 user_data: *mut c_void,
83 ) -> vs::ViStatus {
84 let pack: &mut CallbackPack<T> = &mut *(user_data as *mut CallbackPack<T>);
85 let instr = Instrument::from_raw_ss(instr);
86 let event = event::Event::new(event, event_type);
87 let ret = pack.call(&instr, &event);
88 std::mem::forget(event); std::mem::forget(instr); ret
92 }
93
94 (
95 NonNull::new(data).expect("impossible to pass in a null ptr"),
96 trampoline::<C>,
97 )
98}
99impl<F: Callback> CallbackWrapper<F> {
100 pub(crate) fn new(f: F) -> (Self, Receiver<F::Output>) {
101 let (pack, receiver) = CallbackPack::from_callback(f);
102 let (data, fun) = split_pack(pack);
103 (Self { f: data, hold: fun }, receiver)
104 }
105}
106
107pub struct Handler<'b, F: Callback> {
111 instr: BorrowedSs<'b>,
112 rec: Receiver<F::Output>,
113 event_kind: event::EventKind,
114 callback: CallbackWrapper<F>,
115}
116
117impl<'b, F: Callback> Handler<'b, F> {
118 pub(crate) fn new(
119 instr: BorrowedSs<'b>,
120 event_kind: event::EventKind,
121 callback: F,
122 ) -> Result<Self> {
123 let (callback, rec) = CallbackWrapper::new(callback);
124 super::wrap_raw_error_in_unsafe!(vs::viInstallHandler(
125 instr.as_raw_ss(),
126 event_kind as _,
127 Some(callback.hold),
128 callback.f.as_ptr() as _
129 ))?;
130 Ok(Self {
131 instr,
132 rec,
133 event_kind,
134 callback,
135 })
136 }
137}
138
139impl<'b, F: Callback> Drop for Handler<'b, F> {
140 fn drop(&mut self) {
141 unsafe {
142 vs::viUninstallHandler(
143 self.instr.as_raw_ss(),
144 self.event_kind as _,
145 Some(self.callback.hold),
146 self.callback.f.as_ptr() as _,
147 );
148 drop(Box::from_raw(self.callback.f.as_ptr()));
149 }
150 }
151}
152
153impl<'b, F: Callback> Handler<'b, F> {
154 pub fn uninstall(self) {}
155}
156
157impl<'b, F: Callback> AsRef<Receiver<F::Output>> for Handler<'b, F> {
158 fn as_ref(&self) -> &Receiver<F::Output> {
159 &self.rec
160 }
161}
162
163impl<'b, F: Callback> Handler<'b, F> {
164 pub fn receiver(&self) -> &Receiver<F::Output> {
165 self.as_ref()
166 }
167}