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