gstreamer/subclass/
error.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use thiserror::Error;
4
5use crate::{prelude::ElementExt, ErrorMessage, FlowReturn};
6
7#[doc(hidden)]
8#[inline(never)]
9pub fn post_panic_error_message(
10    element: &crate::Element,
11    src: &crate::Object,
12    panic: Option<Box<dyn std::any::Any + Send + 'static>>,
13) {
14    let cause = panic.as_ref().and_then(|err| {
15        err.downcast_ref::<&str>()
16            .copied()
17            .or_else(|| err.downcast_ref::<String>().map(|s| s.as_str()))
18    });
19
20    let msg = if let Some(cause) = cause {
21        crate::message::Error::builder(crate::LibraryError::Failed, &format!("Panicked: {cause}"))
22            .src(src)
23            .build()
24    } else {
25        crate::message::Error::builder(crate::LibraryError::Failed, "Panicked")
26            .src(src)
27            .build()
28    };
29
30    let _ = element.post_message(msg);
31}
32
33#[macro_export]
34macro_rules! panic_to_error(
35    ($imp:expr, $ret:expr, $code:block) => {{
36        #[allow(clippy::unused_unit)]
37        #[cfg(panic = "abort")]
38        {
39            if true {
40                #[allow(unused_mut)]
41                let mut closure = || { $code };
42                closure()
43            } else {
44                let _imp = $imp;
45                $ret
46            }
47        }
48        #[cfg(not(panic = "abort"))]
49        {
50            let panicked = $imp.panicked();
51            let element = $crate::glib::subclass::types::ObjectSubclassExt::obj($imp);
52            let element = unsafe { $crate::glib::prelude::Cast::unsafe_cast_ref::<$crate::Element>(element.as_ref()) };
53            if panicked.load(std::sync::atomic::Ordering::Relaxed) {
54                $crate::subclass::post_panic_error_message(
55                    element,
56                    $crate::glib::prelude::Cast::upcast_ref::<$crate::Object>(element),
57                    None,
58                );
59                $ret
60            } else {
61                let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| $code));
62
63                match result {
64                    Ok(result) => result,
65                    Err(err) => {
66                        panicked.store(true, std::sync::atomic::Ordering::Relaxed);
67                        $crate::subclass::post_panic_error_message(
68                            element,
69                            $crate::glib::prelude::Cast::upcast_ref::<$crate::Object>(element),
70                            Some(err),
71                        );
72                        $ret
73                    }
74                }
75            }
76        }
77    }};
78);
79
80#[derive(Clone, Debug, PartialEq, Eq, Error)]
81pub enum FlowError {
82    #[error("Flushing")]
83    Flushing,
84    #[error("Eos")]
85    Eos,
86    #[error("Not Negotiated")]
87    NotNegotiated(ErrorMessage),
88    #[error("Error")]
89    Error(ErrorMessage),
90}
91
92impl From<FlowError> for FlowReturn {
93    fn from(err: FlowError) -> Self {
94        FlowReturn::from(&err)
95    }
96}
97
98impl From<&FlowError> for FlowReturn {
99    fn from(err: &FlowError) -> FlowReturn {
100        match *err {
101            FlowError::Flushing => FlowReturn::Flushing,
102            FlowError::Eos => FlowReturn::Eos,
103            FlowError::NotNegotiated(..) => FlowReturn::NotNegotiated,
104            FlowError::Error(..) => FlowReturn::Error,
105        }
106    }
107}