1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{cmp::Ordering, ops, slice}; |
4 | |
5 | use crate::{ |
6 | ffi, gobject_ffi, prelude::*, translate::*, ParamSpecValueArray, ParamSpecValueArrayBuilder, |
7 | Type, Value, |
8 | }; |
9 | |
10 | wrapper! { |
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 | |
21 | impl 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 | |
171 | impl ops::Deref for ValueArray { |
172 | type Target = [Value]; |
173 | |
174 | #[inline ] |
175 | fn deref(&self) -> &[Value] { |
176 | self.as_slice() |
177 | } |
178 | } |
179 | |
180 | impl ops::DerefMut for ValueArray { |
181 | #[inline ] |
182 | fn deref_mut(&mut self) -> &mut [Value] { |
183 | self.as_mut_slice() |
184 | } |
185 | } |
186 | |
187 | impl Default for ValueArray { |
188 | fn default() -> Self { |
189 | Self::with_capacity(8) |
190 | } |
191 | } |
192 | |
193 | impl 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 | |
199 | impl std::iter::Extend<Value> for ValueArray { |
200 | fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) { |
201 | for v: Value in iter.into_iter() { |
202 | self.append_value(&v); |
203 | } |
204 | } |
205 | } |
206 | |
207 | // Implementing `Value` traits manually because of a custom ParamSpec |
208 | impl StaticType for ValueArray { |
209 | #[inline ] |
210 | fn static_type() -> Type { |
211 | unsafe { from_glib(val:gobject_ffi::g_value_array_get_type()) } |
212 | } |
213 | } |
214 | |
215 | #[doc (hidden)] |
216 | impl ValueType for ValueArray { |
217 | type Type = Self; |
218 | } |
219 | |
220 | #[doc (hidden)] |
221 | impl crate::value::ValueTypeOptional for ValueArray {} |
222 | |
223 | #[doc (hidden)] |
224 | unsafe 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: *mut c_void = 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)] |
236 | unsafe 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: &GValue = &*(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)] |
255 | impl ToValue for ValueArray { |
256 | #[inline ] |
257 | fn to_value(&self) -> Value { |
258 | unsafe { |
259 | let mut value: 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 | v_boxed: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 | |
274 | impl std::convert::From<ValueArray> for Value { |
275 | #[inline ] |
276 | fn from(o: ValueArray) -> Self { |
277 | unsafe { |
278 | let mut value: 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 | v_boxed:IntoGlibPtr::<*mut gobject_ffi::GValueArray>::into_glib_ptr(self:o) as *mut _, |
282 | ); |
283 | value |
284 | } |
285 | } |
286 | } |
287 | |
288 | #[doc (hidden)] |
289 | impl crate::value::ToValueOptional for ValueArray { |
290 | #[inline ] |
291 | fn to_value_optional(s: Option<&Self>) -> Value { |
292 | let mut value: Value = Value::for_value_type::<Self>(); |
293 | unsafe { |
294 | gobject_ffi::g_value_take_boxed( |
295 | value.to_glib_none_mut().0, |
296 | v_boxed:ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(&s) as *mut _, |
297 | ); |
298 | } |
299 | |
300 | value |
301 | } |
302 | } |
303 | |
304 | impl 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)] |
315 | mod 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 | } |
346 | |