1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// 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<T: BoxedType>() -> crate::Type {
unsafe extern "C" fn boxed_copy<T: BoxedType>(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<T: BoxedType>(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::<T>),
Some(boxed_free::<T>),
));
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());
}
}