Skip to main content

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::{ManuallyDrop, forget};
7use core::ops::Deref;
8use core::ptr::NonNull;
9
10use crate::{Chunk, Decode, DecodeError, Decoder, DecoderExt as _, FromWire, IntoNatural, Wire};
11
12/// A type that can be borrowed as a decoder.
13///
14/// # Safety
15///
16/// Moving a value of this type must not invalidate any references to chunks
17/// returned from `take_chunks`. This usually means that the chunks returned
18/// from `take_chunks` point to non-local memory (e.g. on the heap, elsewhere on
19/// the stack).
20pub unsafe trait AsDecoder<'de> {
21    /// The borrowed decoder type.
22    type Decoder: Decoder<'de>;
23
24    /// Borrowes this value as a decoder.
25    fn as_decoder(&'de mut self) -> Self::Decoder;
26}
27
28unsafe impl<'de> AsDecoder<'de> for Vec<Chunk> {
29    type Decoder = &'de mut [Chunk];
30
31    fn as_decoder(&'de mut self) -> Self::Decoder {
32        self.as_mut_slice()
33    }
34}
35
36/// Extension methods for `AsDecoder`.
37pub trait AsDecoderExt: for<'de> AsDecoder<'de> {
38    /// Decodes a value from the decoder and finishes it.
39    ///
40    /// On success, returns `Ok` of a `Decoded` value with the decoder. Returns `Err` if decoding
41    /// failed or the decoder finished with an error.
42    fn into_decoded<T>(self) -> Result<Decoded<T, Self>, DecodeError>
43    where
44        Self: for<'de> AsDecoder<'de> + Sized,
45        T: Wire<Constraint = ()>,
46        for<'de> T::Narrowed<'de>: Decode<<Self as AsDecoder<'de>>::Decoder, Constraint = ()>;
47
48    /// Decodes a value from the decoder and finishes it.
49    ///
50    /// On success, returns `Ok` of a `Decoded` value with the decoder. Returns `Err` if decoding
51    /// failed or the decoder finished with an error.
52    fn into_decoded_with_constraint<T>(
53        self,
54        constraint: T::Constraint,
55    ) -> Result<Decoded<T, Self>, DecodeError>
56    where
57        Self: for<'de> AsDecoder<'de> + Sized,
58        T: Wire,
59        for<'de> T::Narrowed<'de>:
60            Decode<<Self as AsDecoder<'de>>::Decoder, Constraint = T::Constraint>;
61}
62
63impl<D: for<'de> AsDecoder<'de>> AsDecoderExt for D {
64    fn into_decoded<T>(self) -> Result<Decoded<T, Self>, DecodeError>
65    where
66        Self: for<'de> AsDecoder<'de> + Sized,
67        T: Wire<Constraint = ()>,
68        for<'de> T::Narrowed<'de>: Decode<<Self as AsDecoder<'de>>::Decoder, Constraint = ()>,
69    {
70        Self::into_decoded_with_constraint::<T>(self, ())
71    }
72
73    fn into_decoded_with_constraint<T>(
74        mut self,
75        constraint: T::Constraint,
76    ) -> Result<Decoded<T, Self>, DecodeError>
77    where
78        Self: for<'de> AsDecoder<'de> + Sized,
79        T: Wire,
80        for<'de> T::Narrowed<'de>:
81            Decode<<Self as AsDecoder<'de>>::Decoder, Constraint = T::Constraint>,
82    {
83        let mut decoder = self.as_decoder();
84        let mut slot = decoder.take_slot::<T::Narrowed<'_>>()?;
85        T::Narrowed::decode(slot.as_mut(), &mut decoder, constraint)?;
86        decoder.commit();
87        decoder.finish()?;
88
89        let ptr = unsafe { NonNull::new_unchecked(slot.as_mut_ptr().cast()) };
90        drop(decoder);
91        Ok(Decoded { ptr, decoder: ManuallyDrop::new(self) })
92    }
93}
94
95/// A decoded value and the decoder which contains it.
96pub struct Decoded<T: ?Sized, D> {
97    ptr: NonNull<T>,
98    decoder: ManuallyDrop<D>,
99}
100
101// SAFETY: `Decoded` doesn't add any restrictions on sending across thread boundaries, and so is
102// `Send` if `T` and `D` are `Send`.
103unsafe impl<T: Send + ?Sized, D: Send> Send for Decoded<T, D> {}
104
105// SAFETY: `Decoded` doesn't add any interior mutability, so it is `Sync` if `T` and `D` are `Sync`.
106unsafe impl<T: Sync + ?Sized, D: Sync> Sync for Decoded<T, D> {}
107
108impl<T: ?Sized, D> Drop for Decoded<T, D> {
109    fn drop(&mut self) {
110        // SAFETY: `ptr` points to a `T` which is safe to drop as an invariant of `Decoded`. We will
111        // only ever drop it once, since `drop` may only be called once.
112        unsafe {
113            self.ptr.as_ptr().drop_in_place();
114        }
115        // SAFETY: `decoder` is only ever dropped once, since `drop` may only be called once.
116        unsafe {
117            ManuallyDrop::drop(&mut self.decoder);
118        }
119    }
120}
121
122impl<T: ?Sized, D> Decoded<T, D> {
123    /// Returns the raw pointer and decoder used to create this `Decoded`.
124    pub fn into_raw_parts(mut self) -> (*mut T, D) {
125        let ptr = self.ptr.as_ptr();
126        // SAFETY: We forget `self` immediately after taking `self.decoder`, so we won't double-drop
127        // the decoder.
128        let decoder = unsafe { ManuallyDrop::take(&mut self.decoder) };
129        forget(self);
130        (ptr, decoder)
131    }
132
133    /// Takes the value out of this `Decoded` and calls `FromWire::from_wire` on the taken value to
134    /// convert it to the default natural type.
135    ///
136    /// This consumes the `Decoded`.
137    pub fn take(self) -> T::Natural
138    where
139        T: Wire + IntoNatural,
140        T::Natural: for<'de> FromWire<T::Narrowed<'de>>,
141    {
142        self.take_as::<T::Natural>()
143    }
144
145    /// Takes the value out of this `Decoded` and calls `U::from_wire` on the taken value.
146    ///
147    /// This consumes the `Decoded`.
148    pub fn take_as<U>(self) -> U
149    where
150        T: Wire,
151        U: for<'de> FromWire<T::Narrowed<'de>>,
152    {
153        self.take_with(|wire| U::from_wire(wire))
154    }
155
156    /// Takes the value out of this `Decoded` and passes it to the given function.
157    ///
158    /// This consumes the `Decoded`.
159    pub fn take_with<U>(self, f: impl for<'de> FnOnce(T::Narrowed<'de>) -> U) -> U
160    where
161        T: Wire,
162    {
163        let (ptr, decoder) = self.into_raw_parts();
164        let value = unsafe { ptr.cast::<T::Narrowed<'_>>().read() };
165        let result = f(value);
166        drop(decoder);
167        result
168    }
169}
170
171impl<T: ?Sized, B> Deref for Decoded<T, B> {
172    type Target = T;
173
174    fn deref(&self) -> &Self::Target {
175        // SAFETY: `ptr` is non-null, properly-aligned, and valid for reads and writes as an
176        // invariant of `Decoded`.
177        unsafe { self.ptr.as_ref() }
178    }
179}
180
181impl<T: fmt::Debug + ?Sized, B: fmt::Debug> fmt::Debug for Decoded<T, B> {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        self.deref().fmt(f)
184    }
185}