Skip to main content

fidl_next_codec/wire/
ptr.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;
7
8use munge::munge;
9
10use crate::{Chunk, DecodeError, Slot, wire};
11use fidl_constants::{ALLOC_ABSENT_U64, ALLOC_PRESENT_U64};
12
13/// A raw FIDL pointer
14#[repr(C, align(8))]
15pub union Pointer<'de, T> {
16    encoded: wire::Uint64,
17    decoded: *mut T,
18    _phantom: PhantomData<&'de mut [Chunk]>,
19}
20
21// SAFETY: `Pointer` is a raw pointer wrapper and doesn't add any thread safety restrictions.
22unsafe impl<T: Send> Send for Pointer<'_, T> {}
23// SAFETY: `Pointer` contains no interior mutability.
24unsafe impl<T: Sync> Sync for Pointer<'_, T> {}
25
26impl<'de, T> Pointer<'de, T> {
27    /// Returns whether the wire pointer was encoded present.
28    pub fn is_encoded_present(slot: Slot<'_, Self>) -> Result<bool, DecodeError> {
29        // `unsafe` block required in the next version of munge
30        #[allow(unused_unsafe)]
31        // SAFETY: `slot` is a valid `Slot` of `Pointer`. Destructuring it is safe.
32        let encoded = unsafe {
33            munge!(let Self { encoded } = slot);
34            encoded
35        };
36        match **encoded {
37            ALLOC_ABSENT_U64 => Ok(false),
38            ALLOC_PRESENT_U64 => Ok(true),
39            x => Err(DecodeError::InvalidPointerPresence(x)),
40        }
41    }
42
43    /// Encodes that a pointer is present in an output.
44    pub fn encode_present(out: &mut MaybeUninit<Self>) {
45        // `unsafe` block required in the next version of munge
46        #[allow(unused_unsafe)]
47        // SAFETY: `out` is a valid mutable reference to a `MaybeUninit<Pointer>`.
48        // Destructuring it via `munge!` is safe.
49        let encoded = unsafe {
50            munge!(let Self { encoded } = out);
51            encoded
52        };
53        encoded.write(wire::Uint64(ALLOC_PRESENT_U64));
54    }
55
56    /// Encodes that a pointer is absent in a slot.
57    pub fn encode_absent(out: &mut MaybeUninit<Self>) {
58        // `unsafe` block required in the next version of munge
59        #[allow(unused_unsafe)]
60        // SAFETY: `out` is a valid mutable reference to a `MaybeUninit<Pointer>`.
61        // Destructuring it via `munge!` is safe.
62        let encoded = unsafe {
63            munge!(let Self { encoded } = out);
64            encoded
65        };
66        encoded.write(wire::Uint64(ALLOC_ABSENT_U64));
67    }
68
69    /// Sets the decoded value of the pointer.
70    pub fn set_decoded(slot: Slot<'_, Self>, mut value: Slot<'de, T>) {
71        // `unsafe` block required in the next version of munge
72        #[allow(unused_unsafe)]
73        // SAFETY: `slot` is a valid `Slot` of `Pointer`. Destructuring it is safe.
74        let mut decoded = unsafe {
75            munge!(let Self { decoded } = slot);
76            decoded
77        };
78        // SAFETY: Identical to `decoded.write(ptr.into_raw())`, but raw
79        // pointers don't currently implement `IntoBytes`.
80        unsafe {
81            *decoded.as_mut_ptr() = value.as_mut_ptr();
82        }
83    }
84
85    /// Sets the decoded value of the pointer to the first element of a slice.
86    pub fn set_decoded_slice(slot: Slot<'_, Self>, mut slice: Slot<'de, [T]>) {
87        // `unsafe` block required in the next version of munge
88        #[allow(unused_unsafe)]
89        // SAFETY: `slot` is a valid `Slot` of `Pointer`. Destructuring it is safe.
90        let mut decoded = unsafe {
91            munge!(let Self { decoded } = slot);
92            decoded
93        };
94        // SAFETY: Identical to `decoded.write(ptr.into_raw())`, but raw
95        // pointers don't currently implement `IntoBytes`.
96        unsafe {
97            *decoded.as_mut_ptr() = slice.as_mut_ptr().cast();
98        }
99    }
100
101    /// Returns the underlying pointer.
102    pub fn as_ptr(&self) -> *mut T {
103        // SAFETY: Reading a raw pointer from a union is safe because raw pointers have no validity
104        // invariants. The caller must ensure the pointer is valid before dereferencing it.
105        unsafe { self.decoded }
106    }
107}