1use glib_sys;
6use std::borrow::Borrow;
7use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
8use std::fmt;
9use std::hash::{Hash, Hasher};
10use std::ops::Deref;
11use std::slice;
12use translate::*;
13
14glib_wrapper! {
15 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
40impl Bytes {
41 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 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 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
80unsafe impl Send for Bytes {}
81unsafe impl Sync for Bytes {}
82
83impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes {
84 fn from(value: &'a T) -> Bytes {
85 Bytes::new(value.borrow())
86 }
87}
88
89impl fmt::Debug for Bytes {
90 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
98impl AsRef<[u8]> for Bytes {
99 fn as_ref(&self) -> &[u8] {
100 &*self
101 }
102}
103
104impl Deref for Bytes {
105 type Target = [u8];
106
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
117impl PartialEq for Bytes {
118 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
128impl Eq for Bytes {}
129
130impl PartialOrd for Bytes {
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
142impl Ord for Bytes {
143 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
154macro_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
186impl_cmp!(Bytes, [u8]);
187impl_cmp!(Bytes, &'a [u8]);
188impl_cmp!(&'a Bytes, [u8]);
189impl_cmp!(Bytes, Vec<u8>);
190impl_cmp!(&'a Bytes, Vec<u8>);
191
192impl Hash for Bytes {
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)]
200mod tests {
201 use super::*;
202 use std::collections::HashSet;
203
204 #[test]
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]
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]
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]
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]
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}