forked from mirrors/gstreamer-rs
element: Add catch_panic_future()
helper function for subclasses
This allows wrapping a future in a way that panics are converted to error messages on the object. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
This commit is contained in:
parent
27380d237c
commit
df223af719
3 changed files with 53 additions and 2 deletions
|
@ -32,6 +32,7 @@ pretty-hex = "0.3"
|
|||
thiserror = "1"
|
||||
smallvec = { version = "1.0", features = ["write"] }
|
||||
itertools = "0.11"
|
||||
pin-project-lite = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
ron = "0.8"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Take a look at the license at the top of the repository in the LICENSE file.
|
||||
|
||||
use std::{borrow::Cow, sync::atomic};
|
||||
use std::{borrow::Cow, future::Future, sync::atomic};
|
||||
|
||||
use glib::{subclass::prelude::*, translate::*};
|
||||
|
||||
|
@ -294,6 +294,18 @@ pub trait ElementImplExt: sealed::Sealed + ObjectSubclass {
|
|||
panic_to_error!(self, fallback(), { f(self) })
|
||||
}
|
||||
|
||||
fn catch_panic_future<R, F: FnOnce() -> R, G: Future<Output = R>>(
|
||||
&self,
|
||||
fallback: F,
|
||||
fut: G,
|
||||
) -> CatchPanic<Self, F, G> {
|
||||
CatchPanic {
|
||||
self_: self.ref_counted().downgrade(),
|
||||
fallback: Some(fallback),
|
||||
fut,
|
||||
}
|
||||
}
|
||||
|
||||
fn catch_panic_pad_function<R, F: FnOnce(&Self) -> R, G: FnOnce() -> R>(
|
||||
parent: Option<&crate::Object>,
|
||||
fallback: G,
|
||||
|
@ -316,6 +328,44 @@ pub trait ElementImplExt: sealed::Sealed + ObjectSubclass {
|
|||
|
||||
impl<T: ElementImpl> ElementImplExt for T {}
|
||||
|
||||
pin_project_lite::pin_project! {
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct CatchPanic<T: glib::subclass::types::ObjectSubclass, F, G> {
|
||||
self_: glib::subclass::ObjectImplWeakRef<T>,
|
||||
fallback: Option<F>,
|
||||
#[pin]
|
||||
fut: G,
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, T: ElementImpl, F: FnOnce() -> R, G: Future<Output = R>> Future for CatchPanic<T, F, G> {
|
||||
type Output = R;
|
||||
|
||||
fn poll(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
let Some(self_) = this.self_.upgrade() else {
|
||||
return std::task::Poll::Ready((this
|
||||
.fallback
|
||||
.take()
|
||||
.expect("Future polled after resolving"))(
|
||||
));
|
||||
};
|
||||
|
||||
panic_to_error!(
|
||||
&*self_,
|
||||
std::task::Poll::Ready(this.fallback.take().expect("Future polled after resolving")()),
|
||||
{
|
||||
let fut = this.fut;
|
||||
fut.poll(cx)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ElementImpl> IsSubclassable<T> for Element {
|
||||
fn class_init(klass: &mut glib::Class<Self>) {
|
||||
Self::parent_class_init::<T>(klass);
|
||||
|
|
|
@ -33,7 +33,7 @@ mod uri_handler;
|
|||
|
||||
pub use self::{
|
||||
device_provider::DeviceProviderMetadata,
|
||||
element::ElementMetadata,
|
||||
element::{CatchPanic, ElementMetadata},
|
||||
error::{post_panic_error_message, FlowError},
|
||||
plugin::{MAJOR_VERSION, MINOR_VERSION},
|
||||
task_pool::TaskPoolFunction,
|
||||
|
|
Loading…
Reference in a new issue