x11rb/
utils.rs

1//! Utility functions that are not specific to X11.
2//!
3//! # CSlice
4//!
5//! [`CSlice`] is a wrapper around some bytes in memory. It is unsafe to construct, but takes
6//! ownership of the bytes and allows accessing them as a `[u8]`. When dropped, the underlying
7//! memory is freed via [`libc::free`].
8//!
9//! `CSlice` is only available when the `allow-unsafe-code` feature is enabled.
10
11pub use x11rb_protocol::RawFdContainer;
12
13#[cfg(feature = "allow-unsafe-code")]
14mod unsafe_code {
15    use std::mem::forget;
16    use std::ops::{Deref, Index};
17    use std::ptr::NonNull;
18    use std::slice::{from_raw_parts, SliceIndex};
19
20    use libc::free;
21
22    /// Wrapper around a slice that was allocated in C code.
23    ///
24    /// `CSlice` is only available when the `allow-unsafe-code` feature is enabled.
25    pub struct CSlice {
26        ptr: NonNull<[u8]>,
27    }
28
29    // `CSlice` is `Send` and `Sync` because, once created, it is
30    // completely immutable (it does not have interior mutability),
31    // so it can be safely accessed from different threads simultaneously.
32    unsafe impl Send for CSlice {}
33    unsafe impl Sync for CSlice {}
34
35    impl CSlice {
36        /// Constructs a new `CSlice` from the given parts. `libc::free` will be called on the given
37        /// pointer when the slice is dropped.
38        ///
39        /// # Safety
40        ///
41        /// The same rules as for `std::slice::from_raw_parts` apply. Additionally, the given pointer
42        /// must be safe to free with `libc::free`.
43        pub unsafe fn new(ptr: *const u8, len: usize) -> CSlice {
44            CSlice {
45                ptr: NonNull::from(from_raw_parts(ptr, len)),
46            }
47        }
48
49        /// Convert `self` into a raw part.
50        ///
51        /// Ownership of the returned pointer is given to the caller. Specifically, `libc::free` will
52        /// not be called on it by `CSlice`.
53        pub fn into_ptr(self) -> *const u8 {
54            let ptr = self.ptr.as_ptr() as *const u8;
55            forget(self);
56            ptr
57        }
58    }
59
60    impl Drop for CSlice {
61        fn drop(&mut self) {
62            unsafe { free(self.ptr.as_ptr() as _) }
63        }
64    }
65
66    impl Deref for CSlice {
67        type Target = [u8];
68
69        fn deref(&self) -> &[u8] {
70            unsafe { self.ptr.as_ref() }
71        }
72    }
73
74    impl AsRef<[u8]> for CSlice {
75        fn as_ref(&self) -> &[u8] {
76            self
77        }
78    }
79
80    impl<I> Index<I> for CSlice
81    where
82        I: SliceIndex<[u8]>,
83    {
84        type Output = I::Output;
85
86        fn index(&self, index: I) -> &I::Output {
87            (**self).index(index)
88        }
89    }
90
91    impl std::fmt::Debug for CSlice {
92        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93            std::fmt::Debug::fmt(&**self, f)
94        }
95    }
96}
97
98#[cfg(feature = "allow-unsafe-code")]
99pub use unsafe_code::CSlice;