1 // Copyright 2013-2016, 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 use glib_sys; 6 use std::borrow::Borrow; 7 use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; 8 use std::fmt; 9 use std::hash::{Hash, Hasher}; 10 use std::ops::Deref; 11 use std::slice; 12 use translate::*; 13 14 glib_wrapper! { 15 /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`). 16 /// 17 /// `From` implementations that take references (e.g. `&[u8]`) copy the 18 /// data. The `from_static` constructor avoids copying static data. 19 /// 20 /// ``` 21 /// use glib::Bytes; 22 /// 23 /// let v = vec![1, 2, 3]; 24 /// let b = Bytes::from(&v); 25 /// assert_eq!(v, b); 26 /// 27 /// let s = b"xyz"; 28 /// let b = Bytes::from_static(s); 29 /// assert_eq!(&s[..], b); 30 /// ``` 31 pub struct Bytes(Shared<glib_sys::GBytes>); 32 33 match fn { 34 ref => |ptr| glib_sys::g_bytes_ref(ptr), 35 unref => |ptr| glib_sys::g_bytes_unref(ptr), 36 get_type => || glib_sys::g_bytes_get_type(), 37 } 38 } 39 40 impl Bytes { 41 /// Copies `data` into a new shared slice. new<T: AsRef<[u8]>>(data: T) -> Bytes42 fn new<T: AsRef<[u8]>>(data: T) -> Bytes { 43 let data = data.as_ref(); 44 unsafe { from_glib_full(glib_sys::g_bytes_new(data.as_ptr() as *const _, data.len())) } 45 } 46 47 /// Creates a view into static `data` without copying. from_static(data: &'static [u8]) -> Bytes48 pub fn from_static(data: &'static [u8]) -> Bytes { 49 unsafe { 50 from_glib_full(glib_sys::g_bytes_new_static( 51 data.as_ptr() as *const _, 52 data.len(), 53 )) 54 } 55 } 56 57 /// Takes ownership of `data` and creates a new `Bytes` without copying. from_owned<T: AsRef<[u8]> + Send + 'static>(data: T) -> Bytes58 pub fn from_owned<T: AsRef<[u8]> + Send + 'static>(data: T) -> Bytes { 59 let data: Box<T> = Box::new(data); 60 let (size, data_ptr) = { 61 let data = (*data).as_ref(); 62 (data.len(), data.as_ptr()) 63 }; 64 65 unsafe extern "C" fn drop_box<T: AsRef<[u8]> + Send + 'static>(b: glib_sys::gpointer) { 66 let _: Box<T> = Box::from_raw(b as *mut _); 67 } 68 69 unsafe { 70 from_glib_full(glib_sys::g_bytes_new_with_free_func( 71 data_ptr as *const _, 72 size, 73 Some(drop_box::<T>), 74 Box::into_raw(data) as *mut _, 75 )) 76 } 77 } 78 } 79 80 unsafe impl Send for Bytes {} 81 unsafe impl Sync for Bytes {} 82 83 impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes { from(value: &'a T) -> Bytes84 fn from(value: &'a T) -> Bytes { 85 Bytes::new(value.borrow()) 86 } 87 } 88 89 impl fmt::Debug for Bytes { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 91 f.debug_struct("Bytes") 92 .field("ptr", &self.to_glib_none().0) 93 .field("data", &&self[..]) 94 .finish() 95 } 96 } 97 98 impl AsRef<[u8]> for Bytes { as_ref(&self) -> &[u8]99 fn as_ref(&self) -> &[u8] { 100 &*self 101 } 102 } 103 104 impl Deref for Bytes { 105 type Target = [u8]; 106 deref(&self) -> &[u8]107 fn deref(&self) -> &[u8] { 108 unsafe { 109 let mut len = 0; 110 let ptr = glib_sys::g_bytes_get_data(self.to_glib_none().0, &mut len); 111 debug_assert!(!ptr.is_null() || len == 0); 112 slice::from_raw_parts(ptr as *const u8, len) 113 } 114 } 115 } 116 117 impl PartialEq for Bytes { eq(&self, other: &Self) -> bool118 fn eq(&self, other: &Self) -> bool { 119 unsafe { 120 from_glib(glib_sys::g_bytes_equal( 121 self.to_glib_none().0 as *const _, 122 other.to_glib_none().0 as *const _, 123 )) 124 } 125 } 126 } 127 128 impl Eq for Bytes {} 129 130 impl PartialOrd for Bytes { partial_cmp(&self, other: &Self) -> Option<Ordering>131 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 132 unsafe { 133 let ret = glib_sys::g_bytes_compare( 134 self.to_glib_none().0 as *const _, 135 other.to_glib_none().0 as *const _, 136 ); 137 ret.partial_cmp(&0) 138 } 139 } 140 } 141 142 impl Ord for Bytes { cmp(&self, other: &Self) -> Ordering143 fn cmp(&self, other: &Self) -> Ordering { 144 unsafe { 145 let ret = glib_sys::g_bytes_compare( 146 self.to_glib_none().0 as *const _, 147 other.to_glib_none().0 as *const _, 148 ); 149 ret.cmp(&0) 150 } 151 } 152 } 153 154 macro_rules! impl_cmp { 155 ($lhs:ty, $rhs: ty) => { 156 impl<'a, 'b> PartialEq<$rhs> for $lhs { 157 #[inline] 158 fn eq(&self, other: &$rhs) -> bool { 159 self[..].eq(&other[..]) 160 } 161 } 162 163 impl<'a, 'b> PartialEq<$lhs> for $rhs { 164 #[inline] 165 fn eq(&self, other: &$lhs) -> bool { 166 self[..].eq(&other[..]) 167 } 168 } 169 170 impl<'a, 'b> PartialOrd<$rhs> for $lhs { 171 #[inline] 172 fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { 173 self[..].partial_cmp(&other[..]) 174 } 175 } 176 177 impl<'a, 'b> PartialOrd<$lhs> for $rhs { 178 #[inline] 179 fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { 180 self[..].partial_cmp(&other[..]) 181 } 182 } 183 }; 184 } 185 186 impl_cmp!(Bytes, [u8]); 187 impl_cmp!(Bytes, &'a [u8]); 188 impl_cmp!(&'a Bytes, [u8]); 189 impl_cmp!(Bytes, Vec<u8>); 190 impl_cmp!(&'a Bytes, Vec<u8>); 191 192 impl Hash for Bytes { hash<H: Hasher>(&self, state: &mut H)193 fn hash<H: Hasher>(&self, state: &mut H) { 194 self.len().hash(state); 195 Hash::hash_slice(self, state) 196 } 197 } 198 199 #[cfg(test)] 200 mod tests { 201 use super::*; 202 use std::collections::HashSet; 203 204 #[test] eq()205 fn eq() { 206 let abc: &[u8] = b"abc"; 207 let def: &[u8] = b"def"; 208 let a1 = Bytes::from(abc); 209 let a2 = Bytes::from(abc); 210 let d = Bytes::from(def); 211 assert_eq!(a1, a2); 212 assert_eq!(def, d); 213 assert!(a1 != d); 214 assert!(a1 != def); 215 } 216 217 #[test] ord()218 fn ord() { 219 let abc: &[u8] = b"abc"; 220 let def: &[u8] = b"def"; 221 let a = Bytes::from(abc); 222 let d = Bytes::from(def); 223 assert!(a < d); 224 assert!(a < def); 225 assert!(abc < d); 226 assert!(d > a); 227 assert!(d > abc); 228 assert!(def > a); 229 } 230 231 #[test] hash()232 fn hash() { 233 let b1 = Bytes::from(b"this is a test"); 234 let b2 = Bytes::from(b"this is a test"); 235 let b3 = Bytes::from(b"test"); 236 let mut set = HashSet::new(); 237 set.insert(b1); 238 assert!(set.contains(&b2)); 239 assert!(!set.contains(&b3)); 240 } 241 242 #[test] from_static()243 fn from_static() { 244 let b1 = Bytes::from_static(b"this is a test"); 245 let b2 = Bytes::from(b"this is a test"); 246 assert_eq!(b1, b2); 247 } 248 249 #[test] from_owned()250 fn from_owned() { 251 let b = Bytes::from_owned(vec![1, 2, 3]); 252 assert_eq!(b, [1u8, 2u8, 3u8].as_ref()); 253 } 254 } 255