// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Module for registering boxed types for Rust types. use crate::{prelude::*, translate::*}; // rustdoc-stripper-ignore-next /// Trait for defining boxed types. /// /// Links together the type name with the type itself. /// /// See [`register_boxed_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_boxed_type`]: fn.register_boxed_type.html pub trait BoxedType: StaticType + Clone + Sized + 'static { // rustdoc-stripper-ignore-next /// Boxed type name. /// /// This must be unique in the whole process. const NAME: &'static str; } // rustdoc-stripper-ignore-next /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`Boxed!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`Boxed!`]: ../../derive.Boxed.html pub fn register_boxed_type() -> crate::Type { unsafe extern "C" fn boxed_copy(v: ffi::gpointer) -> ffi::gpointer { let v = &*(v as *mut T); let copy = Box::new(v.clone()); Box::into_raw(copy) as ffi::gpointer } unsafe extern "C" fn boxed_free(v: ffi::gpointer) { let v = v as *mut T; let _ = Box::from_raw(v); } unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID, "Type {} has already been registered", type_name.to_str().unwrap() ); let type_ = crate::Type::from_glib(gobject_ffi::g_boxed_type_register_static( type_name.as_ptr(), Some(boxed_copy::), Some(boxed_free::), )); assert!(type_.is_valid()); type_ } } #[cfg(test)] mod test { // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::prelude::*; use crate::translate::{FromGlibPtrBorrow, FromGlibPtrFull, IntoGlibPtr}; #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)] #[boxed_type(name = "MyBoxed")] struct MyBoxed(String); #[test] fn test_register() { assert!(MyBoxed::static_type().is_valid()); } #[test] fn test_value() { assert!(MyBoxed::static_type().is_valid()); let b = MyBoxed(String::from("abc")); let v = b.to_value(); let b2 = v.get::<&MyBoxed>().unwrap(); assert_eq!(&b, b2); } #[test] fn test_from_glib_borrow() { assert!(MyBoxed::static_type().is_valid()); let b = MyBoxed(String::from("abc")); let raw_ptr = unsafe { MyBoxed::into_glib_ptr(b) }; // test that the from_glib_borrow does not take ownership of the raw_ptr let _ = unsafe { MyBoxed::from_glib_borrow(raw_ptr) }; let new_b = unsafe { MyBoxed::from_glib_full(raw_ptr) }; assert_eq!(new_b.0, "abc".to_string()); } }