Repository: gtk-rs/gtk3-rs (language: rust)

Issue:
Migrate more structs from manually implemented to glib::wrapper! with BoxedInline
CC @GuillaumeGomez 

See https://github.com/gtk-rs/gtk3-rs/pull/639

Similar things can also be done to other plain structs. Searching for #[repr(transparent)] and #[repr(C)] gives a few more candidates. Everything except for `gdk::Atom` should be doable.


Discussion / hints:

Fix patch:
diff --git a/gdk/src/geometry.rs b/gdk/src/geometry.rs
index 20586d5c9ab2..e4f25a95c265 100644
--- a/gdk/src/geometry.rs
+++ b/gdk/src/geometry.rs
@@ -2,66 +2,63 @@
 
 use crate::Gravity;
 use glib::translate::*;
+use std::fmt;
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[repr(C)]
-#[doc(alias = "GdkGeometry")]
-pub struct Geometry {
-    pub min_width: i32,
-    pub min_height: i32,
-    pub max_width: i32,
-    pub max_height: i32,
-    pub base_width: i32,
-    pub base_height: i32,
-    pub width_inc: i32,
-    pub height_inc: i32,
-    pub min_aspect: f64,
-    pub max_aspect: f64,
-    pub win_gravity: Gravity,
+glib::wrapper! {
+    #[doc(alias = "GdkGeometry")]
+    pub struct Geometry(BoxedInline<ffi::GdkGeometry>);
 }
 
-#[doc(hidden)]
-impl<'a> ToGlibPtr<'a, *const ffi::GdkGeometry> for Geometry {
-    type Storage = &'a Self;
-
-    #[inline]
-    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GdkGeometry, Self> {
-        let ptr: *const Geometry = &*self;
-        Stash(ptr as *const ffi::GdkGeometry, self)
+impl Geometry {
+    pub fn min_width(&self) -> i32 {
+        self.0.min_width
     }
-}
-
-#[doc(hidden)]
-impl<'a> ToGlibPtrMut<'a, *mut ffi::GdkGeometry> for Geometry {
-    type Storage = &'a mut Self;
-
-    #[inline]
-    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GdkGeometry, Self> {
-        let ptr: *mut Geometry = &mut *self;
-        StashMut(ptr as *mut ffi::GdkGeometry, self)
+    pub fn min_height(&self) -> i32 {
+        self.0.min_height
     }
-}
-
-#[doc(hidden)]
-impl FromGlibPtrNone<*const ffi::GdkGeometry> for Geometry {
-    unsafe fn from_glib_none(ptr: *const ffi::GdkGeometry) -> Self {
-        *(ptr as *const Geometry)
+    pub fn max_width(&self) -> i32 {
+        self.0.max_width
     }
-}
-
-#[doc(hidden)]
-impl FromGlibPtrNone<*mut ffi::GdkGeometry> for Geometry {
-    unsafe fn from_glib_none(ptr: *mut ffi::GdkGeometry) -> Self {
-        *(ptr as *mut Geometry)
+    pub fn max_height(&self) -> i32 {
+        self.0.max_height
+    }
+    pub fn base_width(&self) -> i32 {
+        self.0.base_width
+    }
+    pub fn base_height(&self) -> i32 {
+        self.0.base_height
+    }
+    pub fn width_inc(&self) -> i32 {
+        self.0.width_inc
+    }
+    pub fn height_inc(&self) -> i32 {
+        self.0.height_inc
+    }
+    pub fn min_aspect(&self) -> f64 {
+        self.0.min_aspect
+    }
+    pub fn max_aspect(&self) -> f64 {
+        self.0.max_aspect
+    }
+    pub fn win_gravity(&self) -> Gravity {
+        unsafe { from_glib(self.0.win_gravity) }
     }
 }
 
-#[doc(hidden)]
-impl FromGlibPtrFull<*mut ffi::GdkGeometry> for Geometry {
-    #[inline]
-    unsafe fn from_glib_full(ptr: *mut ffi::GdkGeometry) -> Self {
-        let geom = *(ptr as *mut Geometry);
-        glib::ffi::g_free(ptr as *mut _);
-        geom
+impl fmt::Debug for Geometry {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Geometry")
+            .field("min_width", &self.min_width())
+            .field("min_height", &self.min_height())
+            .field("max_width", &self.max_width())
+            .field("max_height", &self.max_height())
+            .field("base_width", &self.base_width())
+            .field("base_height", &self.base_height())
+            .field("width_inc", &self.width_inc())
+            .field("height_inc", &self.height_inc())
+            .field("min_aspect", &self.min_aspect())
+            .field("max_aspect", &self.max_aspect())
+            .field("win_gravity", &self.win_gravity())
+            .finish()
     }
 }
diff --git a/gdk/src/keymap_key.rs b/gdk/src/keymap_key.rs
index 8e4471b311a7..bfd07ac8070d 100644
--- a/gdk/src/keymap_key.rs
+++ b/gdk/src/keymap_key.rs
@@ -1,58 +1,30 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
-use glib::translate::*;
+use std::fmt;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-#[repr(C)]
-#[doc(alias = "GdkKeymapKey")]
-pub struct KeymapKey {
-    pub keycode: u32,
-    pub group: i32,
-    pub level: i32,
+glib::wrapper! {
+    #[doc(alias = "GdkKeymapKey")]
+    pub struct KeymapKey(BoxedInline<ffi::GdkKeymapKey>);
 }
 
-#[doc(hidden)]
-impl<'a> ToGlibPtr<'a, *const ffi::GdkKeymapKey> for KeymapKey {
-    type Storage = &'a Self;
-
-    #[inline]
-    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GdkKeymapKey, Self> {
-        let ptr: *const KeymapKey = &*self;
-        Stash(ptr as *const ffi::GdkKeymapKey, self)
+impl KeymapKey {
+    pub fn keycode(&self) -> u32 {
+        self.0.keycode
     }
-}
-
-#[doc(hidden)]
-impl<'a> ToGlibPtrMut<'a, *mut ffi::GdkKeymapKey> for KeymapKey {
-    type Storage = &'a mut Self;
-
-    #[inline]
-    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GdkKeymapKey, Self> {
-        let ptr: *mut KeymapKey = &mut *self;
-        StashMut(ptr as *mut ffi::GdkKeymapKey, self)
+    pub fn group(&self) -> i32 {
+        self.0.group
     }
-}
-
-#[doc(hidden)]
-impl FromGlibPtrNone<*const ffi::GdkKeymapKey> for KeymapKey {
-    unsafe fn from_glib_none(ptr: *const ffi::GdkKeymapKey) -> Self {
-        *(ptr as *const KeymapKey)
-    }
-}
-
-#[doc(hidden)]
-impl FromGlibPtrNone<*mut ffi::GdkKeymapKey> for KeymapKey {
-    unsafe fn from_glib_none(ptr: *mut ffi::GdkKeymapKey) -> Self {
-        *(ptr as *mut KeymapKey)
+    pub fn level(&self) -> i32 {
+        self.0.level
     }
 }
 
-#[doc(hidden)]
-impl FromGlibPtrFull<*mut ffi::GdkKeymapKey> for KeymapKey {
-    #[inline]
-    unsafe fn from_glib_full(ptr: *mut ffi::GdkKeymapKey) -> Self {
-        let geom = *(ptr as *mut KeymapKey);
-        glib::ffi::g_free(ptr as *mut _);
-        geom
+impl fmt::Debug for KeymapKey {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Geometry")
+            .field("keycode", &self.keycode())
+            .field("group", &self.group())
+            .field("level", &self.level())
+            .finish()
     }
 }
diff --git a/gtk/src/page_range.rs b/gtk/src/page_range.rs
index a3b2ef9d29cc..21024b47a5d3 100644
--- a/gtk/src/page_range.rs
+++ b/gtk/src/page_range.rs
@@ -1,11 +1,11 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
-use glib::translate::*;
-use std::ptr;
+use std::fmt;
 
-#[repr(C)]
-#[doc(alias = "GtkPageRange")]
-pub struct PageRange(ffi::GtkPageRange);
+glib::wrapper! {
+    #[doc(alias = "GtkPageRange")]
+    pub struct PageRange(BoxedInline<ffi::GtkPageRange>);
+}
 
 impl PageRange {
     pub fn new(start: i32, end: i32) -> PageRange {
@@ -24,35 +24,11 @@ impl PageRange {
     }
 }
 
-#[doc(hidden)]
-impl<'a> ToGlibPtr<'a, *const ffi::GtkPageRange> for PageRange {
-    type Storage = Box<ffi::GtkPageRange>;
-
-    #[inline]
-    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GtkPageRange, Self> {
-        let page_range = Box::new(self.0);
-        Stash(&*page_range, page_range)
-    }
-}
-
-impl FromGlibContainerAsVec<ffi::GtkPageRange, *mut ffi::GtkPageRange> for PageRange {
-    unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GtkPageRange, num: usize) -> Vec<Self> {
-        if num == 0 || ptr.is_null() {
-            return Vec::new();
-        }
-
-        let mut res = Vec::with_capacity(num);
-        for i in 0..num {
-            res.push(PageRange(ptr::read(ptr.add(i))));
-        }
-        res
-    }
-
-    unsafe fn from_glib_container_num_as_vec(_: *mut ffi::GtkPageRange, _: usize) -> Vec<Self> {
-        unimplemented!();
-    }
-
-    unsafe fn from_glib_full_num_as_vec(_: *mut ffi::GtkPageRange, _: usize) -> Vec<Self> {
-        unimplemented!();
+impl fmt::Debug for PageRange {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("PageRange")
+            .field("start", &self.start())
+            .field("end", &self.end())
+            .finish()
     }
 }


Test patch: