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