use crate::mu;
use crate::serialize::reader::*;
use crate::valid_u32::*;
use core::convert::Infallible;
use core::mem::MaybeUninit as MU;
#[cfg(feature = "alloc")]
use xdr_common::MAX_PREALLOC_BYTES;
struct PartialInitGuard<'a, T> {
slice: &'a mut [MU<T>],
initialized: usize,
}
impl<T> Drop for PartialInitGuard<'_, T> {
fn drop(&mut self) {
for elt in self.slice.iter_mut().take(self.initialized) {
unsafe {
elt.assume_init_drop();
}
}
}
}
#[inline]
pub fn read_xdr<'r, R, T>(r: &mut R) -> ReadResult<T>
where
R: Reader<'r>,
T: ReadXDR<'r>,
{
<T as ReadXDR>::read_xdr(r)
}
pub trait ReadXDR<'r>: Sized {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self>;
#[inline]
fn read_xdr_in_place<'s, R: Reader<'r>>(
r: &mut R,
slot: Slot<'s, Self>,
) -> ReadResult<Init<'s, Self>> {
Ok(slot.write(Self::read_xdr(r)?))
}
}
#[repr(transparent)]
pub struct Slot<'s, T> {
slot: &'s mut MU<T>,
}
impl<'s, T> Slot<'s, T> {
#[inline]
pub unsafe fn from_raw(ptr: *mut T) -> Self {
Self {
slot: unsafe { &mut *ptr.cast::<MU<T>>() },
}
}
#[inline]
pub fn write(self, value: T) -> Init<'s, T> {
Init {
value: self.slot.write(value),
}
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.slot.as_mut_ptr()
}
#[inline]
pub fn as_uninit_mut(&mut self) -> &mut MU<T> {
self.slot
}
#[inline]
pub unsafe fn assume_init(self) -> Init<'s, T> {
Init {
value: unsafe { self.slot.assume_init_mut() },
}
}
}
#[repr(transparent)]
pub struct Init<'s, T> {
value: &'s mut T,
}
impl<'s, T> Init<'s, T> {
#[inline]
pub fn into_mut(self) -> &'s mut T {
self.value
}
}
#[inline]
pub fn read_xdr_in_place<'r, 's, R, T>(r: &mut R, slot: &'s mut MU<T>) -> ReadResult<&'s mut T>
where
R: Reader<'r>,
T: ReadXDR<'r>,
{
Ok(T::read_xdr_in_place(r, Slot { slot })?.into_mut())
}
#[doc(hidden)]
pub mod in_place {
use super::*;
pub struct FieldGuard<T>(*mut T);
impl<T> Drop for FieldGuard<T> {
#[inline]
fn drop(&mut self) {
unsafe { core::ptr::drop_in_place(self.0) }
}
}
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
pub unsafe fn read_field<'r, R, F>(r: &mut R, field: *mut F) -> ReadResult<FieldGuard<F>>
where
R: Reader<'r>,
F: ReadXDR<'r>,
{
let slot = unsafe { Slot::from_raw(field) };
F::read_xdr_in_place(r, slot)?;
Ok(FieldGuard(field))
}
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
pub unsafe fn write_field<F>(field: *mut F, value: F) -> FieldGuard<F> {
unsafe { field.write(value) };
FieldGuard(field)
}
}
pub trait ReadXDROwned: for<'r> ReadXDR<'r> {}
impl<T> ReadXDROwned for T where T: for<'r> ReadXDR<'r> {}
macro_rules! construct_int_impls {
{ $( $read_method:ident for $int_ty:ty ),* $(,)? } => { $(
impl<'r> ReadXDR<'r> for $int_ty {
#[inline]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<$int_ty> {
r.$read_method()
}
}
)* };
}
construct_int_impls! {
read_i64 for i64,
read_i32 for i32,
read_i16 for i16,
read_u64 for u64,
read_u32 for u32,
read_u16 for u16,
read_bool for bool,
read_f32 for f32,
read_f64 for f64,
}
impl<'r, T, const N: usize> ReadXDR<'r> for [T; N]
where
T: ReadXDR<'r>,
{
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let () = ValidU32::<N>::OK;
let mut arr: [MU<T>; N] = [const { MU::uninit() }; N];
let mut guard = PartialInitGuard {
slice: &mut arr,
initialized: 0,
};
for elt in guard.slice.iter_mut() {
elt.write(read_xdr(r)?);
guard.initialized += 1;
}
core::mem::forget(guard);
let arr = unsafe { mu::array_assume_init(arr) };
Ok(arr)
}
fn read_xdr_in_place<'s, R: Reader<'r>>(
r: &mut R,
mut slot: Slot<'s, Self>,
) -> ReadResult<Init<'s, Self>> {
let () = ValidU32::<N>::OK;
let elems = unsafe { &mut *slot.as_mut_ptr().cast::<[MU<T>; N]>() };
let mut guard = PartialInitGuard {
slice: elems,
initialized: 0,
};
for elt in guard.slice.iter_mut() {
read_xdr_in_place(r, elt)?;
guard.initialized += 1;
}
core::mem::forget(guard);
Ok(unsafe { slot.assume_init() })
}
}
impl<'r: 'a, 'a> ReadXDR<'r> for &'a [u8] {
#[inline]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes: &'r [u8] = r.read_opaque_variable(u32::MAX)?;
Ok(bytes)
}
}
impl<'r: 'a, 'a, const N: usize> ReadXDR<'r> for &'a [u8; N] {
#[inline]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let () = ValidU32::<N>::OK;
let len = N as u32;
let bytes: &'r [u8; N] = unsafe {
r.read_opaque_fixed(len as usize)?
.try_into()
.unwrap_unchecked()
};
Ok(bytes)
}
}
impl<'r, const N: usize> ReadXDR<'r> for [u8; N] {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let () = ValidU32::<N>::OK;
let mut arr: [MU<u8>; N] = [MU::uninit(); N];
r.read_opaque_fixed_into(&mut arr, N as u32)?;
let arr = unsafe { mu::array_assume_init(arr) };
Ok(arr)
}
fn read_xdr_in_place<'s, R: Reader<'r>>(
r: &mut R,
mut slot: Slot<'s, Self>,
) -> ReadResult<Init<'s, Self>> {
let () = ValidU32::<N>::OK;
let bytes = unsafe { &mut *slot.as_mut_ptr().cast::<[MU<u8>; N]>() };
r.read_opaque_fixed_into(bytes, N as u32)?;
Ok(unsafe { slot.assume_init() })
}
}
impl<'r: 'a, 'a> ReadXDR<'r> for &'a str {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes: &'r [u8] = r.read_opaque_variable(u32::MAX)?;
let s: &'r str = str::from_utf8(bytes).map_err(|_| ReadError::bad_utf8())?;
Ok(s)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'r> ReadXDR<'r> for alloc::string::String {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes = r.read_opaque_variable(u32::MAX)?;
let s = str::from_utf8(bytes).map_err(|_| ReadError::bad_utf8())?;
Ok(alloc::string::String::from(s))
}
}
impl<'r> ReadXDR<'r> for () {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
Ok(())
}
}
impl<'r> ReadXDR<'r> for Infallible {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
unreachable!()
}
}
macro_rules! read_tuple {
{ $( $index:tt : $t:ident ),+ $(,)? } => {
impl<'r, $($t),+> ReadXDR<'r> for ($($t,)+)
where
$( $t: ReadXDR<'r>, )+
{
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
Ok(($(read_xdr::<R, $t>(r)?,)+))
}
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr_in_place<'s, R: Reader<'r>>(
r: &mut R,
mut slot: Slot<'s, Self>,
) -> ReadResult<Init<'s, Self>> {
let base = slot.as_mut_ptr();
let guards = ($(unsafe {
in_place::read_field(r, &raw mut (*base).$index)?
},)+);
core::mem::forget(guards);
Ok(unsafe { slot.assume_init() })
}
}
};
}
read_tuple!(0: T1);
read_tuple!(0: T1, 1: T2);
read_tuple!(0: T1, 1: T2, 2: T3);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10);
read_tuple!(0: T1, 1: T2, 2: T3, 3: T4, 4: T5, 5: T6, 6: T7, 7: T8, 8: T9, 9: T10, 10: T11);
read_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);
read_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);
read_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);
read_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);
read_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);
impl<'r, T> ReadXDR<'r> for Option<T>
where
T: ReadXDR<'r>,
{
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let is_present = r.read_bool()?;
if is_present {
Ok(Some(read_xdr(r)?))
} else {
Ok(None)
}
}
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr_in_place<'s, R: Reader<'r>>(
r: &mut R,
slot: Slot<'s, Self>,
) -> ReadResult<Init<'s, Self>> {
if !r.read_bool()? {
return Ok(slot.write(None));
}
let mut value = MU::<T>::uninit();
read_xdr_in_place(r, &mut value)?;
Ok(slot.write(Some(unsafe { value.assume_init() })))
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<'r, T> ReadXDR<'r> for xdr_common::Box<T>
where
T: ReadXDR<'r>,
{
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
if core::mem::size_of::<T>() <= 2 * core::mem::size_of::<usize>() {
let mut value = MU::<T>::uninit();
read_xdr_in_place(r, &mut value)?;
return Ok(Self::new(unsafe { value.assume_init() }));
}
let mut boxed = Self::new_uninit();
read_xdr_in_place(r, &mut *boxed)?;
Ok(unsafe { boxed.assume_init() })
}
}
#[cfg(not(feature = "alloc"))]
impl<'r, T> ReadXDR<'r> for xdr_common::Box<T>
where
T: ReadXDR<'r>,
{
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
Ok(Self::new(read_xdr(r)?))
}
}
#[cfg(feature = "alloc")]
macro_rules! impl_read_xdr_shared_pointer {
($ptr:ident) => {
impl<'r, T> ReadXDR<'r> for $ptr<T>
where
T: ReadXDR<'r>,
{
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
if core::mem::size_of::<T>() <= 2 * core::mem::size_of::<usize>() {
let mut value = MU::<T>::uninit();
read_xdr_in_place(r, &mut value)?;
return Ok(Self::new(unsafe { value.assume_init() }));
}
let shared = Self::new_uninit();
let slot = unsafe { &mut *$ptr::as_ptr(&shared).cast_mut() };
read_xdr_in_place(r, slot)?;
Ok(unsafe { shared.assume_init() })
}
}
};
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
const _: () = {
use alloc::rc::Rc;
impl_read_xdr_shared_pointer!(Rc);
};
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
const _: () = {
use alloc::sync::Arc;
impl_read_xdr_shared_pointer!(Arc);
};
impl<'r, T, E> ReadXDR<'r> for core::result::Result<T, E>
where
T: ReadXDR<'r>,
E: ReadXDR<'r>,
{
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let d = r.read_i32()?;
match d {
0 => Ok(Result::Ok(read_xdr(r)?)),
1 => Ok(Result::Err(read_xdr(r)?)),
_ => Err(ReadError::bad_discriminator(d)),
}
}
}
impl<'r, T> ReadXDR<'r> for core::marker::PhantomData<T> {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
Ok(core::marker::PhantomData)
}
}
#[cfg(feature = "alloc")]
#[inline]
fn fill_spare<'r, R, T>(r: &mut R, vec: &mut alloc::vec::Vec<T>, count: usize) -> ReadResult<()>
where
R: Reader<'r>,
T: ReadXDR<'r>,
{
let slice = &mut vec.spare_capacity_mut()[..count];
let mut guard = PartialInitGuard {
slice,
initialized: 0,
};
for elt in guard.slice.iter_mut() {
read_xdr_in_place(r, elt)?;
guard.initialized += 1;
}
core::mem::forget(guard);
unsafe { vec.set_len(vec.len() + count) };
Ok(())
}
#[cfg(feature = "alloc")]
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_vec<'r, R, T>(r: &mut R, len: usize) -> ReadResult<alloc::vec::Vec<T>>
where
R: Reader<'r>,
T: ReadXDR<'r>,
{
let cap = len.min(MAX_PREALLOC_BYTES / core::mem::size_of::<T>().max(1));
let mut vec = alloc::vec::Vec::with_capacity(cap);
fill_spare(r, &mut vec, cap)?;
while vec.len() < len {
vec.reserve(1);
let count = (len - vec.len()).min(vec.capacity() - vec.len());
fill_spare(r, &mut vec, count)?;
}
Ok(vec)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
const _: () = {
use alloc::vec::Vec;
impl<'r> ReadXDR<'r> for Vec<u8> {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes: &[u8] = r.read_opaque_variable(u32::MAX)?;
let vec = Vec::from(bytes); Ok(vec)
}
}
impl<'r, T> ReadXDR<'r> for Vec<T>
where
T: ReadXDR<'r>,
{
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let len = r.read_u32()? as usize;
read_vec(r, len)
}
}
};
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
const _: () = {
use xdr_common::*;
use crate::ReadXDR;
use crate::serialize::reader::{ReadError, Reader};
use alloc::vec::Vec;
impl<'r, const MAX: u32> ReadXDR<'r> for BytesM<MAX> {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes = r.read_opaque_variable(MAX)?;
let vec = Vec::from(bytes);
Ok(Self(vec))
}
}
impl<'r, const MAX: u32> ReadXDR<'r> for StringM<MAX> {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes = r.read_opaque_variable(MAX)?;
let vec = Vec::from(bytes);
Ok(Self(vec))
}
}
impl<'r, const MAX: u32, T> ReadXDR<'r> for VecM<T, MAX>
where
T: ReadXDR<'r>,
{
#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let len = r.read_u32()? as usize;
if len > MAX as usize {
return Err(ReadError::max_length_exceeded());
}
Ok(Self(read_vec(r, len)?))
}
}
impl<'r, const MAX: u32> ReadXDR<'r> for VecM<u8, MAX> {
fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
let bytes = r.read_opaque_variable(MAX)?;
let vec = Vec::from(bytes);
Ok(Self(vec))
}
}
};
#[cfg(not(feature = "alloc"))]
const _: () = {
use crate::ReadXDR;
use crate::serialize::reader::Reader;
use xdr_common::*;
impl<'r, const MAX: u32> ReadXDR<'r> for BytesM<MAX> {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
unimplemented!()
}
}
impl<'r, const MAX: u32> ReadXDR<'r> for StringM<MAX> {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
unimplemented!()
}
}
impl<'r, const MAX: u32, T> ReadXDR<'r> for VecM<T, MAX>
where
T: ReadXDR<'r> + 'static,
{
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
unimplemented!()
}
}
impl<'r, const MAX: u32> ReadXDR<'r> for VecM<u8, MAX> {
fn read_xdr<R: Reader<'r>>(_r: &mut R) -> ReadResult<Self> {
unimplemented!()
}
}
};