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}