Skip to main content

ffmpeg_next/util/
interrupt.rs

1use std::panic;
2use std::process;
3
4use crate::ffi::*;
5use libc::{c_int, c_void};
6
7pub struct Interrupt {
8    pub interrupt: AVIOInterruptCB,
9    pub guard: InterruptGuard,
10}
11
12pub struct InterruptGuard {
13    opaque: *mut c_void,
14    drop_fn: unsafe fn(*mut c_void),
15}
16
17unsafe impl Send for InterruptGuard {}
18unsafe impl Sync for InterruptGuard {}
19
20impl Drop for InterruptGuard {
21    fn drop(&mut self) {
22        if !self.opaque.is_null() {
23            unsafe { (self.drop_fn)(self.opaque) };
24            self.opaque = std::ptr::null_mut();
25        }
26    }
27}
28
29extern "C" fn callback<F>(opaque: *mut c_void) -> c_int
30where
31    F: FnMut() -> bool,
32{
33    // Clippy suggests to remove &mut, but it doesn't compile then (move occurs because value has type `F`, which does not implement the `Copy` trait)
34    #[allow(clippy::needless_borrow)]
35    match panic::catch_unwind(|| (unsafe { &mut *(opaque as *mut F) })()) {
36        Ok(ret) => ret as c_int,
37        Err(_) => process::abort(),
38    }
39}
40
41unsafe fn drop_box<F>(opaque: *mut c_void) {
42    unsafe {
43        drop(Box::from_raw(opaque as *mut F));
44    }
45}
46
47pub fn new<F>(opaque: Box<F>) -> Interrupt
48where
49    F: FnMut() -> bool + Send + 'static,
50{
51    let opaque = Box::into_raw(opaque) as *mut c_void;
52    let interrupt_cb = AVIOInterruptCB {
53        callback: Some(callback::<F>),
54        opaque,
55    };
56    Interrupt {
57        interrupt: interrupt_cb,
58        guard: InterruptGuard {
59            opaque,
60            drop_fn: drop_box::<F>,
61        },
62    }
63}