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