Skip to main content

xdrs/
read_xdr.rs

1//! Reading XDR data into Rust types.
2//!
3//! This module provides the [`ReadXDR`] trait and implementations for
4//! converting [XDR][RFC-4506]-encoded data (as defined in RFC 4506)
5//! into Rust values.
6//!
7//! # Stack usage
8//!
9//! Decoding does not enforce a recursion depth limit. Types that are
10//! recursive through a heap-allocated container (e.g.
11//! `Vec<Node>` where `Node` contains another `Vec<Node>`) will
12//! recurse once per nesting level in the input, and a sufficiently
13//! deep input can exhaust the call stack.
14//!
15//! Similarly, decoding a large fixed-size array `[T; N]` or a
16//! `heapless::Vec<T, N>` with a large `N` requires corresponding
17//! stack space, because those types are stack-allocated by
18//! definition.
19//!
20//! The recommended approach for untrusted input is to define types
21//! with static nesting depth (e.g. a fixed chain of structs instead
22//! of a recursive `Vec<Node>`) so that stack usage is bounded at
23//! compile time. When recursive types are unavoidable, callers
24//! should apply their own resource limits (e.g. capping input length
25//! or running the decoder on a thread with a sized stack) rather
26//! than relying on the decoder to bound stack usage.
27//!
28//! [RFC-4506]: https://datatracker.ietf.org/doc/html/rfc4506
29
30use crate::mu;
31use crate::serialize::reader::*;
32use crate::valid_u32::*;
33use core::convert::Infallible;
34use core::mem::MaybeUninit as MU;
35
36#[cfg(feature = "alloc")]
37use xdr_common::MAX_PREALLOC_BYTES;
38
39struct PartialInitGuard<'a, T> {
40    slice: &'a mut [MU<T>],
41    initialized: usize,
42}
43
44impl<T> Drop for PartialInitGuard<'_, T> {
45    fn drop(&mut self) {
46        // `take` rather than indexing `[..self.initialized]`: the bound holds
47        // by construction, but it is not visible here, so the index would keep
48        // a bounds check and a panicking branch in every array and VecM decode.
49        for elt in self.slice.iter_mut().take(self.initialized) {
50            // SAFETY: elements up to `self.initialized` were successfully
51            // written via `MaybeUninit::write` before the count was incremented.
52            unsafe {
53                elt.assume_init_drop();
54            }
55        }
56    }
57}
58
59/// Reads an XDR value of type `T` from the reader `r`.
60///
61/// This is a convenience function that calls [`ReadXDR::read_xdr`] on the type.
62///
63/// # Example
64///
65/// ```rust
66/// use xdrs::cxs;
67/// // Valid CXS-encoded u32 value of 0 (just one byte)
68/// let data = [0u8];
69/// let _value: u32 = cxs::decode(&data)?;
70/// # Ok::<(), xdrs::ReadError>(())
71/// ```
72#[inline]
73pub fn read_xdr<'r, R, T>(r: &mut R) -> ReadResult<T>
74where
75    R: Reader<'r>,
76    T: ReadXDR<'r>,
77{
78    <T as ReadXDR>::read_xdr(r)
79}
80
81/// Types that can be constructed by reading XDR-encoded data, possibly
82/// sharing data from the input.
83///
84/// The lifetime parameter `'r` represents the lifetime of data borrowed
85/// from the reader.
86///
87/// Borrowed types implement this for every lifetime the reader outlives:
88/// `&'a [u8]`, `&'a [u8; N]` and `&'a str` are `ReadXDR<'r>` whenever
89/// `'r: 'a`, not only when `'a` is `'r` itself. So a decoded borrow can be
90/// placed somewhere whose type is already fixed to a shorter lifetime, such
91/// as a slot behind `&mut` or a generic parameter inferred from one, without
92/// relying on the use site to shorten it.
93///
94/// # Derived impls and struct lifetimes
95///
96/// `#[derive(ReadXDR)]` on a type `Foo<'a, 'b, ..>` emits an impl of the
97/// form `impl<'_r: 'a + 'b + .., 'a, 'b, ..> ReadXDR<'_r> for Foo<'a, 'b, ..>`.
98/// That is: **every lifetime parameter on the type must be `<=` the lifetime
99/// of the reader buffer**, regardless of whether that parameter is actually
100/// used to borrow from the buffer. In particular, a phantom lifetime such as
101/// `PhantomData<&'a ()>` is constrained alongside any "real" borrow.
102///
103/// Practical implication: you cannot decode `Foo<'static>` from a buffer
104/// whose lifetime isn't `'static`. If a type has a lifetime parameter that
105/// doesn't actually borrow from the buffer (e.g. it's purely a phantom
106/// marker), let the lifetime be inferred from the buffer rather than
107/// naming it explicitly, or implement `ReadXDR` by hand.
108///
109/// Custom borrowed field types need the same bounds as the built-in borrows:
110/// implement `ReadXDR<'r>` for `Borrowed<'a>` whenever `'r: 'a`. An impl only
111/// for `ReadXDR<'a> for Borrowed<'a>` can work by value through lifetime
112/// coercion, but cannot fill a field whose type is fixed behind `&mut`.
113///
114/// ```rust
115/// use xdrs::{ReadXDR, ReadResult};
116/// use xdrs::serialize::reader::Reader;
117///
118/// struct Borrowed<'a>(&'a [u8]);
119///
120/// impl<'r: 'a, 'a> ReadXDR<'r> for Borrowed<'a> {
121///     fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
122///         Ok(Self(r.read_opaque_variable(u32::MAX)?))
123///     }
124/// }
125/// ```
126///
127/// # In-place decoding
128///
129/// [`ReadXDR::read_xdr_in_place`] decodes straight into a destination that
130/// the decoder hands over as a [`Slot`], and returns an [`Init`] proving
131/// that the slot was filled. The trait is safe to implement because an
132/// `Init` can only be produced from the slot it refers to: safely through
133/// [`Slot::write`], or through [`Slot::assume_init`] once the implementation
134/// has initialized the value itself. A decoder such as `Box`,
135/// `Vec` or a derived struct relies on that proof to treat the destination
136/// as initialized and, later, to drop it.
137///
138/// Most types keep the default, which decodes with [`ReadXDR::read_xdr`] and
139/// writes the result into the slot. An override only has to make sure that
140/// on an error or panic nothing is left in the slot that needs dropping:
141/// callers never drop a destination they did not get an `Init` for, so an
142/// override that initializes part of the value before failing must drop
143/// what it wrote.
144///
145/// A safe override cannot return a value that lives somewhere else:
146///
147/// ```rust,compile_fail
148/// use xdrs::{Init, ReadXDR, ReadResult, Slot};
149/// use xdrs::serialize::reader::Reader;
150///
151/// struct Elsewhere(u32);
152///
153/// impl<'r> ReadXDR<'r> for Elsewhere {
154///     fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
155///         Ok(Self(r.read_u32()?))
156///     }
157///
158///     fn read_xdr_in_place<'s, R: Reader<'r>>(
159///         r: &mut R,
160///         slot: Slot<'s, Self>,
161///     ) -> ReadResult<Init<'s, Self>> {
162///         // error: expected `Init<'s, Elsewhere>`, found `&mut Elsewhere`
163///         Ok(Box::leak(Box::new(Self::read_xdr(r)?)))
164///     }
165/// }
166/// ```
167///
168/// # Example
169///
170/// ```rust
171/// use xdrs::{ReadXDR, cxs};
172///
173/// let data = [0u8]; // valid CXS encoding for the unsigned integer 0
174/// let _value: u32 = cxs::decode(&data)?;
175/// # Ok::<(), xdrs::ReadError>(())
176/// ```
177pub trait ReadXDR<'r>: Sized {
178    /// Reads an XDR value from the reader.
179    ///
180    /// This method should read the appropriate amount of data from the reader
181    /// and construct a value of type `Self`.
182    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self>;
183
184    /// Reads an XDR value directly into `slot`, without first building it
185    /// on the stack.
186    ///
187    /// The returned [`Init`] proves that `slot` holds a valid `Self`; it
188    /// comes from [`Slot::write`], or from [`Slot::assume_init`] after the
189    /// implementation initialized the value through [`Slot::as_mut_ptr`].
190    /// On error, nothing in `slot` may be left that needs dropping: an
191    /// implementation that writes part of the value before failing must
192    /// drop what it wrote.
193    ///
194    /// The default implementation decodes with [`ReadXDR::read_xdr`] and
195    /// moves the result into `slot`. Overriding it pays off for large
196    /// values, such as structs with big fixed-size arrays, that would
197    /// otherwise be built in a stack frame and then copied. Callers with a
198    /// `MaybeUninit` destination go through [`read_xdr_in_place`].
199    #[inline]
200    fn read_xdr_in_place<'s, R: Reader<'r>>(
201        r: &mut R,
202        slot: Slot<'s, Self>,
203    ) -> ReadResult<Init<'s, Self>> {
204        Ok(slot.write(Self::read_xdr(r)?))
205    }
206}
207
208/// The destination of an in-place decode: uninitialized storage for a `T`,
209/// borrowed for `'s`.
210///
211/// The decoder creates one for each call to [`ReadXDR::read_xdr_in_place`];
212/// there is no safe way to make one. Writing a value with [`Slot::write`]
213/// consumes the slot and yields the [`Init`] the method returns, so a safe
214/// implementation can only fulfil its contract by filling this very slot.
215/// Implementations that initialize the value piecewise write through
216/// [`Slot::as_mut_ptr`] and then call [`Slot::assume_init`].
217#[repr(transparent)]
218pub struct Slot<'s, T> {
219    slot: &'s mut MU<T>,
220}
221
222impl<'s, T> Slot<'s, T> {
223    /// Creates a slot for the storage behind `ptr`.
224    ///
225    /// # Safety
226    ///
227    /// `ptr` must be valid for writes, properly aligned, not aliased for
228    /// `'s`, and must not hold a value that needs dropping. The slot stands
229    /// for that storage alone: an [`Init`] obtained from it proves only that
230    /// `*ptr` is initialized, and must not be returned from
231    /// [`ReadXDR::read_xdr_in_place`] in place of the slot that call was
232    /// given.
233    #[inline]
234    pub unsafe fn from_raw(ptr: *mut T) -> Self {
235        // SAFETY: the caller guarantees `ptr` is valid, aligned, and
236        // unaliased for `'s`; `MaybeUninit<T>` has the same layout as `T`.
237        Self {
238            slot: unsafe { &mut *ptr.cast::<MU<T>>() },
239        }
240    }
241
242    /// Writes `value` into the slot.
243    #[inline]
244    pub fn write(self, value: T) -> Init<'s, T> {
245        Init {
246            value: self.slot.write(value),
247        }
248    }
249
250    /// A pointer to the storage, for initializing the value piecewise.
251    ///
252    /// Writing through it is sound; reading or dropping is not until the
253    /// value is initialized.
254    #[inline]
255    pub fn as_mut_ptr(&mut self) -> *mut T {
256        self.slot.as_mut_ptr()
257    }
258
259    /// The storage as `MaybeUninit`.
260    #[inline]
261    pub fn as_uninit_mut(&mut self) -> &mut MU<T> {
262        self.slot
263    }
264
265    /// Declares the slot initialized.
266    ///
267    /// # Safety
268    ///
269    /// The storage must hold a valid `T`, written through
270    /// [`Slot::as_mut_ptr`] or [`Slot::as_uninit_mut`].
271    #[inline]
272    pub unsafe fn assume_init(self) -> Init<'s, T> {
273        // SAFETY: the caller guarantees the storage is initialized.
274        Init {
275            value: unsafe { self.slot.assume_init_mut() },
276        }
277    }
278}
279
280/// Proof that a [`Slot`] was initialized: a reference to the decoded value
281/// in its destination.
282///
283/// Only [`Slot::write`] and [`Slot::assume_init`] produce one, so holding
284/// an `Init<'s, T>` means the slot it came from holds a valid `T`.
285#[repr(transparent)]
286pub struct Init<'s, T> {
287    value: &'s mut T,
288}
289
290impl<'s, T> Init<'s, T> {
291    /// The decoded value, in its destination.
292    #[inline]
293    pub fn into_mut(self) -> &'s mut T {
294        self.value
295    }
296}
297
298/// Reads an XDR value of type `T` from the reader `r` directly into `slot`.
299///
300/// On success, `slot` is initialized and the returned reference points to
301/// it. On error, `slot` is left uninitialized with nothing to drop.
302#[inline]
303pub fn read_xdr_in_place<'r, 's, R, T>(r: &mut R, slot: &'s mut MU<T>) -> ReadResult<&'s mut T>
304where
305    R: Reader<'r>,
306    T: ReadXDR<'r>,
307{
308    Ok(T::read_xdr_in_place(r, Slot { slot })?.into_mut())
309}
310
311/// Support code for `#[derive(ReadXDR)]`. Not public API.
312#[doc(hidden)]
313pub mod in_place {
314    use super::*;
315
316    /// Drops one already-decoded field if a later field fails to decode.
317    ///
318    /// Generated code creates one guard per field as it goes and forgets
319    /// them all once every field is written. Guards drop in reverse order on
320    /// an early return, which unwinds exactly the fields written so far.
321    pub struct FieldGuard<T>(*mut T);
322
323    impl<T> Drop for FieldGuard<T> {
324        #[inline]
325        fn drop(&mut self) {
326            // SAFETY: a guard is only created for a field that was fully
327            // initialized, and only dropped (rather than forgotten) when the
328            // enclosing value is abandoned, so the field is dropped once.
329            unsafe { core::ptr::drop_in_place(self.0) }
330        }
331    }
332
333    /// Decodes a field of type `F` into the field at `field`.
334    ///
335    /// # Safety
336    ///
337    /// `field` must be valid for writes, properly aligned, not aliased for
338    /// the duration of the call, and must not hold a value that needs
339    /// dropping. It must remain valid and initialized until the returned
340    /// guard is dropped or forgotten; the guard owns the right to drop it.
341    #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
342    pub unsafe fn read_field<'r, R, F>(r: &mut R, field: *mut F) -> ReadResult<FieldGuard<F>>
343    where
344        R: Reader<'r>,
345        F: ReadXDR<'r>,
346    {
347        // SAFETY: the caller guarantees `field` is valid, aligned and
348        // unaliased, and the `Init` is consumed here, as proof for this
349        // field only.
350        let slot = unsafe { Slot::from_raw(field) };
351        F::read_xdr_in_place(r, slot)?;
352        Ok(FieldGuard(field))
353    }
354
355    /// Moves an already-built value into the field at `field`.
356    ///
357    /// Used for fields decoded through `#[xdr(from = ..)]` or `via`, which
358    /// must be converted before they can be stored.
359    ///
360    /// # Safety
361    ///
362    /// Same as [`read_field`].
363    #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
364    pub unsafe fn write_field<F>(field: *mut F, value: F) -> FieldGuard<F> {
365        // SAFETY: forwarded caller contract.
366        unsafe { field.write(value) };
367        FieldGuard(field)
368    }
369}
370
371/// Types that can be constructed by reading XDR data
372/// of any lifetime.
373///
374/// This trait is automatically implemented for any type that implements
375/// [`ReadXDR`] for all lifetimes. It's useful for types that don't borrow
376/// data from the reader.
377pub trait ReadXDROwned: for<'r> ReadXDR<'r> {}
378
379impl<T> ReadXDROwned for T where T: for<'r> ReadXDR<'r> {}
380
381macro_rules! construct_int_impls {
382    { $( $read_method:ident for $int_ty:ty ),* $(,)? } => { $(
383
384        impl<'r> ReadXDR<'r> for $int_ty {
385            #[inline]
386            fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<$int_ty> {
387                r.$read_method()
388            }
389        }
390
391    )* };
392}
393
394construct_int_impls! {
395    read_i64 for i64,
396    read_i32 for i32,
397    read_i16 for i16,
398
399    read_u64 for u64,
400    read_u32 for u32,
401    read_u16 for u16,
402
403    read_bool for bool,
404    read_f32 for f32,
405    read_f64 for f64,
406}
407
408impl<'r, T, const N: usize> ReadXDR<'r> for [T; N]
409where
410    T: ReadXDR<'r>,
411{
412    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
413        let () = ValidU32::<N>::OK;
414
415        let mut arr: [MU<T>; N] = [const { MU::uninit() }; N];
416        let mut guard = PartialInitGuard {
417            slice: &mut arr,
418            initialized: 0,
419        };
420
421        for elt in guard.slice.iter_mut() {
422            elt.write(read_xdr(r)?);
423            guard.initialized += 1;
424        }
425
426        core::mem::forget(guard);
427
428        // SAFETY: all elements have been initialized
429        let arr = unsafe { mu::array_assume_init(arr) };
430
431        Ok(arr)
432    }
433
434    fn read_xdr_in_place<'s, R: Reader<'r>>(
435        r: &mut R,
436        mut slot: Slot<'s, Self>,
437    ) -> ReadResult<Init<'s, Self>> {
438        let () = ValidU32::<N>::OK;
439
440        // SAFETY: `[T; N]` has the same layout as `[MaybeUninit<T>; N]`,
441        // and `slot` is borrowed for the whole call.
442        let elems = unsafe { &mut *slot.as_mut_ptr().cast::<[MU<T>; N]>() };
443        let mut guard = PartialInitGuard {
444            slice: elems,
445            initialized: 0,
446        };
447
448        for elt in guard.slice.iter_mut() {
449            read_xdr_in_place(r, elt)?;
450            guard.initialized += 1;
451        }
452
453        core::mem::forget(guard);
454
455        // SAFETY: all elements have been initialized
456        Ok(unsafe { slot.assume_init() })
457    }
458}
459
460// Borrowed types are decodable for every lifetime the reader buffer
461// outlives, not only the reader's own: the borrow comes out of the reader as
462// `&'r _` and is shortened to `'a` here. This matters wherever the decoded
463// type is fixed by an invariant position (a generic parameter, a slot
464// behind `&mut`), where the shortening cannot happen at the use site.
465impl<'r: 'a, 'a> ReadXDR<'r> for &'a [u8] {
466    #[inline]
467    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
468        let bytes: &'r [u8] = r.read_opaque_variable(u32::MAX)?;
469        Ok(bytes)
470    }
471}
472
473impl<'r: 'a, 'a, const N: usize> ReadXDR<'r> for &'a [u8; N] {
474    #[inline]
475    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
476        let () = ValidU32::<N>::OK;
477        let len = N as u32;
478
479        // SAFETY: read_opaque_fixed returns a slice of exactly `len` bytes,
480        // and len == N as u32, so the slice length matches the array size.
481        let bytes: &'r [u8; N] = unsafe {
482            r.read_opaque_fixed(len as usize)?
483                .try_into()
484                .unwrap_unchecked()
485        };
486        Ok(bytes)
487    }
488}
489
490impl<'r, const N: usize> ReadXDR<'r> for [u8; N] {
491    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
492        let () = ValidU32::<N>::OK;
493
494        let mut arr: [MU<u8>; N] = [MU::uninit(); N];
495
496        // Panic-safe: arr has exactly N elements and len is N as u32.
497        r.read_opaque_fixed_into(&mut arr, N as u32)?;
498
499        // SAFETY: read_opaque_fixed_into initialized all N elements.
500        let arr = unsafe { mu::array_assume_init(arr) };
501
502        Ok(arr)
503    }
504
505    fn read_xdr_in_place<'s, R: Reader<'r>>(
506        r: &mut R,
507        mut slot: Slot<'s, Self>,
508    ) -> ReadResult<Init<'s, Self>> {
509        let () = ValidU32::<N>::OK;
510
511        // SAFETY: `[u8; N]` has the same layout as
512        // `[MaybeUninit<u8>; N]`, and `slot` is borrowed for the whole call.
513        let bytes = unsafe { &mut *slot.as_mut_ptr().cast::<[MU<u8>; N]>() };
514
515        // Panic-safe: bytes has exactly N elements and len is N as u32.
516        r.read_opaque_fixed_into(bytes, N as u32)?;
517
518        // SAFETY: read_opaque_fixed_into initialized all N elements.
519        Ok(unsafe { slot.assume_init() })
520    }
521}
522
523impl<'r: 'a, 'a> ReadXDR<'r> for &'a str {
524    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
525        let bytes: &'r [u8] = r.read_opaque_variable(u32::MAX)?;
526        let s: &'r str = str::from_utf8(bytes).map_err(|_| ReadError::bad_utf8())?;
527        Ok(s)
528    }
529}
530
531#[cfg(feature = "alloc")]
532#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
533impl<'r> ReadXDR<'r> for alloc::string::String {
534    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
535        let bytes = r.read_opaque_variable(u32::MAX)?;
536        let s = str::from_utf8(bytes).map_err(|_| ReadError::bad_utf8())?;
537        Ok(alloc::string::String::from(s))
538    }
539}
540
541impl<'r> ReadXDR<'r> for () {
542    fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
543        Ok(())
544    }
545}
546
547impl<'r> ReadXDR<'r> for Infallible {
548    fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
549        unreachable!()
550    }
551}
552
553macro_rules! read_tuple {
554    { $( $index:tt : $t:ident ),+ $(,)? } => {
555        impl<'r, $($t),+> ReadXDR<'r> for ($($t,)+)
556        where
557            $( $t: ReadXDR<'r>, )+
558        {
559            fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
560                Ok(($(read_xdr::<R, $t>(r)?,)+))
561            }
562
563            #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
564            fn read_xdr_in_place<'s, R: Reader<'r>>(
565                r: &mut R,
566                mut slot: Slot<'s, Self>,
567            ) -> ReadResult<Init<'s, Self>> {
568                let base = slot.as_mut_ptr();
569                // SAFETY: tuple fields are aligned, disjoint, and in the
570                // caller's exclusively borrowed slot. If a read fails, Rust
571                // drops the guards already constructed in this tuple.
572                let guards = ($(unsafe {
573                    in_place::read_field(r, &raw mut (*base).$index)?
574                },)+);
575                core::mem::forget(guards);
576                // SAFETY: every tuple field was successfully initialized.
577                Ok(unsafe { slot.assume_init() })
578            }
579        }
580    };
581}
582
583read_tuple!(0: T1);
584read_tuple!(0: T1, 1: T2);
585read_tuple!(0: T1, 1: T2, 2: T3);
586read_tuple!(0: T1, 1: T2, 2: T3, 3: T4);
587read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5);
588read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6);
589read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7);
590read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8);
591read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9);
592read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10);
593read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11);
594read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11, 11: T12);
595read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11, 11: T12, 12: T13);
596read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11, 11: T12, 12: T13, 13: T14);
597read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11, 11: T12, 12: T13, 13: T14, 14: T15);
598read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11, 11: T12, 12: T13, 13: T14, 14: T15, 15: T16);
599
600impl<'r, T> ReadXDR<'r> for Option<T>
601where
602    T: ReadXDR<'r>,
603{
604    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
605        let is_present = r.read_bool()?;
606        if is_present {
607            Ok(Some(read_xdr(r)?))
608        } else {
609            Ok(None)
610        }
611    }
612
613    #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
614    fn read_xdr_in_place<'s, R: Reader<'r>>(
615        r: &mut R,
616        slot: Slot<'s, Self>,
617    ) -> ReadResult<Init<'s, Self>> {
618        if !r.read_bool()? {
619            return Ok(slot.write(None));
620        }
621
622        // Option's payload layout is not specified for arbitrary T. Decode
623        // into one payload temporary, then construct Some normally. This
624        // avoids the additional Result<Option<T>> temporary used by the
625        // default method, and lets None initialize only its discriminant.
626        let mut value = MU::<T>::uninit();
627        read_xdr_in_place(r, &mut value)?;
628        // SAFETY: read_xdr_in_place initialized the payload on success.
629        Ok(slot.write(Some(unsafe { value.assume_init() })))
630    }
631}
632
633#[cfg(feature = "alloc")]
634#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
635impl<'r, T> ReadXDR<'r> for xdr_common::Box<T>
636where
637    T: ReadXDR<'r>,
638{
639    #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
640    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
641        // For at most two machine words, moving the value is cheap. Decode
642        // before allocating so scalar reads need not depend on the heap
643        // destination, and a failed read needs no allocation or deallocation.
644        // This size check is constant for each T and disappears at compile time.
645        if core::mem::size_of::<T>() <= 2 * core::mem::size_of::<usize>() {
646            let mut value = MU::<T>::uninit();
647            read_xdr_in_place(r, &mut value)?;
648            // SAFETY: read_xdr_in_place initialized the value on success.
649            return Ok(Self::new(unsafe { value.assume_init() }));
650        }
651
652        let mut boxed = Self::new_uninit();
653        read_xdr_in_place(r, &mut *boxed)?;
654        // SAFETY: read_xdr_in_place returned Ok, so the value is initialized.
655        Ok(unsafe { boxed.assume_init() })
656    }
657}
658
659#[cfg(not(feature = "alloc"))]
660impl<'r, T> ReadXDR<'r> for xdr_common::Box<T>
661where
662    T: ReadXDR<'r>,
663{
664    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
665        Ok(Self::new(read_xdr(r)?))
666    }
667}
668
669/// Implements `ReadXDR` for a shared pointer (`Rc` or `Arc`) whose pointee
670/// is decoded the same way `Box<T>` is: small values are decoded on the
671/// stack and moved into a fresh allocation, larger ones are decoded straight
672/// into it. `ReadXDROwned` follows from the blanket impl whenever
673/// `T: ReadXDROwned`.
674#[cfg(feature = "alloc")]
675macro_rules! impl_read_xdr_shared_pointer {
676    ($ptr:ident) => {
677        impl<'r, T> ReadXDR<'r> for $ptr<T>
678        where
679            T: ReadXDR<'r>,
680        {
681            #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
682            fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
683                // Same size threshold as `Box<T>`: for at most two machine
684                // words, moving the value is cheap, and decoding before
685                // allocating means a failed read needs no allocation.
686                if core::mem::size_of::<T>() <= 2 * core::mem::size_of::<usize>() {
687                    let mut value = MU::<T>::uninit();
688                    read_xdr_in_place(r, &mut value)?;
689                    // SAFETY: read_xdr_in_place initialized the value on success.
690                    return Ok(Self::new(unsafe { value.assume_init() }));
691                }
692
693                let shared = Self::new_uninit();
694                // SAFETY: `shared` was just allocated and no other strong or
695                // weak pointer to it exists, so the slot cannot be aliased
696                // and writing through its pointer is sound. This is what
697                // `get_mut_unchecked` does, which is not stable yet; `get_mut`
698                // would add a uniqueness check (atomic for `Arc`) that is
699                // known to pass.
700                let slot = unsafe { &mut *$ptr::as_ptr(&shared).cast_mut() };
701                read_xdr_in_place(r, slot)?;
702                // SAFETY: read_xdr_in_place returned Ok, so the value is
703                // initialized. On error, dropping `shared` frees the
704                // allocation without dropping the uninitialized `T`.
705                Ok(unsafe { shared.assume_init() })
706            }
707        }
708    };
709}
710
711#[cfg(feature = "alloc")]
712#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
713const _: () = {
714    use alloc::rc::Rc;
715    impl_read_xdr_shared_pointer!(Rc);
716};
717
718// `alloc::sync` exists only on targets with pointer-sized atomics.
719#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
720#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
721const _: () = {
722    use alloc::sync::Arc;
723    impl_read_xdr_shared_pointer!(Arc);
724};
725
726impl<'r, T, E> ReadXDR<'r> for core::result::Result<T, E>
727where
728    T: ReadXDR<'r>,
729    E: ReadXDR<'r>,
730{
731    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
732        let d = r.read_i32()?;
733
734        match d {
735            0 => Ok(Result::Ok(read_xdr(r)?)),
736            1 => Ok(Result::Err(read_xdr(r)?)),
737            _ => Err(ReadError::bad_discriminator(d)),
738        }
739    }
740}
741
742impl<'r, T> ReadXDR<'r> for core::marker::PhantomData<T> {
743    fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
744        Ok(core::marker::PhantomData)
745    }
746}
747
748/// Decodes `count` elements directly into the spare capacity at the end of
749/// `vec`, which must already have room for them.
750///
751/// On error, the elements decoded so far in this call are dropped and `vec`
752/// keeps its previous length, so whatever it already held is dropped with
753/// it as usual.
754#[cfg(feature = "alloc")]
755#[inline]
756fn fill_spare<'r, R, T>(r: &mut R, vec: &mut alloc::vec::Vec<T>, count: usize) -> ReadResult<()>
757where
758    R: Reader<'r>,
759    T: ReadXDR<'r>,
760{
761    let slice = &mut vec.spare_capacity_mut()[..count];
762    let mut guard = PartialInitGuard {
763        slice,
764        initialized: 0,
765    };
766
767    for elt in guard.slice.iter_mut() {
768        read_xdr_in_place(r, elt)?;
769        guard.initialized += 1;
770    }
771
772    core::mem::forget(guard);
773
774    // SAFETY: all `count` elements of the spare capacity were initialized.
775    unsafe { vec.set_len(vec.len() + count) };
776    Ok(())
777}
778
779/// Decodes `len` elements into a new vector.
780///
781/// Capacity for up to [`MAX_PREALLOC_BYTES`] is reserved up front, since
782/// `len` comes from the wire and must not drive an unbounded allocation,
783/// and those elements are decoded straight into it. After that, grow the
784/// vector as needed and decode each batch into its spare capacity.
785#[cfg(feature = "alloc")]
786// Keep the reader local to the caller so its position updates and overflow
787// checks can be optimized across the element-decoding loop. The Vec/VecM
788// entry points must also inline for the same reason.
789#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
790fn read_vec<'r, R, T>(r: &mut R, len: usize) -> ReadResult<alloc::vec::Vec<T>>
791where
792    R: Reader<'r>,
793    T: ReadXDR<'r>,
794{
795    let cap = len.min(MAX_PREALLOC_BYTES / core::mem::size_of::<T>().max(1));
796    let mut vec = alloc::vec::Vec::with_capacity(cap);
797    fill_spare(r, &mut vec, cap)?;
798
799    while vec.len() < len {
800        vec.reserve(1);
801        let count = (len - vec.len()).min(vec.capacity() - vec.len());
802        fill_spare(r, &mut vec, count)?;
803    }
804
805    Ok(vec)
806}
807
808#[cfg(feature = "alloc")]
809#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
810const _: () = {
811    use alloc::vec::Vec;
812
813    impl<'r> ReadXDR<'r> for Vec<u8> {
814        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
815            let bytes: &[u8] = r.read_opaque_variable(u32::MAX)?;
816            let vec = Vec::from(bytes); // copy the slice
817            Ok(vec)
818        }
819    }
820
821    impl<'r, T> ReadXDR<'r> for Vec<T>
822    where
823        T: ReadXDR<'r>,
824    {
825        #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
826        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
827            let len = r.read_u32()? as usize;
828            read_vec(r, len)
829        }
830    }
831};
832
833#[cfg(feature = "alloc")]
834#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
835const _: () = {
836    use xdr_common::*;
837
838    use crate::ReadXDR;
839    use crate::serialize::reader::{ReadError, Reader};
840
841    use alloc::vec::Vec; // can use noalloc machinery in common_types to avoid this
842
843    impl<'r, const MAX: u32> ReadXDR<'r> for BytesM<MAX> {
844        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
845            let bytes = r.read_opaque_variable(MAX)?;
846            let vec = Vec::from(bytes);
847            Ok(Self(vec))
848        }
849    }
850
851    impl<'r, const MAX: u32> ReadXDR<'r> for StringM<MAX> {
852        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
853            let bytes = r.read_opaque_variable(MAX)?;
854            let vec = Vec::from(bytes);
855            Ok(Self(vec))
856        }
857    }
858
859    impl<'r, const MAX: u32, T> ReadXDR<'r> for VecM<T, MAX>
860    where
861        T: ReadXDR<'r>,
862    {
863        #[cfg_attr(not(target_arch = "riscv32"), inline(always))]
864        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
865            let len = r.read_u32()? as usize;
866            if len > MAX as usize {
867                return Err(ReadError::max_length_exceeded());
868            }
869
870            Ok(Self(read_vec(r, len)?))
871        }
872    }
873
874    // make VecM<u8> work like BytesM;
875    impl<'r, const MAX: u32> ReadXDR<'r> for VecM<u8, MAX> {
876        fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
877            let bytes = r.read_opaque_variable(MAX)?;
878            let vec = Vec::from(bytes);
879            Ok(Self(vec))
880        }
881    }
882};
883
884#[cfg(not(feature = "alloc"))]
885const _: () = {
886    use crate::ReadXDR;
887    use crate::serialize::reader::Reader;
888    use xdr_common::*;
889
890    impl<'r, const MAX: u32> ReadXDR<'r> for BytesM<MAX> {
891        fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
892            unimplemented!()
893        }
894    }
895
896    impl<'r, const MAX: u32> ReadXDR<'r> for StringM<MAX> {
897        fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
898            unimplemented!()
899        }
900    }
901
902    impl<'r, const MAX: u32, T> ReadXDR<'r> for VecM<T, MAX>
903    where
904        T: ReadXDR<'r> + 'static,
905    {
906        fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
907            unimplemented!()
908        }
909    }
910
911    // make VecM<u8> work like BytesM;
912    impl<'r, const MAX: u32> ReadXDR<'r> for VecM<u8, MAX> {
913        fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
914            unimplemented!()
915        }
916    }
917};