glib/
byte_array.rs

1// Copyright 2019, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5//! # Examples
6//!
7//! ```
8//! use glib::prelude::*; // or `use gtk::prelude::*;`
9//! use glib::ByteArray;
10//!
11//! let ba = ByteArray::from(b"def");
12//! ba.append(b"ghi").prepend(b"abc");
13//! ba.remove_range(3, 3);
14//! assert_eq!(ba, "abcghi".as_bytes());
15//! ```
16
17use 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}