1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! # Examples
5//!
6//! ```
7//! use glib::prelude::*; // or `use gtk::prelude::*;`
8//! use glib::ByteArray;
9//!
10//! let ba = ByteArray::from(b"abc");
11//! assert_eq!(ba, "abc".as_bytes());
12//! ```
13
14use std::{
15 borrow::Borrow,
16 cmp::Ordering,
17 fmt,
18 hash::{Hash, Hasher},
19 ops::Deref,
20 slice,
21};
22
23use crate::translate::*;
24
25wrapper! {
26 #[doc(alias = "GByteArray")]
27 pub struct ByteArray(Shared<ffi::GByteArray>);
28
29 match fn {
30 ref => |ptr| ffi::g_byte_array_ref(ptr),
31 unref => |ptr| ffi::g_byte_array_unref(ptr),
32 type_ => || ffi::g_byte_array_get_type(),
33 }
34}
35
36impl Deref for ByteArray {
37 type Target = [u8];
38
39 #[inline]
40 fn deref(&self) -> &[u8] {
41 unsafe {
42 let self_ptr: *const ffi::GByteArray = self.to_glib_none().0;
43 let ptr: *mut u8 = (*self_ptr).data;
44 let len: usize = (*self_ptr).len as usize;
45 debug_assert!(!ptr.is_null() || len == 0);
46 if ptr.is_null() {
47 &[]
48 } else {
49 slice::from_raw_parts(data:ptr as *const u8, len)
50 }
51 }
52 }
53}
54
55impl AsRef<[u8]> for ByteArray {
56 #[inline]
57 fn as_ref(&self) -> &[u8] {
58 self
59 }
60}
61
62impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
63 fn from(value: &'a T) -> ByteArray {
64 let value: &{unknown} = value.borrow();
65 unsafe {
66 let ba: *mut GByteArray = ffi::g_byte_array_new();
67 ffi::g_byte_array_append(array:ba, data:value.as_ptr(), value.len() as u32);
68 from_glib_full(ptr:ba)
69 }
70 }
71}
72
73impl fmt::Debug for ByteArray {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 f.debug_list().entries(self.as_ref()).finish()
76 }
77}
78
79macro_rules! impl_cmp {
80 ($lhs:ty, $rhs: ty) => {
81 #[allow(clippy::redundant_slicing)]
82 #[allow(clippy::extra_unused_lifetimes)]
83 impl<'a, 'b> PartialEq<$rhs> for $lhs {
84 #[inline]
85 fn eq(&self, other: &$rhs) -> bool {
86 self[..].eq(&other[..])
87 }
88 }
89
90 #[allow(clippy::redundant_slicing)]
91 #[allow(clippy::extra_unused_lifetimes)]
92 impl<'a, 'b> PartialEq<$lhs> for $rhs {
93 #[inline]
94 fn eq(&self, other: &$lhs) -> bool {
95 self[..].eq(&other[..])
96 }
97 }
98
99 #[allow(clippy::redundant_slicing)]
100 #[allow(clippy::extra_unused_lifetimes)]
101 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
102 #[inline]
103 fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
104 self[..].partial_cmp(&other[..])
105 }
106 }
107
108 #[allow(clippy::redundant_slicing)]
109 #[allow(clippy::extra_unused_lifetimes)]
110 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
111 #[inline]
112 fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
113 self[..].partial_cmp(&other[..])
114 }
115 }
116 };
117}
118
119impl_cmp!(ByteArray, [u8]);
120impl_cmp!(ByteArray, &'a [u8]);
121impl_cmp!(&'a ByteArray, [u8]);
122impl_cmp!(ByteArray, Vec<u8>);
123impl_cmp!(&'a ByteArray, Vec<u8>);
124
125impl PartialEq for ByteArray {
126 fn eq(&self, other: &Self) -> bool {
127 self[..] == other[..]
128 }
129}
130
131impl Eq for ByteArray {}
132
133impl Hash for ByteArray {
134 fn hash<H: Hasher>(&self, state: &mut H) {
135 Hash::hash_slice(&self[..], state)
136 }
137}
138#[cfg(test)]
139mod tests {
140 use std::collections::HashSet;
141
142 use super::*;
143
144 #[test]
145 fn various() {
146 let ba = ByteArray::from(b"foobar");
147 assert_eq!(ba, b"foobar" as &[u8]);
148 }
149
150 #[test]
151 fn hash() {
152 let b1 = ByteArray::from(b"this is a test");
153 let b2 = ByteArray::from(b"this is a test");
154 let b3 = ByteArray::from(b"test");
155 let mut set = HashSet::new();
156 set.insert(b1);
157 assert!(set.contains(&b2));
158 assert!(!set.contains(&b3));
159 }
160}
161