gstreamer-rs/gstreamer/src/subclass/error.rs
Sebastian Dröge b468280353 Improve code generation with panic=abort around panic handling code
None of that can ever be called in that case but the compiler can't know
that in more complicated cases like these. Handling it explicitly allows
no handling code to be generated at all here, like would already happen
everywhere else.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1441>
2024-05-16 16:38:15 +03:00

108 lines
3.2 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use thiserror::Error;
use crate::{prelude::ElementExt, ErrorMessage, FlowReturn};
#[doc(hidden)]
#[inline(never)]
pub fn post_panic_error_message(
element: &crate::Element,
src: &crate::Object,
panic: Option<Box<dyn std::any::Any + Send + 'static>>,
) {
let cause = panic.as_ref().and_then(|err| {
err.downcast_ref::<&str>()
.copied()
.or_else(|| err.downcast_ref::<String>().map(|s| s.as_str()))
});
let msg = if let Some(cause) = cause {
crate::message::Error::builder(crate::LibraryError::Failed, &format!("Panicked: {cause}"))
.src(src)
.build()
} else {
crate::message::Error::builder(crate::LibraryError::Failed, "Panicked")
.src(src)
.build()
};
let _ = element.post_message(msg);
}
#[macro_export]
macro_rules! panic_to_error(
($imp:expr, $ret:expr, $code:block) => {{
#[allow(clippy::unused_unit)]
#[cfg(panic = "abort")]
{
if true {
#[allow(unused_mut)]
let mut closure = || { $code };
closure()
} else {
let _imp = $imp;
$ret
}
}
#[cfg(not(panic = "abort"))]
{
let panicked = $imp.panicked();
let element = $crate::glib::subclass::types::ObjectSubclassExt::obj($imp);
let element = unsafe { $crate::glib::prelude::Cast::unsafe_cast_ref::<$crate::Element>(element.as_ref()) };
if panicked.load(std::sync::atomic::Ordering::Relaxed) {
$crate::subclass::post_panic_error_message(
element,
$crate::glib::prelude::Cast::upcast_ref::<$crate::Object>(element),
None,
);
$ret
} else {
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| $code));
match result {
Ok(result) => result,
Err(err) => {
panicked.store(true, std::sync::atomic::Ordering::Relaxed);
$crate::subclass::post_panic_error_message(
element,
$crate::glib::prelude::Cast::upcast_ref::<$crate::Object>(element),
Some(err),
);
$ret
}
}
}
}
}};
);
#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum FlowError {
#[error("Flushing")]
Flushing,
#[error("Eos")]
Eos,
#[error("Not Negotiated")]
NotNegotiated(ErrorMessage),
#[error("Error")]
Error(ErrorMessage),
}
impl From<FlowError> for FlowReturn {
fn from(err: FlowError) -> Self {
FlowReturn::from(&err)
}
}
impl<'a> From<&'a FlowError> for FlowReturn {
fn from(err: &FlowError) -> FlowReturn {
match *err {
FlowError::Flushing => FlowReturn::Flushing,
FlowError::Eos => FlowReturn::Eos,
FlowError::NotNegotiated(..) => FlowReturn::NotNegotiated,
FlowError::Error(..) => FlowReturn::Error,
}
}
}