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};