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    // rustdoc-stripper-ignore-next-stop
28    /// Contains the public fields of a GByteArray.
29    #[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}