glib/
value_array.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{cmp::Ordering, ops, slice};
4
5use crate::{
6    ffi, gobject_ffi, prelude::*, translate::*, ParamSpecValueArray, ParamSpecValueArrayBuilder,
7    Type, Value,
8};
9
10wrapper! {
11    #[derive(Debug)]
12    #[doc(alias = "GValueArray")]
13    pub struct ValueArray(Boxed<gobject_ffi::GValueArray>);
14
15    match fn {
16        copy => |ptr| gobject_ffi::g_value_array_copy(mut_override(ptr)),
17        free => |ptr| gobject_ffi::g_value_array_free(ptr),
18    }
19}
20
21impl ValueArray {
22    #[inline]
23    pub fn new(values: impl IntoIterator<Item = impl ToValue>) -> Self {
24        let iter = values.into_iter();
25        let mut array = Self::with_capacity(iter.size_hint().0);
26        for v in iter {
27            array.append(v.to_value());
28        }
29
30        array
31    }
32
33    #[inline]
34    pub fn from_values(values: impl IntoIterator<Item = Value>) -> Self {
35        Self::new(values)
36    }
37
38    #[doc(alias = "g_value_array_new")]
39    #[inline]
40    pub fn with_capacity(capacity: usize) -> ValueArray {
41        assert!(capacity <= u32::MAX as usize);
42
43        unsafe { from_glib_full(gobject_ffi::g_value_array_new(capacity as u32)) }
44    }
45
46    #[inline]
47    pub fn is_empty(&self) -> bool {
48        self.len() == 0
49    }
50
51    #[inline]
52    pub fn len(&self) -> usize {
53        self.inner.n_values as usize
54    }
55
56    #[doc(alias = "g_value_array_append")]
57    #[inline]
58    pub fn append(&mut self, value: impl ToValue) {
59        self.append_value(&value.to_value());
60    }
61
62    #[doc(alias = "g_value_array_append")]
63    #[inline]
64    pub fn append_value(&mut self, value: &Value) {
65        unsafe {
66            gobject_ffi::g_value_array_append(self.to_glib_none_mut().0, value.to_glib_none().0);
67        }
68    }
69
70    #[doc(alias = "g_value_array_insert")]
71    #[inline]
72    pub fn insert(&mut self, index_: usize, value: impl ToValue) {
73        self.insert_value(index_, &value.to_value());
74    }
75
76    #[doc(alias = "g_value_array_insert")]
77    #[inline]
78    pub fn insert_value(&mut self, index_: usize, value: &Value) {
79        assert!(index_ <= self.len());
80
81        unsafe {
82            gobject_ffi::g_value_array_insert(
83                self.to_glib_none_mut().0,
84                index_ as u32,
85                value.to_glib_none().0,
86            );
87        }
88    }
89
90    #[doc(alias = "g_value_array_prepend")]
91    #[inline]
92    pub fn prepend(&mut self, value: impl ToValue) {
93        self.prepend_value(&value.to_value());
94    }
95
96    #[doc(alias = "g_value_array_prepend")]
97    #[inline]
98    pub fn prepend_value(&mut self, value: &Value) {
99        unsafe {
100            gobject_ffi::g_value_array_prepend(self.to_glib_none_mut().0, value.to_glib_none().0);
101        }
102    }
103
104    #[doc(alias = "g_value_array_remove")]
105    #[inline]
106    pub fn remove(&mut self, index_: usize) {
107        assert!(index_ < self.len());
108
109        unsafe {
110            gobject_ffi::g_value_array_remove(self.to_glib_none_mut().0, index_ as u32);
111        }
112    }
113
114    #[doc(alias = "g_value_array_sort_with_data")]
115    pub fn sort_with_data<F: FnMut(&Value, &Value) -> Ordering>(&mut self, compare_func: F) {
116        unsafe extern "C" fn compare_func_trampoline(
117            a: ffi::gconstpointer,
118            b: ffi::gconstpointer,
119            func: ffi::gpointer,
120        ) -> i32 {
121            let func = func as *mut &mut (dyn FnMut(&Value, &Value) -> Ordering);
122
123            let a = &*(a as *const Value);
124            let b = &*(b as *const Value);
125
126            (*func)(a, b).into_glib()
127        }
128        unsafe {
129            let mut func = compare_func;
130            let func_obj: &mut (dyn FnMut(&Value, &Value) -> Ordering) = &mut func;
131            let func_ptr =
132                &func_obj as *const &mut (dyn FnMut(&Value, &Value) -> Ordering) as ffi::gpointer;
133
134            gobject_ffi::g_value_array_sort_with_data(
135                self.to_glib_none_mut().0,
136                Some(compare_func_trampoline),
137                func_ptr,
138            );
139        }
140    }
141
142    #[inline]
143    pub fn as_slice(&self) -> &[Value] {
144        if self.is_empty() {
145            return &[];
146        }
147
148        unsafe {
149            slice::from_raw_parts(
150                (*self.as_ptr()).values as *const Value,
151                (*self.as_ptr()).n_values as usize,
152            )
153        }
154    }
155
156    #[inline]
157    pub fn as_mut_slice(&mut self) -> &mut [Value] {
158        if self.is_empty() {
159            return &mut [];
160        }
161
162        unsafe {
163            slice::from_raw_parts_mut(
164                (*self.as_ptr()).values as *mut Value,
165                (*self.as_ptr()).n_values as usize,
166            )
167        }
168    }
169}
170
171impl ops::Deref for ValueArray {
172    type Target = [Value];
173
174    #[inline]
175    fn deref(&self) -> &[Value] {
176        self.as_slice()
177    }
178}
179
180impl ops::DerefMut for ValueArray {
181    #[inline]
182    fn deref_mut(&mut self) -> &mut [Value] {
183        self.as_mut_slice()
184    }
185}
186
187impl Default for ValueArray {
188    fn default() -> Self {
189        Self::with_capacity(8)
190    }
191}
192
193impl std::iter::FromIterator<Value> for ValueArray {
194    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
195        Self::from_values(iter)
196    }
197}
198
199impl std::iter::Extend<Value> for ValueArray {
200    fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
201        for v in iter.into_iter() {
202            self.append_value(&v);
203        }
204    }
205}
206
207// Implementing `Value` traits manually because of a custom ParamSpec
208impl StaticType for ValueArray {
209    #[inline]
210    fn static_type() -> Type {
211        unsafe { from_glib(gobject_ffi::g_value_array_get_type()) }
212    }
213}
214
215#[doc(hidden)]
216impl ValueType for ValueArray {
217    type Type = Self;
218}
219
220#[doc(hidden)]
221impl crate::value::ValueTypeOptional for ValueArray {}
222
223#[doc(hidden)]
224unsafe impl<'a> crate::value::FromValue<'a> for ValueArray {
225    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
226
227    #[inline]
228    unsafe fn from_value(value: &'a Value) -> Self {
229        let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0);
230        debug_assert!(!ptr.is_null());
231        from_glib_full(ptr as *mut gobject_ffi::GValueArray)
232    }
233}
234
235#[doc(hidden)]
236unsafe impl<'a> crate::value::FromValue<'a> for &'a ValueArray {
237    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
238
239    #[inline]
240    unsafe fn from_value(value: &'a Value) -> Self {
241        debug_assert_eq!(
242            std::mem::size_of::<Self>(),
243            std::mem::size_of::<ffi::gpointer>()
244        );
245        let value = &*(value as *const Value as *const gobject_ffi::GValue);
246        debug_assert!(!value.data[0].v_pointer.is_null());
247        <ValueArray>::from_glib_ptr_borrow(
248            &*(&value.data[0].v_pointer as *const ffi::gpointer
249                as *const *mut gobject_ffi::GValueArray),
250        )
251    }
252}
253
254#[doc(hidden)]
255impl ToValue for ValueArray {
256    #[inline]
257    fn to_value(&self) -> Value {
258        unsafe {
259            let mut value = Value::from_type_unchecked(<Self as StaticType>::static_type());
260            gobject_ffi::g_value_take_boxed(
261                value.to_glib_none_mut().0,
262                ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(self) as *mut _,
263            );
264            value
265        }
266    }
267
268    #[inline]
269    fn value_type(&self) -> Type {
270        <Self as StaticType>::static_type()
271    }
272}
273
274impl std::convert::From<ValueArray> for Value {
275    #[inline]
276    fn from(o: ValueArray) -> Self {
277        unsafe {
278            let mut value = Value::from_type_unchecked(<ValueArray as StaticType>::static_type());
279            gobject_ffi::g_value_take_boxed(
280                value.to_glib_none_mut().0,
281                IntoGlibPtr::<*mut gobject_ffi::GValueArray>::into_glib_ptr(o) as *mut _,
282            );
283            value
284        }
285    }
286}
287
288#[doc(hidden)]
289impl crate::value::ToValueOptional for ValueArray {
290    #[inline]
291    fn to_value_optional(s: Option<&Self>) -> Value {
292        let mut value = Value::for_value_type::<Self>();
293        unsafe {
294            gobject_ffi::g_value_take_boxed(
295                value.to_glib_none_mut().0,
296                ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(&s) as *mut _,
297            );
298        }
299
300        value
301    }
302}
303
304impl HasParamSpec for ValueArray {
305    type ParamSpec = ParamSpecValueArray;
306    type SetValue = Self;
307    type BuilderFn = fn(&str) -> ParamSpecValueArrayBuilder;
308
309    fn param_spec_builder() -> Self::BuilderFn {
310        Self::ParamSpec::builder
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317
318    #[test]
319    fn test_new() {
320        let arr = ValueArray::new(["123", "456"]);
321        assert_eq!(
322            arr.first().and_then(|v| v.get::<String>().ok()),
323            Some(String::from("123"))
324        );
325        assert_eq!(
326            arr.get(1).and_then(|v| v.get::<String>().ok()),
327            Some(String::from("456"))
328        );
329    }
330
331    #[test]
332    fn test_append() {
333        let mut arr = ValueArray::default();
334        arr.append("123");
335        arr.append(123u32);
336        arr.append_value(&Value::from(456u64));
337
338        assert_eq!(
339            arr.first().and_then(|v| v.get::<String>().ok()),
340            Some(String::from("123"))
341        );
342        assert_eq!(arr.get(1).and_then(|v| v.get::<u32>().ok()), Some(123));
343        assert_eq!(arr.get(2).and_then(|v| v.get::<u64>().ok()), Some(456));
344    }
345}