diff --git a/glib/src/lib.rs b/glib/src/lib.rs index 027ff38e4b19..da582bb65ebb 100644 --- a/glib/src/lib.rs +++ b/glib/src/lib.rs @@ -29,8 +29,8 @@ pub use self::bytes::Bytes; pub use self::closure::{Closure, RustClosure}; pub use self::error::{BoolError, Error}; pub use self::object::{ - BorrowedObject, Cast, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt, ObjectType, - SendWeakRef, WeakRef, + BorrowedObject, Cast, CastNone, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt, + ObjectType, SendWeakRef, WeakRef, }; pub use self::signal::{ signal_handler_block, signal_handler_disconnect, signal_handler_unblock, diff --git a/glib/src/object.rs b/glib/src/object.rs index 6973c8d0c1fc..9c2738249271 100644 --- a/glib/src/object.rs +++ b/glib/src/object.rs @@ -288,6 +288,79 @@ pub trait Cast: ObjectType { impl Cast for T {} +// rustdoc-stripper-ignore-next +/// Convenience trait mirroring `Cast`, implemented on `Option` types. +/// +/// # Warning +/// Inveitably this trait will discard informations about a downcast failure: +/// you don't know if the object was not of the expected type, or if it was `None`. +/// If you need to handle the downcast error, use `Cast` over a `glib::Object`. +/// +/// # Example +/// ```ignore +/// let widget: Option = list_item.child(); +/// +/// // Without using `CastNone` +/// let label = widget.unwrap().downcast::().unwrap(); +/// +/// // Using `CastNone` we can avoid the first `unwrap()` call +/// let label = widget.and_downcast::().unwrap(); +/// ```` +pub trait CastNone: Sized { + type Inner; + fn and_downcast(self) -> Option + where + Self::Inner: CanDowncast; + fn and_downcast_ref(&self) -> Option<&T> + where + Self::Inner: CanDowncast; + fn and_upcast(self) -> Option + where + Self::Inner: IsA; + fn and_upcast_ref(&self) -> Option<&T> + where + Self::Inner: IsA; + fn and_dynamic_cast(self) -> Result; + fn and_dynamic_cast_ref(&self) -> Option<&T>; +} +impl CastNone for Option { + type Inner = I; + + fn and_downcast(self) -> Option + where + Self::Inner: CanDowncast, + { + self.and_then(|i| i.downcast().ok()) + } + + fn and_downcast_ref(&self) -> Option<&T> + where + Self::Inner: CanDowncast, + { + self.as_ref().and_then(|i| i.downcast_ref()) + } + fn and_upcast(self) -> Option + where + Self::Inner: IsA, + { + self.map(|i| i.upcast()) + } + + fn and_upcast_ref(&self) -> Option<&T> + where + Self::Inner: IsA, + { + self.as_ref().map(|i| i.upcast_ref()) + } + fn and_dynamic_cast(self) -> Result { + self.ok_or(None) + .and_then(|i| i.dynamic_cast().map_err(|e| Some(e))) + } + fn and_dynamic_cast_ref(&self) -> Option<&T> { + self.as_ref().and_then(|i| i.dynamic_cast_ref()) + } +} + // rustdoc-stripper-ignore-next /// Marker trait for the statically known possibility of downcasting from `Self` to `T`. pub trait CanDowncast {} diff --git a/glib/src/prelude.rs b/glib/src/prelude.rs index 1d2b14b433d3..9e3540a25ac4 100644 --- a/glib/src/prelude.rs +++ b/glib/src/prelude.rs @@ -5,6 +5,6 @@ pub use crate::param_spec::ParamSpecBuilderExt; pub use crate::{ - Cast, Continue, IsA, ObjectExt, ObjectType, ParamSpecType, StaticType, StaticTypeExt, + Cast, CastNone, Continue, IsA, ObjectExt, ObjectType, ParamSpecType, StaticType, StaticTypeExt, StaticVariantType, ToSendValue, ToValue, ToVariant, };