fidl_next_codec/
decoded.rs

1// Copyright 2025 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::fmt;
6use core::mem::{forget, ManuallyDrop};
7use core::ops::Deref;
8use core::ptr::NonNull;
9
10use crate::{FromWire, Wire};
11
12/// A decoded value and the decoder which contains it.
13pub struct Decoded<T: ?Sized, D> {
14    ptr: NonNull<T>,
15    decoder: ManuallyDrop<D>,
16}
17
18// SAFETY: `Decoded` doesn't add any restrictions on sending across thread boundaries, and so is
19// `Send` if `T` and `D` are `Send`.
20unsafe impl<T: Send + ?Sized, D: Send> Send for Decoded<T, D> {}
21
22// SAFETY: `Decoded` doesn't add any interior mutability, so it is `Sync` if `T` and `D` are `Sync`.
23unsafe impl<T: Sync + ?Sized, D: Sync> Sync for Decoded<T, D> {}
24
25impl<T: ?Sized, D> Drop for Decoded<T, D> {
26    fn drop(&mut self) {
27        // SAFETY: `ptr` points to a `T` which is safe to drop as an invariant of `Decoded`. We will
28        // only ever drop it once, since `drop` may only be called once.
29        unsafe {
30            self.ptr.as_ptr().drop_in_place();
31        }
32        // SAFETY: `decoder` is only ever dropped once, since `drop` may only be called once.
33        unsafe {
34            ManuallyDrop::drop(&mut self.decoder);
35        }
36    }
37}
38
39impl<T: ?Sized, D> Decoded<T, D> {
40    /// Creates an owned value contained within a decoder.
41    ///
42    /// `Decoded` drops `ptr`, but does not free the backing memory. `decoder` should free the
43    /// memory backing `ptr` when dropped.
44    ///
45    /// # Safety
46    ///
47    /// - `ptr` must be non-null, properly-aligned, and valid for reads and writes.
48    /// - `ptr` must be valid for dropping.
49    /// - `ptr` must remain valid until `decoder` is dropped.
50    pub unsafe fn new_unchecked(ptr: *mut T, decoder: D) -> Self {
51        Self { ptr: unsafe { NonNull::new_unchecked(ptr) }, decoder: ManuallyDrop::new(decoder) }
52    }
53
54    /// Returns the raw pointer and decoder used to create this `Decoded`.
55    pub fn into_raw_parts(mut self) -> (*mut T, D) {
56        let ptr = self.ptr.as_ptr();
57        // SAFETY: We forget `self` immediately after taking `self.decoder`, so we won't double-drop
58        // the decoder.
59        let decoder = unsafe { ManuallyDrop::take(&mut self.decoder) };
60        forget(self);
61        (ptr, decoder)
62    }
63
64    /// Takes the value out of this `Decoded` and calls `From::from` on the taken value.
65    ///
66    /// This consumes the `Decoded`.
67    pub fn take<U>(self) -> U
68    where
69        T: Wire,
70        U: for<'de> FromWire<T::Decoded<'de>>,
71    {
72        self.take_with(|wire| U::from_wire(wire))
73    }
74
75    /// Takes the value out of this `Decoded` and passes it to the given function.
76    ///
77    /// This consumes the `Decoded`.
78    pub fn take_with<U>(self, f: impl FnOnce(T::Decoded<'_>) -> U) -> U
79    where
80        T: Wire,
81    {
82        let (ptr, decoder) = self.into_raw_parts();
83        let value = unsafe { ptr.cast::<T::Decoded<'_>>().read() };
84        let result = f(value);
85        drop(decoder);
86        result
87    }
88}
89
90impl<T: ?Sized, B> Deref for Decoded<T, B> {
91    type Target = T;
92
93    fn deref(&self) -> &Self::Target {
94        // SAFETY: `ptr` is non-null, properly-aligned, and valid for reads and writes as an
95        // invariant of `Decoded`.
96        unsafe { self.ptr.as_ref() }
97    }
98}
99
100impl<T: fmt::Debug + ?Sized, B: fmt::Debug> fmt::Debug for Decoded<T, B> {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        self.deref().fmt(f)
103    }
104}