Skip to content

Commit 6961ee4

Browse files
authored
Add CastNone trait (#843)
* Add CastNone trait Closes #842 * Add CastNone to prelude, add dynamic_cast * Add example for CastNone * Describe type using turbofish op
1 parent 346d5c2 commit 6961ee4

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

glib/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ pub use self::bytes::Bytes;
2929
pub use self::closure::{Closure, RustClosure};
3030
pub use self::error::{BoolError, Error};
3131
pub use self::object::{
32-
BorrowedObject, Cast, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt, ObjectType,
33-
SendWeakRef, WeakRef,
32+
BorrowedObject, Cast, CastNone, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt,
33+
ObjectType, SendWeakRef, WeakRef,
3434
};
3535
pub use self::signal::{
3636
signal_handler_block, signal_handler_disconnect, signal_handler_unblock,

glib/src/object.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,79 @@ pub trait Cast: ObjectType {
288288

289289
impl<T: ObjectType> Cast for T {}
290290

291+
// rustdoc-stripper-ignore-next
292+
/// Convenience trait mirroring `Cast`, implemented on `Option<Object>` types.
293+
///
294+
/// # Warning
295+
/// Inveitably this trait will discard informations about a downcast failure:
296+
/// you don't know if the object was not of the expected type, or if it was `None`.
297+
/// If you need to handle the downcast error, use `Cast` over a `glib::Object`.
298+
///
299+
/// # Example
300+
/// ```ignore
301+
/// let widget: Option<Widget> = list_item.child();
302+
///
303+
/// // Without using `CastNone`
304+
/// let label = widget.unwrap().downcast::<gtk::Label>().unwrap();
305+
///
306+
/// // Using `CastNone` we can avoid the first `unwrap()` call
307+
/// let label = widget.and_downcast::<gtk::Label>().unwrap();
308+
/// ````
309+
pub trait CastNone: Sized {
310+
type Inner;
311+
fn and_downcast<T: ObjectType>(self) -> Option<T>
312+
where
313+
Self::Inner: CanDowncast<T>;
314+
fn and_downcast_ref<T: ObjectType>(&self) -> Option<&T>
315+
where
316+
Self::Inner: CanDowncast<T>;
317+
fn and_upcast<T: ObjectType>(self) -> Option<T>
318+
where
319+
Self::Inner: IsA<T>;
320+
fn and_upcast_ref<T: ObjectType>(&self) -> Option<&T>
321+
where
322+
Self::Inner: IsA<T>;
323+
fn and_dynamic_cast<T: ObjectType>(self) -> Result<T, Self>;
324+
fn and_dynamic_cast_ref<T: ObjectType>(&self) -> Option<&T>;
325+
}
326+
impl<I: ObjectType + Sized> CastNone for Option<I> {
327+
type Inner = I;
328+
329+
fn and_downcast<T: ObjectType>(self) -> Option<T>
330+
where
331+
Self::Inner: CanDowncast<T>,
332+
{
333+
self.and_then(|i| i.downcast().ok())
334+
}
335+
336+
fn and_downcast_ref<T: ObjectType>(&self) -> Option<&T>
337+
where
338+
Self::Inner: CanDowncast<T>,
339+
{
340+
self.as_ref().and_then(|i| i.downcast_ref())
341+
}
342+
fn and_upcast<T: ObjectType>(self) -> Option<T>
343+
where
344+
Self::Inner: IsA<T>,
345+
{
346+
self.map(|i| i.upcast())
347+
}
348+
349+
fn and_upcast_ref<T: ObjectType>(&self) -> Option<&T>
350+
where
351+
Self::Inner: IsA<T>,
352+
{
353+
self.as_ref().map(|i| i.upcast_ref())
354+
}
355+
fn and_dynamic_cast<T: ObjectType>(self) -> Result<T, Self> {
356+
self.ok_or(None)
357+
.and_then(|i| i.dynamic_cast().map_err(|e| Some(e)))
358+
}
359+
fn and_dynamic_cast_ref<T: ObjectType>(&self) -> Option<&T> {
360+
self.as_ref().and_then(|i| i.dynamic_cast_ref())
361+
}
362+
}
363+
291364
// rustdoc-stripper-ignore-next
292365
/// Marker trait for the statically known possibility of downcasting from `Self` to `T`.
293366
pub trait CanDowncast<T> {}

glib/src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
66
pub use crate::param_spec::ParamSpecBuilderExt;
77
pub use crate::{
8-
Cast, Continue, IsA, ObjectExt, ObjectType, ParamSpecType, StaticType, StaticTypeExt,
8+
Cast, CastNone, Continue, IsA, ObjectExt, ObjectType, ParamSpecType, StaticType, StaticTypeExt,
99
StaticVariantType, ToSendValue, ToValue, ToVariant,
1010
};

0 commit comments

Comments
 (0)