vapoursynth/
function.rs

1//! VapourSynth callable functions.
2
3use 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/// Holds a reference to a function that may be called.
15#[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    /// Wraps `handle` in a `Function`.
46    ///
47    /// # Safety
48    /// The caller must ensure `handle` and the lifetime are valid and API is cached.
49    #[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    /// Returns the underlying pointer.
58    #[inline]
59    pub(crate) fn ptr(&self) -> *mut ffi::VSFunction {
60        self.handle.as_ptr()
61    }
62
63    /// Creates a new function.
64    ///
65    /// To indicate an error from the callback, set an error on the output map.
66    #[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    /// Calls the function. If the call fails `out` will have an error set.
119    #[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}