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<'buf, T: ?Sized> {
21    ptr: *mut T,
22    _phantom: PhantomData<&'buf mut [u8]>,
23}
24
25impl<'buf, T: ?Sized> Slot<'buf, T> {
26    /// Returns a new `Slot` backed by the given `MaybeUninit`.
27    pub fn new(backing: &'buf mut MaybeUninit<T>) -> Self
28    where
29        T: Sized,
30    {
31        unsafe {
32            backing.as_mut_ptr().write_bytes(0, 1);
33        }
34        unsafe { Self::new_unchecked(backing.as_mut_ptr()) }
35    }
36
37    /// Creates a new slot from the given pointer.
38    ///
39    /// # Safety
40    ///
41    /// `ptr` must point to enough initialized bytes with the correct alignment
42    /// to represent a `T`.
43    pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
44        Self { ptr, _phantom: PhantomData }
45    }
46
47    /// Mutably reborrows the slot.
48    pub fn as_mut(&mut self) -> Slot<'_, T> {
49        Self { ptr: self.ptr, _phantom: PhantomData }
50    }
51
52    /// Returns a mutable pointer to the underlying potentially-invalid value.
53    pub fn as_mut_ptr(&mut self) -> *mut T {
54        self.ptr
55    }
56
57    /// Returns a pointer to the underlying potentially-invalid value.
58    pub fn as_ptr(&self) -> *const T {
59        self.ptr
60    }
61
62    /// Returns a reference to the contained value.
63    ///
64    /// # Safety
65    ///
66    /// The slot must contain a valid `T`.
67    pub unsafe fn deref_unchecked(&self) -> &T {
68        unsafe { &*self.as_ptr() }
69    }
70
71    /// Returns a mutable reference to the contained value.
72    ///
73    /// # Safety
74    ///
75    /// The slot must contain a valid `T`.
76    pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T {
77        unsafe { &mut *self.as_mut_ptr() }
78    }
79
80    /// Writes the given value into the slot.
81    pub fn write(&mut self, value: T)
82    where
83        T: IntoBytes + Sized,
84    {
85        unsafe {
86            self.as_mut_ptr().write(value);
87        }
88    }
89}
90
91impl<T> Slot<'_, T> {
92    /// Returns a slice of the underlying bytes.
93    pub fn as_bytes(&self) -> &[u8] {
94        unsafe { from_raw_parts(self.ptr.cast::<u8>(), size_of::<T>()) }
95    }
96}
97
98impl<T, const N: usize> Slot<'_, [T; N]> {
99    /// Returns a slot of the element at the given index.
100    pub fn index(&mut self, index: usize) -> Slot<'_, T> {
101        assert!(index < N, "attempted to index out-of-bounds");
102
103        Slot { ptr: unsafe { self.as_mut_ptr().cast::<T>().add(index) }, _phantom: PhantomData }
104    }
105}
106
107impl<T> Slot<'_, [T]> {
108    /// Creates a new slice slot from the given pointer.
109    ///
110    /// # Safety
111    ///
112    /// `ptr` must point to enough initialized bytes with the correct alignment
113    /// to represent a slice of `len` `T`s.
114    pub unsafe fn new_slice_unchecked(ptr: *mut T, len: usize) -> Self {
115        Self { ptr: slice_from_raw_parts_mut(ptr, len), _phantom: PhantomData }
116    }
117
118    /// Returns a slot of the element at the given index.
119    pub fn index(&mut self, index: usize) -> Slot<'_, T> {
120        assert!(index < self.ptr.len(), "attempted to index out-of-bounds");
121
122        Slot { ptr: unsafe { self.as_mut_ptr().cast::<T>().add(index) }, _phantom: PhantomData }
123    }
124}
125
126impl<T: FromBytes> Deref for Slot<'_, T> {
127    type Target = T;
128
129    fn deref(&self) -> &Self::Target {
130        unsafe { &*self.as_ptr() }
131    }
132}
133
134impl<T: FromBytes> DerefMut for Slot<'_, T> {
135    fn deref_mut(&mut self) -> &mut Self::Target {
136        unsafe { &mut *self.as_mut_ptr() }
137    }
138}
139
140impl<'buf, T> Iterator for Slot<'buf, [T]> {
141    type Item = Slot<'buf, T>;
142
143    fn next(&mut self) -> Option<Self::Item> {
144        if self.ptr.len() == 0 {
145            return None;
146        }
147
148        let result = Slot { ptr: self.ptr.cast::<T>(), _phantom: PhantomData };
149
150        self.ptr =
151            slice_from_raw_parts_mut(unsafe { self.ptr.cast::<T>().add(1) }, self.ptr.len() - 1);
152
153        Some(result)
154    }
155}
156
157unsafe impl<T> Destructure for Slot<'_, T> {
158    type Underlying = T;
159    type Destructuring = Move;
160
161    fn underlying(&mut self) -> *mut Self::Underlying {
162        self.as_mut_ptr()
163    }
164}
165
166unsafe impl<'buf, T, U: 'buf> Restructure<U> for Slot<'buf, T> {
167    type Restructured = Slot<'buf, U>;
168
169    unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured {
170        Slot { ptr, _phantom: PhantomData }
171    }
172}