panda/plugins/
glib.rs

1//! glib wrappers for supporting glib-based plugins
2
3use glib_sys::{g_array_free, g_free, g_malloc, gpointer, GArray};
4use std::marker::PhantomData;
5use std::mem::size_of;
6use std::ops::{Deref, DerefMut};
7
8use std::ptr::NonNull;
9
10/// An owned glib-allocated value that will be freed using glib's allocator on drop.
11#[repr(transparent)]
12pub struct GBox<T>(NonNull<T>);
13
14impl<T: Sized> GBox<T> {
15    pub fn new(val: T) -> Self {
16        unsafe {
17            let ptr = g_malloc(size_of::<T>());
18            if !ptr.is_null() {
19                *(ptr as *mut T) = val;
20            }
21            Self(NonNull::new(ptr as *mut T).unwrap())
22        }
23    }
24
25    pub fn as_ptr(&self) -> *const T {
26        self.0.as_ptr()
27    }
28}
29
30impl<T> Deref for GBox<T> {
31    type Target = T;
32
33    fn deref(&self) -> &Self::Target {
34        unsafe { self.0.as_ref() }
35    }
36}
37
38impl<T> DerefMut for GBox<T> {
39    fn deref_mut(&mut self) -> &mut Self::Target {
40        unsafe { self.0.as_mut() }
41    }
42}
43
44impl<T> Drop for GBox<T> {
45    fn drop(&mut self) {
46        unsafe {
47            g_free(self.0.as_ptr() as gpointer);
48        }
49    }
50}
51
52#[repr(transparent)]
53pub struct GBoxedSlice<T>(pub *mut GArray, PhantomData<T>);
54
55impl<T> GBoxedSlice<T> {
56    pub fn is_null(&self) -> bool {
57        self.0.is_null()
58    }
59}
60
61impl<T> Deref for GBoxedSlice<T> {
62    type Target = [T];
63
64    fn deref(&self) -> &Self::Target {
65        if self.0.is_null() {
66            panic!("Invalid GBoxedSlice: null");
67        } else {
68            let g_array = unsafe { &*self.0 };
69
70            if g_array.data.is_null() {
71                &[]
72            } else {
73                unsafe { std::slice::from_raw_parts(g_array.data as _, g_array.len as usize) }
74            }
75        }
76    }
77}
78
79impl<T> DerefMut for GBoxedSlice<T> {
80    fn deref_mut(&mut self) -> &mut Self::Target {
81        if self.0.is_null() {
82            panic!("Invalid GBoxedSlice: null");
83        }
84        let g_array = unsafe { &mut *self.0 };
85
86        if g_array.data.is_null() {
87            &mut []
88        } else {
89            unsafe { std::slice::from_raw_parts_mut(g_array.data as *mut T, g_array.len as usize) }
90        }
91    }
92}
93
94impl<T> Drop for GBoxedSlice<T> {
95    fn drop(&mut self) {
96        if !self.0.is_null() {
97            unsafe {
98                g_array_free(self.0, true as _);
99            }
100        }
101    }
102}