1use glib_sys;
18use std::borrow::Borrow;
19use std::cmp::Ordering;
20use std::fmt;
21use std::hash::{Hash, Hasher};
22use std::mem;
23use std::ops::Deref;
24use std::ptr::NonNull;
25use std::slice;
26use translate::*;
27
28use Bytes;
29
30glib_wrapper! {
31 pub struct ByteArray(Shared<glib_sys::GByteArray>);
32
33 match fn {
34 ref => |ptr| glib_sys::g_byte_array_ref(ptr),
35 unref => |ptr| glib_sys::g_byte_array_unref(ptr),
36 get_type => || glib_sys::g_byte_array_get_type(),
37 }
38}
39
40impl ByteArray {
41 pub fn new() -> ByteArray {
42 unsafe { from_glib_full(glib_sys::g_byte_array_new()) }
43 }
44
45 pub fn with_capacity(size: usize) -> ByteArray {
46 unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) }
47 }
48
49 pub fn into_gbytes(self) -> Bytes {
50 unsafe {
51 let ret = from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override(
52 self.to_glib_none().0,
53 )));
54 mem::forget(self);
55 ret
56 }
57 }
58
59 pub fn append<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
60 let bytes = data.as_ref();
61 unsafe {
62 glib_sys::g_byte_array_append(
63 self.to_glib_none().0,
64 bytes.as_ptr() as *const _,
65 bytes.len() as u32,
66 );
67 }
68 self
69 }
70
71 pub fn prepend<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
72 let bytes = data.as_ref();
73 unsafe {
74 glib_sys::g_byte_array_prepend(
75 self.to_glib_none().0,
76 bytes.as_ptr() as *const _,
77 bytes.len() as u32,
78 );
79 }
80 self
81 }
82
83 pub fn remove_index(&self, index: usize) {
84 unsafe {
85 glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32);
86 }
87 }
88
89 pub fn remove_index_fast(&self, index: usize) {
90 unsafe {
91 glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32);
92 }
93 }
94
95 pub fn remove_range(&self, index: usize, length: usize) {
96 unsafe {
97 glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32);
98 }
99 }
100
101 pub fn set_size(&self, size: usize) {
102 unsafe {
103 glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32);
104 }
105 }
106
107 pub fn sort<F: FnMut(&u8, &u8) -> Ordering>(&self, compare_func: F) {
108 unsafe extern "C" fn compare_func_trampoline(
109 a: glib_sys::gconstpointer,
110 b: glib_sys::gconstpointer,
111 func: glib_sys::gpointer,
112 ) -> i32 {
113 let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering);
114
115 let a = &*(a as *const u8);
116 let b = &*(b as *const u8);
117
118 match (*func)(&a, &b) {
119 Ordering::Less => -1,
120 Ordering::Equal => 0,
121 Ordering::Greater => 1,
122 }
123 }
124 unsafe {
125 let mut func = compare_func;
126 let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func;
127 let func_ptr =
128 &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer;
129
130 glib_sys::g_byte_array_sort_with_data(
131 self.to_glib_none().0,
132 Some(compare_func_trampoline),
133 func_ptr,
134 );
135 }
136 }
137}
138
139impl AsRef<[u8]> for ByteArray {
140 fn as_ref(&self) -> &[u8] {
141 &*self
142 }
143}
144
145impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
146 fn from(value: &'a T) -> ByteArray {
147 let ba = ByteArray::new();
148 ba.append(value.borrow());
149 ba
150 }
151}
152
153impl Deref for ByteArray {
154 type Target = [u8];
155
156 fn deref(&self) -> &[u8] {
157 unsafe {
158 let mut ptr = (*self.to_glib_none().0).data;
159 let len = (*self.to_glib_none().0).len as usize;
160 debug_assert!(!ptr.is_null() || len == 0);
161 if ptr.is_null() {
162 ptr = NonNull::dangling().as_ptr();
163 }
164 slice::from_raw_parts(ptr as *const u8, len)
165 }
166 }
167}
168
169impl Default for ByteArray {
170 fn default() -> Self {
171 Self::new()
172 }
173}
174
175impl fmt::Debug for ByteArray {
176 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177 f.debug_struct("ByteArray")
178 .field("ptr", &self.to_glib_none().0)
179 .field("data", &&self[..])
180 .finish()
181 }
182}
183
184macro_rules! impl_cmp {
185 ($lhs:ty, $rhs: ty) => {
186 impl<'a, 'b> PartialEq<$rhs> for $lhs {
187 #[inline]
188 fn eq(&self, other: &$rhs) -> bool {
189 self[..].eq(&other[..])
190 }
191 }
192
193 impl<'a, 'b> PartialEq<$lhs> for $rhs {
194 #[inline]
195 fn eq(&self, other: &$lhs) -> bool {
196 self[..].eq(&other[..])
197 }
198 }
199
200 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
201 #[inline]
202 fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
203 self[..].partial_cmp(&other[..])
204 }
205 }
206
207 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
208 #[inline]
209 fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
210 self[..].partial_cmp(&other[..])
211 }
212 }
213 };
214}
215
216impl_cmp!(ByteArray, [u8]);
217impl_cmp!(ByteArray, &'a [u8]);
218impl_cmp!(&'a ByteArray, [u8]);
219impl_cmp!(ByteArray, Vec<u8>);
220impl_cmp!(&'a ByteArray, Vec<u8>);
221
222impl PartialEq for ByteArray {
223 fn eq(&self, other: &Self) -> bool {
224 self[..] == other[..]
225 }
226}
227
228impl Eq for ByteArray {}
229
230impl Hash for ByteArray {
231 fn hash<H: Hasher>(&self, state: &mut H) {
232 self.len().hash(state);
233 Hash::hash_slice(&self[..], state)
234 }
235}
236#[cfg(test)]
237mod tests {
238 use super::*;
239 use std::collections::HashSet;
240
241 #[test]
242 fn various() {
243 let ba: ByteArray = Default::default();
244 ba.append("foo").append("bar").prepend("baz");
245 ba.remove_index(0);
246 ba.remove_index_fast(1);
247 ba.remove_range(1, 2);
248 ba.set_size(20);
249 ba.sort(|a, b| a.cmp(b));
250 let abc: &[u8] = b"abc";
251 assert_eq!(ByteArray::from(abc), "abc".as_bytes());
252 }
253
254 #[test]
255 fn hash() {
256 let b1 = ByteArray::from(b"this is a test");
257 let b2 = ByteArray::from(b"this is a test");
258 let b3 = ByteArray::from(b"test");
259 let mut set = HashSet::new();
260 set.insert(b1);
261 assert!(set.contains(&b2));
262 assert!(!set.contains(&b3));
263 }
264}