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}