fidl_next_codec/
slot.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::marker::PhantomData;
6use core::mem::MaybeUninit;
7use core::ops::{Deref, DerefMut};
8use core::ptr::slice_from_raw_parts_mut;
9use core::slice::from_raw_parts;
10
11use munge::{Destructure, Move, Restructure};
12use zerocopy::{FromBytes, IntoBytes};
13
14/// An initialized but potentially invalid value.
15///
16/// The bytes of a `Slot` are always valid to read, but may not represent a
17/// valid value of its type. For example, a `Slot<'_, bool>` may not be set to
18/// 0 or 1.
19#[repr(transparent)]
20pub struct Slot<'de, T: ?Sized> {
21    ptr: *mut T,
22    _phantom: PhantomData<&'de mut [u8]>,
23}
24
25unsafe impl<T: Send> Send for Slot<'_, T> {}
26unsafe impl<T: Sync> Sync for Slot<'_, T> {}
27
28impl<'de, T: ?Sized> Slot<'de, T> {
29    /// Returns a new `Slot` backed by the given `MaybeUninit`.
30    pub fn new(backing: &'de mut MaybeUninit<T>) -> Self
31    where
32        T: Sized,
33    {
34        unsafe {
35            backing.as_mut_ptr().write_bytes(0, 1);
36        }
37        unsafe { Self::new_unchecked(backing.as_mut_ptr()) }
38    }
39
40    /// Creates a new slot from the given pointer.
41    ///
42    /// # Safety
43    ///
44    /// `ptr` must point to enough initialized bytes with the correct alignment
45    /// to represent a `T`.
46    pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
47        Self { ptr, _phantom: PhantomData }
48    }
49
50    /// Mutably reborrows the slot.
51    pub fn as_mut(&mut self) -> Slot<'_, T> {
52        Self { ptr: self.ptr, _phantom: PhantomData }
53    }
54
55    /// Returns a mutable pointer to the underlying potentially-invalid value.
56    pub fn as_mut_ptr(&mut self) -> *mut T {
57        self.ptr
58    }
59
60    /// Returns a pointer to the underlying potentially-invalid value.
61    pub fn as_ptr(&self) -> *const T {
62        self.ptr
63    }
64
65    /// Returns a reference to the contained value.
66    ///
67    /// # Safety
68    ///
69    /// The slot must contain a valid `T`.
70    pub unsafe fn deref_unchecked(&self) -> &T {
71        unsafe { &*self.as_ptr() }
72    }
73
74    /// Returns a mutable reference to the contained value.
75    ///
76    /// # Safety
77    ///
78    /// The slot must contain a valid `T`.
79    pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T {
80        unsafe { &mut *self.as_mut_ptr() }
81    }
82
83    /// Writes the given value into the slot.
84    pub fn write(&mut self, value: T)
85    where
86        T: IntoBytes + Sized,
87    {
88        unsafe {
89            self.as_mut_ptr().write(value);
90        }
91    }
92}
93
94impl<T> Slot<'_, T> {
95    /// Returns a slice of the underlying bytes.
96    pub fn as_bytes(&self) -> &[u8] {
97        unsafe { from_raw_parts(self.ptr.cast::<u8>(), size_of::<T>()) }
98    }
99}
100
101impl<T, const N: usize> Slot<'_, [T; N]> {
102    /// Returns a slot of the element at the given index.
103    pub fn index(&mut self, index: usize) -> Slot<'_, T> {
104        assert!(index < N, "attempted to index out-of-bounds");
105
106        Slot { ptr: unsafe { self.as_mut_ptr().cast::<T>().add(index) }, _phantom: PhantomData }
107    }
108}
109
110impl<T> Slot<'_, [T]> {
111    /// Creates a new slice slot from the given pointer.
112    ///
113    /// # Safety
114    ///
115    /// `ptr` must point to enough initialized bytes with the correct alignment
116    /// to represent a slice of `len` `T`s.
117    pub unsafe fn new_slice_unchecked(ptr: *mut T, len: usize) -> Self {
118        Self { ptr: slice_from_raw_parts_mut(ptr, len), _phantom: PhantomData }
119    }
120
121    /// Returns a slot of the element at the given index.
122    pub fn index(&mut self, index: usize) -> Slot<'_, T> {
123        assert!(index < self.ptr.len(), "attempted to index out-of-bounds");
124
125        Slot { ptr: unsafe { self.as_mut_ptr().cast::<T>().add(index) }, _phantom: PhantomData }
126    }
127}
128
129impl<T: FromBytes> Deref for Slot<'_, T> {
130    type Target = T;
131
132    fn deref(&self) -> &Self::Target {
133        unsafe { &*self.as_ptr() }
134    }
135}
136
137impl<T: FromBytes> DerefMut for Slot<'_, T> {
138    fn deref_mut(&mut self) -> &mut Self::Target {
139        unsafe { &mut *self.as_mut_ptr() }
140    }
141}
142
143impl<'de, T> Iterator for Slot<'de, [T]> {
144    type Item = Slot<'de, T>;
145
146    fn next(&mut self) -> Option<Self::Item> {
147        if self.ptr.len() == 0 {
148            return None;
149        }
150
151        let result = Slot { ptr: self.ptr.cast::<T>(), _phantom: PhantomData };
152
153        self.ptr =
154            slice_from_raw_parts_mut(unsafe { self.ptr.cast::<T>().add(1) }, self.ptr.len() - 1);
155
156        Some(result)
157    }
158}
159
160unsafe impl<T> Destructure for Slot<'_, T> {
161    type Underlying = T;
162    type Destructuring = Move;
163
164    fn underlying(&mut self) -> *mut Self::Underlying {
165        self.as_mut_ptr()
166    }
167}
168
169unsafe impl<'de, T, U: 'de> Restructure<U> for Slot<'de, T> {
170    type Restructured = Slot<'de, U>;
171
172    unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured {
173        Slot { ptr, _phantom: PhantomData }
174    }
175}