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"
|
thiserror = "1"
|
||||||
smallvec = { version = "1.0", features = ["write"] }
|
smallvec = { version = "1.0", features = ["write"] }
|
||||||
itertools = "0.11"
|
itertools = "0.11"
|
||||||
|
pin-project-lite = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Take a look at the license at the top of the repository in the LICENSE file.
|
// 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::*};
|
use glib::{subclass::prelude::*, translate::*};
|
||||||
|
|
||||||
|
@ -294,6 +294,18 @@ pub trait ElementImplExt: sealed::Sealed + ObjectSubclass {
|
||||||
panic_to_error!(self, fallback(), { f(self) })
|
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>(
|
fn catch_panic_pad_function<R, F: FnOnce(&Self) -> R, G: FnOnce() -> R>(
|
||||||
parent: Option<&crate::Object>,
|
parent: Option<&crate::Object>,
|
||||||
fallback: G,
|
fallback: G,
|
||||||
|
@ -316,6 +328,44 @@ pub trait ElementImplExt: sealed::Sealed + ObjectSubclass {
|
||||||
|
|
||||||
impl<T: ElementImpl> ElementImplExt for T {}
|
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 {
|
unsafe impl<T: ElementImpl> IsSubclassable<T> for Element {
|
||||||
fn class_init(klass: &mut glib::Class<Self>) {
|
fn class_init(klass: &mut glib::Class<Self>) {
|
||||||
Self::parent_class_init::<T>(klass);
|
Self::parent_class_init::<T>(klass);
|
||||||
|
|
|
@ -33,7 +33,7 @@ mod uri_handler;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
device_provider::DeviceProviderMetadata,
|
device_provider::DeviceProviderMetadata,
|
||||||
element::ElementMetadata,
|
element::{CatchPanic, ElementMetadata},
|
||||||
error::{post_panic_error_message, FlowError},
|
error::{post_panic_error_message, FlowError},
|
||||||
plugin::{MAJOR_VERSION, MINOR_VERSION},
|
plugin::{MAJOR_VERSION, MINOR_VERSION},
|
||||||
task_pool::TaskPoolFunction,
|
task_pool::TaskPoolFunction,
|
||||||
|
|
Loading…
Reference in a new issue