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
10/// A decoded value and the decoder which contains it.
11pub struct Decoded<T: ?Sized, D> {
12    ptr: NonNull<T>,
13    decoder: ManuallyDrop<D>,
14}
15
16// SAFETY: `Decoded` doesn't add any restrictions on sending across thread boundaries, and so is
17// `Send` if `T` and `D` are `Send`.
18unsafe impl<T: Send + ?Sized, D: Send> Send for Decoded<T, D> {}
19
20// SAFETY: `Decoded` doesn't add any interior mutability, so it is `Sync` if `T` and `D` are `Sync`.
21unsafe impl<T: Sync + ?Sized, D: Sync> Sync for Decoded<T, D> {}
22
23impl<T: ?Sized, D> Drop for Decoded<T, D> {
24    fn drop(&mut self) {
25        // SAFETY: `ptr` points to a `T` which is safe to drop as an invariant of `Decoded`. We will
26        // only ever drop it once, since `drop` may only be called once.
27        unsafe {
28            self.ptr.as_ptr().drop_in_place();
29        }
30        // SAFETY: `decoder` is only ever dropped once, since `drop` may only be called once.
31        unsafe {
32            ManuallyDrop::drop(&mut self.decoder);
33        }
34    }
35}
36
37impl<T: ?Sized, D> Decoded<T, D> {
38    /// Creates an owned value contained within a decoder.
39    ///
40    /// `Decoded` drops `ptr`, but does not free the backing memory. `decoder` should free the
41    /// memory backing `ptr` when dropped.
42    ///
43    /// # Safety
44    ///
45    /// - `ptr` must be non-null, properly-aligned, and valid for reads and writes.
46    /// - `ptr` must be valid for dropping.
47    /// - `ptr` must remain valid until `decoder` is dropped.
48    pub unsafe fn new_unchecked(ptr: *mut T, decoder: D) -> Self {
49        Self { ptr: unsafe { NonNull::new_unchecked(ptr) }, decoder: ManuallyDrop::new(decoder) }
50    }
51
52    /// Returns the raw pointer and decoder used to create this `Decoded`.
53    pub fn into_raw_parts(mut self) -> (*mut T, D) {
54        let ptr = self.ptr.as_ptr();
55        // SAFETY: We forget `self` immediately after taking `self.decoder`, so we won't double-drop
56        // the decoder.
57        let decoder = unsafe { ManuallyDrop::take(&mut self.decoder) };
58        forget(self);
59        (ptr, decoder)
60    }
61}
62
63impl<T: ?Sized, B> Deref for Decoded<T, B> {
64    type Target = T;
65
66    fn deref(&self) -> &Self::Target {
67        // SAFETY: `ptr` is non-null, properly-aligned, and valid for reads and writes as an
68        // invariant of `Decoded`.
69        unsafe { self.ptr.as_ref() }
70    }
71}
72
73impl<T: fmt::Debug + ?Sized, B: fmt::Debug> fmt::Debug for Decoded<T, B> {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        self.deref().fmt(f)
76    }
77}