|
| 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 | +
|
| 17 | +use glib_sys; |
| 18 | +use std::borrow::Borrow; |
| 19 | +use std::cmp::Ordering; |
| 20 | +use std::fmt; |
| 21 | +use std::hash::{Hash, Hasher}; |
| 22 | +use std::mem; |
| 23 | +use std::ops::Deref; |
| 24 | +use std::slice; |
| 25 | +use translate::*; |
| 26 | +use std::ptr::NonNull; |
| 27 | + |
| 28 | +use Bytes; |
| 29 | + |
| 30 | +glib_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 | + |
| 40 | +impl 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 { |
| 109 | + let mut func = compare_func; |
| 110 | + let func_obj: &mut (FnMut(&u8, &u8) -> Ordering) = &mut func; |
| 111 | + let func_ptr = |
| 112 | + &func_obj as *const &mut (FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer; |
| 113 | + |
| 114 | + glib_sys::g_byte_array_sort_with_data( |
| 115 | + self.to_glib_none().0, |
| 116 | + Some(compare_func_trampoline), |
| 117 | + func_ptr, |
| 118 | + ); |
| 119 | + } |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +unsafe extern "C" fn compare_func_trampoline( |
| 124 | + a: glib_sys::gconstpointer, |
| 125 | + b: glib_sys::gconstpointer, |
| 126 | + func: glib_sys::gpointer, |
| 127 | +) -> i32 { |
| 128 | + let func = func as *mut &mut (FnMut(&u8, &u8) -> Ordering); |
| 129 | + |
| 130 | + let a = &*(a as *const u8); |
| 131 | + let b = &*(b as *const u8); |
| 132 | + |
| 133 | + match (*func)(&a, &b) { |
| 134 | + Ordering::Less => -1, |
| 135 | + Ordering::Equal => 0, |
| 136 | + Ordering::Greater => 1, |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +impl AsRef<[u8]> for ByteArray { |
| 141 | + fn as_ref(&self) -> &[u8] { |
| 142 | + &*self |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray { |
| 147 | + fn from(value: &'a T) -> ByteArray { |
| 148 | + let ba = ByteArray::new(); |
| 149 | + ba.append(value.borrow()); |
| 150 | + ba |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +impl Deref for ByteArray { |
| 155 | + type Target = [u8]; |
| 156 | + |
| 157 | + fn deref(&self) -> &[u8] { |
| 158 | + unsafe { |
| 159 | + let mut ptr = (*self.to_glib_none().0).data; |
| 160 | + let len = (*self.to_glib_none().0).len as usize; |
| 161 | + debug_assert!(!ptr.is_null() || len == 0); |
| 162 | + if ptr.is_null() { |
| 163 | + ptr = NonNull::dangling().as_ptr(); |
| 164 | + } |
| 165 | + slice::from_raw_parts(ptr as *const u8, len) |
| 166 | + } |
| 167 | + } |
| 168 | +} |
| 169 | + |
| 170 | +impl Default for ByteArray { |
| 171 | + fn default() -> Self { |
| 172 | + Self::new() |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +impl fmt::Debug for ByteArray { |
| 177 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 178 | + f.debug_struct("ByteArray") |
| 179 | + .field("ptr", &self.to_glib_none().0) |
| 180 | + .field("data", &&self[..]) |
| 181 | + .finish() |
| 182 | + } |
| 183 | +} |
| 184 | + |
| 185 | +macro_rules! impl_cmp { |
| 186 | + ($lhs:ty, $rhs: ty) => { |
| 187 | + impl<'a, 'b> PartialEq<$rhs> for $lhs { |
| 188 | + #[inline] |
| 189 | + fn eq(&self, other: &$rhs) -> bool { |
| 190 | + self[..].eq(&other[..]) |
| 191 | + } |
| 192 | + } |
| 193 | + |
| 194 | + impl<'a, 'b> PartialEq<$lhs> for $rhs { |
| 195 | + #[inline] |
| 196 | + fn eq(&self, other: &$lhs) -> bool { |
| 197 | + self[..].eq(&other[..]) |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + impl<'a, 'b> PartialOrd<$rhs> for $lhs { |
| 202 | + #[inline] |
| 203 | + fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { |
| 204 | + self[..].partial_cmp(&other[..]) |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + impl<'a, 'b> PartialOrd<$lhs> for $rhs { |
| 209 | + #[inline] |
| 210 | + fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { |
| 211 | + self[..].partial_cmp(&other[..]) |
| 212 | + } |
| 213 | + } |
| 214 | + }; |
| 215 | +} |
| 216 | + |
| 217 | +impl_cmp!(ByteArray, [u8]); |
| 218 | +impl_cmp!(ByteArray, &'a [u8]); |
| 219 | +impl_cmp!(&'a ByteArray, [u8]); |
| 220 | +impl_cmp!(ByteArray, Vec<u8>); |
| 221 | +impl_cmp!(&'a ByteArray, Vec<u8>); |
| 222 | + |
| 223 | +impl PartialEq for ByteArray { |
| 224 | + fn eq(&self, other: &Self) -> bool { |
| 225 | + self[..] == other[..] |
| 226 | + } |
| 227 | +} |
| 228 | + |
| 229 | +impl Eq for ByteArray {} |
| 230 | + |
| 231 | +impl Hash for ByteArray { |
| 232 | + fn hash<H: Hasher>(&self, state: &mut H) { |
| 233 | + self.len().hash(state); |
| 234 | + Hash::hash_slice(&self[..], state) |
| 235 | + } |
| 236 | +} |
| 237 | +#[cfg(test)] |
| 238 | +mod tests { |
| 239 | + use super::*; |
| 240 | + use std::collections::HashSet; |
| 241 | + |
| 242 | + #[test] |
| 243 | + fn various() { |
| 244 | + let ba: ByteArray = Default::default(); |
| 245 | + ba.append("foo").append("bar").prepend("baz"); |
| 246 | + ba.remove_index(0); |
| 247 | + ba.remove_index_fast(1); |
| 248 | + ba.remove_range(1, 2); |
| 249 | + ba.set_size(20); |
| 250 | + ba.sort(|a, b| a.cmp(b)); |
| 251 | + let abc: &[u8] = b"abc"; |
| 252 | + assert_eq!(ByteArray::from(abc), "abc".as_bytes()); |
| 253 | + } |
| 254 | + |
| 255 | + #[test] |
| 256 | + fn hash() { |
| 257 | + let b1 = ByteArray::from(b"this is a test"); |
| 258 | + let b2 = ByteArray::from(b"this is a test"); |
| 259 | + let b3 = ByteArray::from(b"test"); |
| 260 | + let mut set = HashSet::new(); |
| 261 | + set.insert(b1); |
| 262 | + assert!(set.contains(&b2)); |
| 263 | + assert!(!set.contains(&b3)); |
| 264 | + } |
| 265 | +} |
0 commit comments