glib/
boxed.rs

1// Copyright 2015-2016, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5//! `IMPL` Boxed wrapper implementation.
6
7use std::cmp;
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::marker::PhantomData;
11use std::mem;
12use std::ops::{Deref, DerefMut};
13use std::ptr;
14use translate::*;
15
16/// Wrapper implementations for Boxed types. See `glib_wrapper!`.
17#[macro_export]
18macro_rules! glib_boxed_wrapper {
19    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
20     @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr,
21     @get_type $get_type_expr:expr) => {
22        glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
23        glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr,
24                            @init $init_arg $init_expr, @clear $clear_arg $clear_expr);
25        glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr);
26    };
27
28    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
29     @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => {
30        glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
31        glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr,
32                            @init $init_arg $init_expr, @clear $clear_arg $clear_expr);
33    };
34
35    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
36     @free $free_arg:ident $free_expr:expr) => {
37        glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
38        glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr);
39    };
40
41    ([$($attr:meta)*] $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr,
42     @free $free_arg:ident $free_expr:expr, @get_type $get_type_expr:expr) => {
43        glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name);
44        glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr);
45        glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr);
46    };
47
48    (@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:path) => {
49        $(#[$attr])*
50        #[derive(Clone)]
51        pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>);
52        #[doc(hidden)]
53        impl $crate::translate::GlibPtrDefault for $name {
54            type GlibType = *mut $ffi_name;
55        }
56
57        #[doc(hidden)]
58        impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name {
59            type Storage = &'a $crate::boxed::Boxed<$ffi_name, MemoryManager>;
60
61            #[inline]
62            fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
63                let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.0);
64                $crate::translate::Stash(stash.0, stash.1)
65            }
66
67            #[inline]
68            fn to_glib_full(&self) -> *const $ffi_name {
69                $crate::translate::ToGlibPtr::to_glib_full(&self.0)
70            }
71        }
72
73        #[doc(hidden)]
74        impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name {
75            type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, MemoryManager>;
76
77            #[inline]
78            fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> {
79                let stash = $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut self.0);
80                $crate::translate::StashMut(stash.0, stash.1)
81            }
82        }
83
84        #[doc(hidden)]
85        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name {
86            type Storage = (Vec<$crate::translate::Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);
87
88            fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
89                let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect();
90                let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect();
91                v_ptr.push(::std::ptr::null_mut() as *const $ffi_name);
92
93                (v_ptr.as_ptr() as *mut *const $ffi_name, (v, Some(v_ptr)))
94            }
95
96            fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) {
97                let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect();
98
99                let v_ptr = unsafe {
100                    let v_ptr = $crate::glib_sys::g_malloc0(::std::mem::size_of::<*const $ffi_name>() * (t.len() + 1)) as *mut *const $ffi_name;
101
102                    for (i, s) in v.iter().enumerate() {
103                        ::std::ptr::write(v_ptr.add(i), s.0);
104                    }
105
106                    v_ptr
107                };
108
109                (v_ptr, (v, None))
110            }
111
112            fn to_glib_full_from_slice(t: &[$name]) -> *mut *const $ffi_name {
113                unsafe {
114                    let v_ptr = $crate::glib_sys::g_malloc0(::std::mem::size_of::<*const $ffi_name>() * (t.len() + 1)) as *mut *const $ffi_name;
115
116                    for (i, s) in t.iter().enumerate() {
117                        ::std::ptr::write(v_ptr.add(i), $crate::translate::ToGlibPtr::to_glib_full(s));
118                    }
119
120                    v_ptr
121                }
122            }
123        }
124
125        #[doc(hidden)]
126        impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name {
127            type Storage = (Vec<$crate::translate::Stash<'a, *const $ffi_name, $name>>, Option<Vec<*const $ffi_name>>);
128
129            fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
130                let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *const $ffi_name>::to_glib_none_from_slice(t);
131                (ptr as *const *const $ffi_name, stash)
132            }
133
134            fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) {
135                // Can't have consumer free a *const pointer
136                unimplemented!()
137            }
138
139            fn to_glib_full_from_slice(_: &[$name]) -> *const *const $ffi_name {
140                // Can't have consumer free a *const pointer
141                unimplemented!()
142            }
143        }
144
145        #[doc(hidden)]
146        impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name {
147            #[inline]
148            unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
149                $name($crate::translate::from_glib_none(ptr))
150            }
151        }
152
153        #[doc(hidden)]
154        impl $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name {
155            #[inline]
156            unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self {
157                $name($crate::translate::from_glib_none(ptr))
158            }
159        }
160
161        #[doc(hidden)]
162        impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name {
163            #[inline]
164            unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
165                $name($crate::translate::from_glib_full(ptr))
166            }
167        }
168
169        #[doc(hidden)]
170        impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name {
171            #[inline]
172            unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self {
173                $name($crate::translate::from_glib_borrow(ptr))
174            }
175        }
176
177        #[doc(hidden)]
178        impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name {
179            #[inline]
180            unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> Self {
181                $crate::translate::from_glib_borrow(ptr as *mut $ffi_name)
182            }
183        }
184
185        #[doc(hidden)]
186        impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
187            unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
188                if num == 0 || ptr.is_null() {
189                    return Vec::new();
190                }
191
192                let mut res = Vec::with_capacity(num);
193                for i in 0..num {
194                    res.push($crate::translate::from_glib_none(::std::ptr::read(ptr.add(i))));
195                }
196                res
197            }
198
199            unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
200                let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num);
201                $crate::glib_sys::g_free(ptr as *mut _);
202                res
203            }
204
205            unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec<Self> {
206                if num == 0 || ptr.is_null() {
207                    return Vec::new();
208                }
209
210                let mut res = Vec::with_capacity(num);
211                for i in 0..num {
212                    res.push($crate::translate::from_glib_full(::std::ptr::read(ptr.add(i))));
213                }
214                $crate::glib_sys::g_free(ptr as *mut _);
215                res
216            }
217        }
218
219        #[doc(hidden)]
220        impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name {
221            unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
222                $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
223            }
224
225            unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
226                $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
227            }
228
229            unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec<Self> {
230                $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr))
231            }
232        }
233    };
234
235    (@value_impl $name:ident, $ffi_name:path, @get_type $get_type_expr:expr) => {
236        impl $crate::types::StaticType for $name {
237            fn static_type() -> $crate::types::Type {
238                #[allow(unused_unsafe)]
239                unsafe { $crate::translate::from_glib($get_type_expr) }
240            }
241        }
242
243        #[doc(hidden)]
244        impl<'a> $crate::value::FromValueOptional<'a> for $name {
245            unsafe fn from_value_optional(value: &$crate::Value) -> Option<Self> {
246                $crate::translate::from_glib_full($crate::gobject_sys::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name)
247            }
248        }
249
250        #[doc(hidden)]
251        impl $crate::value::SetValue for $name {
252            unsafe fn set_value(value: &mut $crate::Value, this: &Self) {
253                $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)
254            }
255        }
256
257        #[doc(hidden)]
258        impl $crate::value::SetValueOptional for $name {
259            unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) {
260                $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)
261            }
262        }
263    };
264
265    (@memory_manager_impl $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => {
266        #[doc(hidden)]
267        pub struct MemoryManager;
268
269        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
270            #[inline]
271            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
272                $copy_expr
273            }
274
275            #[inline]
276            unsafe fn free($free_arg: *mut $ffi_name) {
277                $free_expr
278            }
279
280            #[inline]
281            unsafe fn init(_: *mut $ffi_name) {
282                unimplemented!()
283            }
284
285            #[inline]
286            unsafe fn clear(_: *mut $ffi_name) {
287                unimplemented!()
288            }
289        }
290    };
291
292    (@memory_manager_impl $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr,
293         @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => {
294        #[doc(hidden)]
295        pub struct MemoryManager;
296
297        impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager {
298            #[inline]
299            unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name {
300                $copy_expr
301            }
302
303            #[inline]
304            unsafe fn free($free_arg: *mut $ffi_name) {
305                $free_expr
306            }
307
308            #[inline]
309            unsafe fn init($init_arg: *mut $ffi_name) {
310                $init_expr
311            }
312
313            #[inline]
314            unsafe fn clear($clear_arg: *mut $ffi_name) {
315                $clear_expr
316            }
317        }
318
319        #[doc(hidden)]
320        impl $crate::translate::Uninitialized for $name {
321            #[inline]
322            unsafe fn uninitialized() -> Self {
323                $name($crate::boxed::Boxed::uninitialized())
324            }
325        }
326    };
327}
328
329enum AnyBox<T> {
330    Native(Box<T>),
331    ForeignOwned(ptr::NonNull<T>),
332    ForeignBorrowed(ptr::NonNull<T>),
333}
334
335impl<T> fmt::Debug for AnyBox<T> {
336    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
337        use self::AnyBox::*;
338        match *self {
339            Native(ref b) => f.debug_tuple("Native").field(&(&**b as *const T)).finish(),
340            ForeignOwned(ptr) => f.debug_tuple("ForeignOwned").field(&ptr).finish(),
341            ForeignBorrowed(ptr) => f.debug_tuple("ForeignBorrowed").field(&ptr).finish(),
342        }
343    }
344}
345
346/// Memory management functions for a boxed type.
347pub trait BoxedMemoryManager<T>: 'static {
348    /// Makes a copy.
349    unsafe fn copy(ptr: *const T) -> *mut T;
350    /// Frees the object.
351    unsafe fn free(ptr: *mut T);
352    /// Initializes an already allocated object.
353    unsafe fn init(ptr: *mut T);
354    /// Clears and frees all memory of the object, but not the object itself.
355    unsafe fn clear(ptr: *mut T);
356}
357
358/// Encapsulates memory management logic for boxed types.
359pub struct Boxed<T: 'static, MM: BoxedMemoryManager<T>> {
360    inner: AnyBox<T>,
361    _dummy: PhantomData<MM>,
362}
363
364impl<T: 'static, MM: BoxedMemoryManager<T>> Uninitialized for Boxed<T, MM> {
365    #[inline]
366    unsafe fn uninitialized() -> Self {
367        Boxed {
368            inner: {
369                let mut inner = Box::<T>::new(mem::zeroed());
370                MM::init(&mut *inner);
371
372                AnyBox::Native(inner)
373            },
374            _dummy: PhantomData,
375        }
376    }
377}
378
379impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtr<'a, *const T> for Boxed<T, MM> {
380    type Storage = &'a Self;
381
382    #[inline]
383    fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> {
384        use self::AnyBox::*;
385        let ptr = match self.inner {
386            Native(ref b) => &**b as *const T,
387            ForeignOwned(p) | ForeignBorrowed(p) => p.as_ptr(),
388        };
389        Stash(ptr, self)
390    }
391
392    #[inline]
393    fn to_glib_full(&self) -> *const T {
394        use self::AnyBox::*;
395        let ptr = match self.inner {
396            Native(ref b) => &**b as *const T,
397            ForeignOwned(p) | ForeignBorrowed(p) => p.as_ptr(),
398        };
399        unsafe { MM::copy(ptr) }
400    }
401}
402
403impl<'a, T: 'static, MM: BoxedMemoryManager<T>> ToGlibPtrMut<'a, *mut T> for Boxed<T, MM> {
404    type Storage = &'a mut Self;
405
406    #[inline]
407    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> {
408        use self::AnyBox::*;
409        let ptr = match self.inner {
410            Native(ref mut b) => &mut **b as *mut T,
411            ForeignOwned(p) | ForeignBorrowed(p) => p.as_ptr(),
412        };
413        StashMut(ptr, self)
414    }
415}
416
417impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrNone<*mut T> for Boxed<T, MM> {
418    #[inline]
419    unsafe fn from_glib_none(ptr: *mut T) -> Self {
420        assert!(!ptr.is_null());
421        let ptr = MM::copy(ptr);
422        from_glib_full(ptr)
423    }
424}
425
426impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrNone<*const T> for Boxed<T, MM> {
427    #[inline]
428    unsafe fn from_glib_none(ptr: *const T) -> Self {
429        assert!(!ptr.is_null());
430        let ptr = MM::copy(ptr);
431        from_glib_full(ptr)
432    }
433}
434
435impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrFull<*mut T> for Boxed<T, MM> {
436    #[inline]
437    unsafe fn from_glib_full(ptr: *mut T) -> Self {
438        assert!(!ptr.is_null());
439        Boxed {
440            inner: AnyBox::ForeignOwned(ptr::NonNull::new_unchecked(ptr)),
441            _dummy: PhantomData,
442        }
443    }
444}
445
446impl<T: 'static, MM: BoxedMemoryManager<T>> FromGlibPtrBorrow<*mut T> for Boxed<T, MM> {
447    #[inline]
448    unsafe fn from_glib_borrow(ptr: *mut T) -> Self {
449        assert!(!ptr.is_null());
450        Boxed {
451            inner: AnyBox::ForeignBorrowed(ptr::NonNull::new_unchecked(ptr)),
452            _dummy: PhantomData,
453        }
454    }
455}
456
457impl<T: 'static, MM: BoxedMemoryManager<T>> Drop for Boxed<T, MM> {
458    #[inline]
459    fn drop(&mut self) {
460        unsafe {
461            match self.inner {
462                AnyBox::ForeignOwned(ptr) => {
463                    MM::free(ptr.as_ptr());
464                }
465                AnyBox::Native(ref mut box_) => {
466                    MM::clear(&mut **box_);
467                }
468                _ => (),
469            }
470        }
471    }
472}
473
474impl<T: 'static, MM: BoxedMemoryManager<T>> fmt::Debug for Boxed<T, MM> {
475    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
476        f.debug_struct("Boxed").field("inner", &self.inner).finish()
477    }
478}
479
480impl<T, MM: BoxedMemoryManager<T>> PartialOrd for Boxed<T, MM> {
481    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
482        self.to_glib_none().0.partial_cmp(&other.to_glib_none().0)
483    }
484}
485
486impl<T, MM: BoxedMemoryManager<T>> Ord for Boxed<T, MM> {
487    fn cmp(&self, other: &Self) -> cmp::Ordering {
488        self.to_glib_none().0.cmp(&other.to_glib_none().0)
489    }
490}
491
492impl<T, MM: BoxedMemoryManager<T>> PartialEq for Boxed<T, MM> {
493    fn eq(&self, other: &Self) -> bool {
494        self.to_glib_none().0 == other.to_glib_none().0
495    }
496}
497
498impl<T, MM: BoxedMemoryManager<T>> Eq for Boxed<T, MM> {}
499
500impl<T, MM: BoxedMemoryManager<T>> Hash for Boxed<T, MM> {
501    fn hash<H>(&self, state: &mut H)
502    where
503        H: Hasher,
504    {
505        self.to_glib_none().0.hash(state)
506    }
507}
508
509impl<T: 'static, MM: BoxedMemoryManager<T>> Clone for Boxed<T, MM> {
510    #[inline]
511    fn clone(&self) -> Self {
512        unsafe { from_glib_none(self.to_glib_none().0 as *mut T) }
513    }
514}
515
516impl<T: 'static, MM: BoxedMemoryManager<T>> Deref for Boxed<T, MM> {
517    type Target = T;
518
519    fn deref(&self) -> &T {
520        unsafe {
521            // This is safe because the pointer will remain valid while self is borrowed
522            &*self.to_glib_none().0
523        }
524    }
525}
526
527impl<T: 'static, MM: BoxedMemoryManager<T>> DerefMut for Boxed<T, MM> {
528    fn deref_mut(&mut self) -> &mut T {
529        unsafe {
530            // This is safe because the pointer will remain valid while self is borrowed
531            &mut *self.to_glib_none_mut().0
532        }
533    }
534}