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
21unsafe impl<T: Send> Send for Pointer<'_, T> {}
22unsafe impl<T: Sync> Sync for Pointer<'_, T> {}
23
24impl<'de, T> Pointer<'de, T> {
25    /// Returns whether the wire pointer was encoded present.
26    pub fn is_encoded_present(slot: Slot<'_, Self>) -> Result<bool, DecodeError> {
27        // `unsafe` block required in the next version of munge
28        #[allow(unused_unsafe)]
29        let encoded = unsafe {
30            munge!(let Self { encoded } = slot);
31            encoded
32        };
33        match **encoded {
34            ALLOC_ABSENT_U64 => Ok(false),
35            ALLOC_PRESENT_U64 => Ok(true),
36            x => Err(DecodeError::InvalidPointerPresence(x)),
37        }
38    }
39
40    /// Encodes that a pointer is present in an output.
41    pub fn encode_present(out: &mut MaybeUninit<Self>) {
42        // `unsafe` block required in the next version of munge
43        #[allow(unused_unsafe)]
44        let encoded = unsafe {
45            munge!(let Self { encoded } = out);
46            encoded
47        };
48        encoded.write(wire::Uint64(ALLOC_PRESENT_U64));
49    }
50
51    /// Encodes that a pointer is absent in a slot.
52    pub fn encode_absent(out: &mut MaybeUninit<Self>) {
53        // `unsafe` block required in the next version of munge
54        #[allow(unused_unsafe)]
55        let encoded = unsafe {
56            munge!(let Self { encoded } = out);
57            encoded
58        };
59        encoded.write(wire::Uint64(ALLOC_ABSENT_U64));
60    }
61
62    /// Sets the decoded value of the pointer.
63    pub fn set_decoded(slot: Slot<'_, Self>, mut value: Slot<'de, T>) {
64        // `unsafe` block required in the next version of munge
65        #[allow(unused_unsafe)]
66        let mut decoded = unsafe {
67            munge!(let Self { decoded } = slot);
68            decoded
69        };
70        // SAFETY: Identical to `decoded.write(ptr.into_raw())`, but raw
71        // pointers don't currently implement `IntoBytes`.
72        unsafe {
73            *decoded.as_mut_ptr() = value.as_mut_ptr();
74        }
75    }
76
77    /// Sets the decoded value of the pointer to the first element of a slice.
78    pub fn set_decoded_slice(slot: Slot<'_, Self>, mut slice: Slot<'de, [T]>) {
79        // `unsafe` block required in the next version of munge
80        #[allow(unused_unsafe)]
81        let mut decoded = unsafe {
82            munge!(let Self { decoded } = slot);
83            decoded
84        };
85        // SAFETY: Identical to `decoded.write(ptr.into_raw())`, but raw
86        // pointers don't currently implement `IntoBytes`.
87        unsafe {
88            *decoded.as_mut_ptr() = slice.as_mut_ptr().cast();
89        }
90    }
91
92    /// Returns the underlying pointer.
93    pub fn as_ptr(&self) -> *mut T {
94        unsafe { self.decoded }
95    }
96}