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    ParamSpecValueArray, ParamSpecValueArrayBuilder, Type, Value, ffi, gobject_ffi, prelude::*,
7    translate::*,
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            unsafe {
122                let func = func as *mut &mut dyn FnMut(&Value, &Value) -> Ordering;
123
124                let a = &*(a as *const Value);
125                let b = &*(b as *const Value);
126
127                (*func)(a, b).into_glib()
128            }
129        }
130        unsafe {
131            let mut func = compare_func;
132            let func_obj: &mut dyn FnMut(&Value, &Value) -> Ordering = &mut func;
133            let func_ptr =
134                &func_obj as *const &mut dyn FnMut(&Value, &Value) -> Ordering as ffi::gpointer;
135
136            gobject_ffi::g_value_array_sort_with_data(
137                self.to_glib_none_mut().0,
138                Some(compare_func_trampoline),
139                func_ptr,
140            );
141        }
142    }
143
144    #[inline]
145    pub fn as_slice(&self) -> &[Value] {
146        if self.is_empty() {
147            return &[];
148        }
149
150        unsafe {
151            slice::from_raw_parts(
152                (*self.as_ptr()).values as *const Value,
153                (*self.as_ptr()).n_values as usize,
154            )
155        }
156    }
157
158    #[inline]
159    pub fn as_mut_slice(&mut self) -> &mut [Value] {
160        if self.is_empty() {
161            return &mut [];
162        }
163
164        unsafe {
165            slice::from_raw_parts_mut(
166                (*self.as_ptr()).values as *mut Value,
167                (*self.as_ptr()).n_values as usize,
168            )
169        }
170    }
171}
172
173impl ops::Deref for ValueArray {
174    type Target = [Value];
175
176    #[inline]
177    fn deref(&self) -> &[Value] {
178        self.as_slice()
179    }
180}
181
182impl ops::DerefMut for ValueArray {
183    #[inline]
184    fn deref_mut(&mut self) -> &mut [Value] {
185        self.as_mut_slice()
186    }
187}
188
189impl Default for ValueArray {
190    fn default() -> Self {
191        Self::with_capacity(8)
192    }
193}
194
195impl std::iter::FromIterator<Value> for ValueArray {
196    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
197        Self::from_values(iter)
198    }
199}
200
201impl std::iter::Extend<Value> for ValueArray {
202    fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
203        for v in iter.into_iter() {
204            self.append_value(&v);
205        }
206    }
207}
208
209// Implementing `Value` traits manually because of a custom ParamSpec
210impl StaticType for ValueArray {
211    #[inline]
212    fn static_type() -> Type {
213        unsafe { from_glib(gobject_ffi::g_value_array_get_type()) }
214    }
215}
216
217#[doc(hidden)]
218impl ValueType for ValueArray {
219    type Type = Self;
220}
221
222#[doc(hidden)]
223impl crate::value::ValueTypeOptional for ValueArray {}
224
225#[doc(hidden)]
226unsafe impl<'a> crate::value::FromValue<'a> for ValueArray {
227    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
228
229    #[inline]
230    unsafe fn from_value(value: &'a Value) -> Self {
231        unsafe {
232            let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0);
233            debug_assert!(!ptr.is_null());
234            from_glib_full(ptr as *mut gobject_ffi::GValueArray)
235        }
236    }
237}
238
239#[doc(hidden)]
240unsafe impl<'a> crate::value::FromValue<'a> for &'a ValueArray {
241    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
242
243    #[inline]
244    unsafe fn from_value(value: &'a Value) -> Self {
245        unsafe {
246            debug_assert_eq!(
247                std::mem::size_of::<Self>(),
248                std::mem::size_of::<ffi::gpointer>()
249            );
250            let value = &*(value as *const Value as *const gobject_ffi::GValue);
251            debug_assert!(!value.data[0].v_pointer.is_null());
252            <ValueArray>::from_glib_ptr_borrow(
253                &*(&value.data[0].v_pointer as *const ffi::gpointer
254                    as *const *mut gobject_ffi::GValueArray),
255            )
256        }
257    }
258}
259
260#[doc(hidden)]
261impl ToValue for ValueArray {
262    #[inline]
263    fn to_value(&self) -> Value {
264        unsafe {
265            let mut value = Value::from_type_unchecked(<Self as StaticType>::static_type());
266            gobject_ffi::g_value_take_boxed(
267                value.to_glib_none_mut().0,
268                ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(self) as *mut _,
269            );
270            value
271        }
272    }
273
274    #[inline]
275    fn value_type(&self) -> Type {
276        <Self as StaticType>::static_type()
277    }
278}
279
280impl std::convert::From<ValueArray> for Value {
281    #[inline]
282    fn from(o: ValueArray) -> Self {
283        unsafe {
284            let mut value = Value::from_type_unchecked(<ValueArray as StaticType>::static_type());
285            gobject_ffi::g_value_take_boxed(
286                value.to_glib_none_mut().0,
287                IntoGlibPtr::<*mut gobject_ffi::GValueArray>::into_glib_ptr(o) as *mut _,
288            );
289            value
290        }
291    }
292}
293
294#[doc(hidden)]
295impl crate::value::ToValueOptional for ValueArray {
296    #[inline]
297    fn to_value_optional(s: Option<&Self>) -> Value {
298        let mut value = Value::for_value_type::<Self>();
299        unsafe {
300            gobject_ffi::g_value_take_boxed(
301                value.to_glib_none_mut().0,
302                ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(&s) as *mut _,
303            );
304        }
305
306        value
307    }
308}
309
310impl HasParamSpec for ValueArray {
311    type ParamSpec = ParamSpecValueArray;
312    type SetValue = Self;
313    type BuilderFn = fn(&str) -> ParamSpecValueArrayBuilder;
314
315    fn param_spec_builder() -> Self::BuilderFn {
316        Self::ParamSpec::builder
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use super::*;
323
324    #[test]
325    fn test_new() {
326        let arr = ValueArray::new(["123", "456"]);
327        assert_eq!(
328            arr.first().and_then(|v| v.get::<String>().ok()),
329            Some(String::from("123"))
330        );
331        assert_eq!(
332            arr.get(1).and_then(|v| v.get::<String>().ok()),
333            Some(String::from("456"))
334        );
335    }
336
337    #[test]
338    fn test_append() {
339        let mut arr = ValueArray::default();
340        arr.append("123");
341        arr.append(123u32);
342        arr.append_value(&Value::from(456u64));
343
344        assert_eq!(
345            arr.first().and_then(|v| v.get::<String>().ok()),
346            Some(String::from("123"))
347        );
348        assert_eq!(arr.get(1).and_then(|v| v.get::<u32>().ok()), Some(123));
349        assert_eq!(arr.get(2).and_then(|v| v.get::<u64>().ok()), Some(456));
350    }
351}