1use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::os::raw::c_void;
6use std::ptr::NonNull;
7use std::{mem, panic, process};
8use vapoursynth_sys as ffi;
9
10use crate::api::API;
11use crate::core::CoreRef;
12use crate::map::{Map, MapRef, MapRefMut};
13
14#[derive(Debug)]
16pub struct Function<'core> {
17 handle: NonNull<ffi::VSFunction>,
18 _owner: PhantomData<&'core ()>,
19}
20
21unsafe impl<'core> Send for Function<'core> {}
22unsafe impl<'core> Sync for Function<'core> {}
23
24impl<'core> Drop for Function<'core> {
25 #[inline]
26 fn drop(&mut self) {
27 unsafe {
28 API::get_cached().free_func(self.handle.as_ptr());
29 }
30 }
31}
32
33impl<'core> Clone for Function<'core> {
34 #[inline]
35 fn clone(&self) -> Self {
36 let handle = unsafe { API::get_cached().clone_func(self.handle.as_ptr()) };
37 Self {
38 handle: unsafe { NonNull::new_unchecked(handle) },
39 _owner: PhantomData,
40 }
41 }
42}
43
44impl<'core> Function<'core> {
45 #[inline]
50 pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSFunction) -> Self {
51 Self {
52 handle: NonNull::new_unchecked(handle),
53 _owner: PhantomData,
54 }
55 }
56
57 #[inline]
59 pub(crate) fn ptr(&self) -> *mut ffi::VSFunction {
60 self.handle.as_ptr()
61 }
62
63 #[inline]
67 pub fn new<F>(_api: API, core: CoreRef<'core>, callback: F) -> Self
68 where
69 F: Fn(API, CoreRef<'core>, &Map<'core>, &mut Map<'core>) + Send + Sync + 'core,
70 {
71 unsafe extern "C" fn c_callback<'core, F>(
72 in_: *const ffi::VSMap,
73 out: *mut ffi::VSMap,
74 user_data: *mut c_void,
75 core: *mut ffi::VSCore,
76 _vsapi: *const ffi::VSAPI,
77 ) where
78 F: Fn(API, CoreRef<'core>, &Map<'core>, &mut Map<'core>) + Send + Sync + 'core,
79 {
80 let closure = move || {
81 let api = API::get_cached();
82 let core = CoreRef::from_ptr(core);
83 let in_ = MapRef::from_ptr(in_);
84 let mut out = MapRefMut::from_ptr(out);
85 let callback = Box::from_raw(user_data as *mut F);
86
87 callback(api, core, &in_, &mut out);
88
89 mem::forget(callback);
90 };
91
92 if panic::catch_unwind(closure).is_err() {
93 process::abort();
94 }
95 }
96
97 unsafe extern "C" fn c_free<F>(user_data: *mut c_void) {
98 drop(Box::from_raw(user_data as *mut F))
99 }
100
101 let data = Box::new(callback);
102
103 let handle = unsafe {
104 API::get_cached().create_func(
105 Some(c_callback::<'core, F>),
106 Box::into_raw(data) as _,
107 Some(c_free::<F>),
108 core.ptr(),
109 )
110 };
111
112 Self {
113 handle: unsafe { NonNull::new_unchecked(handle) },
114 _owner: PhantomData,
115 }
116 }
117
118 #[inline]
120 pub fn call(&self, in_: &Map<'core>, out: &mut Map<'core>) {
121 unsafe { API::get_cached().call_func(self.handle.as_ptr(), in_.deref(), out.deref_mut()) };
122 }
123}