Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

Commit

Permalink
Add init/clear function for boxed types
Browse files Browse the repository at this point in the history
These allow allocated them on our side and releasing all memory of them
again. It is needed for functions that take an out parameter and require
us to allocate the underlying object.

Fixes #469
  • Loading branch information
sdroege committed Jun 10, 2019
1 parent 34b8df4 commit c54924e
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 68 deletions.
203 changes: 135 additions & 68 deletions src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,69 +17,38 @@ use translate::*;
#[macro_export]
macro_rules! glib_boxed_wrapper {
([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
@free $free_arg:ident $free_expr:expr,
@free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr,
@get_type $get_type_expr:expr) => {
glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
@free $free_arg $free_expr);

impl $crate::types::StaticType for $name {
fn static_type() -> $crate::types::Type {
#[allow(unused_unsafe)]
unsafe { $crate::translate::from_glib($get_type_expr) }
}
}

#[doc(hidden)]
impl<'a> $crate::value::FromValueOptional<'a> for $name {
unsafe fn from_value_optional(value: &$crate::Value) -> Option<Self> {
$crate::translate::from_glib_full($crate::gobject_sys::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name)
}
}

#[doc(hidden)]
impl $crate::value::SetValue for $name {
unsafe fn set_value(value: &mut $crate::Value, this: &Self) {
$crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(this).0 as $crate::glib_sys::gpointer)
}
}
glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr,
@init $init_arg $init_expr, @clear $clear_arg $clear_expr);
glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr);
};

#[doc(hidden)]
impl $crate::value::SetValueOptional for $name {
unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) {
$crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&this).0 as $crate::glib_sys::gpointer)
}
}
([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
@free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => {
glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr,
@init $init_arg $init_expr, @clear $clear_arg $clear_expr);
};

([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
@free $free_arg:ident $free_expr:expr) => {
glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr);
};

([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
@free $free_arg:ident $free_expr:expr, @get_type $get_type_expr:expr) => {
glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr);
glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr);
};

(@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:path) => {
$(#[$attr])*
#[derive(Clone)]
pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);

#[doc(hidden)]
pub struct MemoryManager;

impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
#[inline]
unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
$copy_expr
}

#[inline]
unsafe fn free($free_arg: *mut $ffi_name) {
$free_expr
}
}

#[doc(hidden)]
impl $crate::translate::Uninitialized for $name {
#[inline]
unsafe fn uninitialized() -> Self {
$name($crate::boxed::Boxed::uninitialized())
}
}

#[doc(hidden)]
impl $crate::translate::GlibPtrDefault for $name {
type GlibType = *mut $ffi_name;
Expand Down Expand Up @@ -261,7 +230,100 @@ macro_rules! glib_boxed_wrapper {
$crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
}
}
}
};

(@value_impl $name:ident, $ffi_name:path, @get_type $get_type_expr:expr) => {
impl $crate::types::StaticType for $name {
fn static_type() -> $crate::types::Type {
#[allow(unused_unsafe)]
unsafe { $crate::translate::from_glib($get_type_expr) }
}
}

#[doc(hidden)]
impl<'a> $crate::value::FromValueOptional<'a> for $name {
unsafe fn from_value_optional(value: &$crate::Value) -> Option<Self> {
$crate::translate::from_glib_full($crate::gobject_sys::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name)
}
}

#[doc(hidden)]
impl $crate::value::SetValue for $name {
unsafe fn set_value(value: &mut $crate::Value, this: &Self) {
$crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(this).0 as $crate::glib_sys::gpointer)
}
}

#[doc(hidden)]
impl $crate::value::SetValueOptional for $name {
unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) {
$crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&this).0 as $crate::glib_sys::gpointer)
}
}
};

(@memory_manager_impl $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => {
#[doc(hidden)]
pub struct MemoryManager;

impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
#[inline]
unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
$copy_expr
}

#[inline]
unsafe fn free($free_arg: *mut $ffi_name) {
$free_expr
}

#[inline]
unsafe fn init(_: *mut $ffi_name) {
unimplemented!()
}

#[inline]
unsafe fn clear(_: *mut $ffi_name) {
unimplemented!()
}
}
};

(@memory_manager_impl $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr,
@init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => {
#[doc(hidden)]
pub struct MemoryManager;

impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
#[inline]
unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
$copy_expr
}

#[inline]
unsafe fn free($free_arg: *mut $ffi_name) {
$free_expr
}

#[inline]
unsafe fn init($init_arg: *mut $ffi_name) {
$init_expr
}

#[inline]
unsafe fn clear($clear_arg: *mut $ffi_name) {
$clear_expr
}
}

#[doc(hidden)]
impl $crate::translate::Uninitialized for $name {
#[inline]
unsafe fn uninitialized() -> Self {
$name($crate::boxed::Boxed::uninitialized())
}
}
};
}

enum AnyBox<T> {
Expand Down Expand Up @@ -293,6 +355,10 @@ pub trait BoxedMemoryManager<T>: 'static {
unsafe fn copy(ptr: *const T) -> *mut T;
/// Frees the object.
unsafe fn free(ptr: *mut T);
/// Initializes an already allocated object.
unsafe fn init(ptr: *mut T);
/// Clears and frees all memory of the object, but not the object itself.
unsafe fn clear(ptr: *mut T);
}

/// Encapsulates memory management logic for boxed types.
Expand All @@ -301,21 +367,16 @@ pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
_dummy: PhantomData<MM>,
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Boxed<T, MM> {
#[inline]
pub unsafe fn uninitialized() -> Self {
Boxed {
inner: AnyBox::Native(Box::new(mem::uninitialized())),
_dummy: PhantomData,
}
}
}

impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
#[inline]
unsafe fn uninitialized() -> Self {
Boxed {
inner: AnyBox::Native(Box::new(mem::uninitialized())),
inner: {
let mut inner = Box::<T>::new(mem::zeroed());
MM::init(&mut *inner);

AnyBox::Native(inner)
},
_dummy: PhantomData,
}
}
Expand Down Expand Up @@ -403,8 +464,14 @@ impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
#[inline]
fn drop(&mut self) {
unsafe {
if let AnyBox::ForeignOwned(ptr) = self.inner {
MM::free(ptr.as_ptr());
match self.inner {
AnyBox::ForeignOwned(ptr) => {
MM::free(ptr.as_ptr());
}
AnyBox::Native(ref mut box_) => {
MM::clear(&mut **box_);
}
_ => (),
}
}
}
Expand Down
32 changes: 32 additions & 0 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,38 @@ macro_rules! glib_wrapper {
@free $free_arg $free_expr, @get_type $get_type_expr);
};

(
$(#[$attr:meta])*
pub struct $name:ident(Boxed<$ffi_name:path>);

match fn {
copy => |$copy_arg:ident| $copy_expr:expr,
free => |$free_arg:ident| $free_expr:expr,
init => |$init_arg:ident| $init_expr:expr,
clear => |$clear_arg:ident| $clear_expr:expr,
}
) => {
glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
@free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr);
};

(
$(#[$attr:meta])*
pub struct $name:ident(Boxed<$ffi_name:path>);

match fn {
copy => |$copy_arg:ident| $copy_expr:expr,
free => |$free_arg:ident| $free_expr:expr,
init => |$init_arg:ident| $init_expr:expr,
clear => |$clear_arg:ident| $clear_expr:expr,
get_type => || $get_type_expr:expr,
}
) => {
glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
@free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr,
@get_type $get_type_expr);
};

// Shared

(
Expand Down

0 comments on commit c54924e

Please sign in to comment.