rdbc_rs/driver/
callback.rs1use anyhow::Result;
8use std::ptr::NonNull;
9
10#[repr(C)]
13pub struct CallbackVTable<Output> {
14 invoke: unsafe fn(NonNull<CallbackVTable<Output>>, result: Result<Output>),
15
16 drop: unsafe fn(NonNull<CallbackVTable<Output>>),
17}
18
19impl<Output> CallbackVTable<Output> {
20 fn new<F>() -> Self
21 where
22 F: FnOnce(Result<Output>),
23 {
24 CallbackVTable {
25 drop: drop::<F, Output>,
26 invoke: invoke::<F, Output>,
27 }
28 }
29}
30
31unsafe fn drop<F, Output>(_: NonNull<CallbackVTable<Output>>)
32where
33 F: FnOnce(Result<Output>),
34{
35}
36
37unsafe fn invoke<F, Output>(vtable: NonNull<CallbackVTable<Output>>, result: Result<Output>)
38where
39 F: FnOnce(Result<Output>),
40{
41 let mut raw = vtable.cast::<Callback<F, Output>>();
42
43 let f = raw.as_mut().f.take();
44
45 f.unwrap()(result);
46}
47
48#[repr(C)]
49struct Callback<F, Output>
50where
51 F: FnOnce(Result<Output>),
52{
53 vtable: CallbackVTable<Output>,
54 f: Option<F>,
55}
56
57pub struct BoxedCallback<Output> {
59 vtable: NonNull<CallbackVTable<Output>>,
60}
61
62impl<Output> BoxedCallback<Output> {
63 pub fn new<F>(f: F) -> Self
64 where
65 F: FnOnce(Result<Output>),
66 {
67 let boxed = Box::new(Callback::<F, Output> {
68 vtable: CallbackVTable::<Output>::new::<F>(),
69 f: Some(f),
70 });
71
72 let ptr =
73 unsafe { NonNull::new_unchecked(Box::into_raw(boxed) as *mut CallbackVTable<Output>) };
74
75 Self { vtable: ptr }
76 }
77
78 pub fn invoke(&self, result: Result<Output>) {
80 unsafe {
81 let invoke = self.vtable.as_ref().invoke;
82
83 invoke(self.vtable, result)
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::BoxedCallback;
91
92 #[test]
93 fn test_boxed_callback() {
94 let boxed: BoxedCallback<usize> = BoxedCallback::new(|v| {
95 assert_eq!(v.unwrap(), 1);
96 });
97
98 boxed.invoke(Ok(1));
99 }
100}