glib/
byte_array.rs

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::{ffi, translate::*};
24
25wrapper! {
26    /// Contains the public fields of a GByteArray.
27    #[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}