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