1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
use core::{fmt::Debug, marker::PhantomData, ops::Deref, slice}; use super::StableLayout; // General Safety Note: The soundness of the `SharedSlice` type is centered // around the fact that the fields are all private, and so *safe rust* must // construct values of the type from an existing valid slice. However, because // the type is `repr(C)` it can of course be constructed with unsafe rust, or // even by foreign code. It is the responsibility of _the other code_ to ensure // that the actual fields are valid for being turned into a slice. /// A struct for **shared** slices with a stable layout. /// /// This is a `repr(C)` variant of `&[T]`. If you want a variant of `&mut [T]` /// then you should use [`UniqueSlice`](crate::UniqueSlice) instead. /// /// Rationale for using this type is given in the crate level docs. /// /// ## Unsafety /// /// Because this type is primarily intended to help _unsafe_ Rust we should /// discuss the precise guarantees offered: /// * **Validity Invariants** /// * The data layout is a `*const T` and then a `usize`. /// * **Soundness Invariants** /// * The `*const T` must point to the start of a valid `&[T]`. /// * The `usize` must be the correct length of that valid `&[T]`. /// * For as long as the `SharedSlice` exists the memory in question has a /// shared borrow over it (tracked via `PhantomData`). /// /// When you use this type with the C ABI, remember that the C ABI **does not** /// support generic types or `repr(Rust)` types! /// /// If you select a particular type for `T` that is compatible with the C ABI, /// such as `u8` or `i32`, then that particular monomorphization of /// `SharedSlice` will be C ABI compatible as well. For example, if your /// element type were `u8` then it would be equivalent layout to the following C /// declaration: /// ```c /// #include <stdint.h> /// // Identical layout to `SharedSlice<'a, u8>` /// typedef struct { /// uint8_t const *ptr; /// uintptr_t len; /// } SharedSlice_u8; /// ``` #[repr(C)] pub struct SharedSlice<'a, T> where T: StableLayout, { ptr: *const T, len: usize, life: PhantomData<&'a [T]>, } unsafe impl<'a, T: StableLayout> StableLayout for SharedSlice<'a, T> {} impl<'a, T: Debug> Debug for SharedSlice<'a, T> where T: StableLayout, { /// Debug prints as a slice would. fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { Debug::fmt(self.deref(), f) } } impl<'a, T> Clone for SharedSlice<'a, T> where T: StableLayout, { #[inline(always)] fn clone(&self) -> Self { // Note(Lokathor): We can't derive Clone and Copy or SharedSlice will only // be Clone and Copy when T is clone and Copy. However, SharedSlice is // actually a *slice of* T, so it is always Clone and Copy even if T is not. *self } } impl<'a, T> Copy for SharedSlice<'a, T> where T: StableLayout {} impl<'a, T> Default for SharedSlice<'a, T> where T: StableLayout, { /// Defaults to an empty slice. /// /// ```rust /// # use chromium::*; /// let shared: SharedSlice<'static, i32> = SharedSlice::default(); /// assert_eq!(shared.len(), 0); /// ``` #[inline(always)] fn default() -> Self { let life = PhantomData; let len = 0; let ptr = core::ptr::NonNull::dangling().as_ptr(); Self { ptr, len, life } } } impl<'a, T> Deref for SharedSlice<'a, T> where T: StableLayout, { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { // Safety: See note at the top of the module. unsafe { slice::from_raw_parts(self.ptr, self.len) } } } impl<'a, T> From<&'a [T]> for SharedSlice<'a, T> where T: StableLayout, { #[inline(always)] fn from(sli: &'a [T]) -> Self { let life = PhantomData; let len = sli.len(); let ptr = sli.as_ptr(); Self { ptr, len, life } } } impl<'a, T> From<SharedSlice<'a, T>> for &'a [T] where T: StableLayout, { #[inline(always)] fn from(shared: SharedSlice<'a, T>) -> Self { // Safety: See note at the top of the module. unsafe { slice::from_raw_parts(shared.ptr, shared.len) } } }