Skip to main content

xdrs/txs/
utils.rs

1//! Convenient interfaces to TXS serialization.
2//!
3//! This module provides high-level functions for encoding and decoding XDR data
4//! using the TXS (Traditional XDR Serialization) format.
5
6use crate::txs::buf_reader::*;
7use crate::txs::into_buf_writer::*;
8use crate::txs::unchecked_buf_writer::*;
9use crate::*;
10use core::mem::MaybeUninit as MU;
11
12/// Decodes TXS-encoded XDR data from a byte slice.
13///
14/// This function reads the entire buffer and deserializes a value of type `T`.
15/// It returns an error if there are any remaining bytes after decoding.
16///
17/// # Example
18///
19/// ```rust
20/// use xdrs::txs;
21///
22/// let data = [0u8; 4]; // valid TXS encoding for the unsigned integer 0
23/// let value: u32 = txs::decode(&data)?;
24/// # Ok::<(), xdrs::ReadError>(())
25/// ```
26// Expose the reader's initial position and aggregate return value to callers.
27#[cfg_attr(not(target_arch = "riscv32"), inline(always))]
28pub fn decode<'r, 'a: 'r, T>(buf: &'a [u8]) -> ReadResult<T>
29where
30    T: ReadXDR<'r>,
31{
32    let mut reader = BufReader::new(buf);
33
34    let value = read_xdr(&mut reader)?;
35
36    debug_assert!(reader.position() <= buf.len());
37
38    let remaining = buf.len() - reader.position();
39    if remaining > 0 {
40        let remaining = remaining as u64;
41        return Err(ReadError::source_remaining(remaining));
42    }
43
44    Ok(value)
45}
46
47/// Encodes a value as TXS-encoded XDR data into a pre-allocated buffer.
48///
49/// This function serializes the value into the provided buffer and returns the
50/// number of bytes written. Returns `Err(WriteError::SpaceExhausted)` if the
51/// buffer is not large enough to hold the serialized data.
52///
53/// # Example
54///
55/// ```rust
56/// use xdrs::txs;
57/// use core::mem::MaybeUninit;
58///
59/// let value: u32 = 42;
60///
61/// let mut buf = [MaybeUninit::uninit(); 16];
62///
63/// let written = txs::encode_into(&value, &mut buf)?;
64/// # Ok::<(), xdrs::WriteError>(())
65/// ```
66pub fn encode_into<T>(value: &T, buf: &mut [MU<u8>]) -> WriteResult<usize>
67where
68    T: WriteXDR + ?Sized,
69{
70    let mut writer = IntoBufWriter::new(buf);
71
72    value.write_xdr(&mut writer)?;
73
74    Ok(writer.written())
75}
76
77/// Encodes a value as TXS-encoded XDR data into a pre-allocated buffer,
78/// without runtime checks.
79///
80/// This is the infallible, unsafe counterpart to [`encode_into`]: no bounds
81/// checking is performed and no error can be returned, minimizing code size
82/// on constrained targets. Returns the number of bytes written.
83///
84/// # Safety
85///
86/// - `buf.len()` must be at least the encoded size of `value`. With
87///   `#[derive(ConstXDRSize)]`, `<T as txs::ConstMaxSize>::MAX_SIZE` (worst
88///   case over all values) — or, with `#[derive(ConstWriteXDR)]`,
89///   `const_txs_size()` (exact for this value) — provide suitable sizes.
90/// - `value` must respect all declared XDR bounds (e.g. a `VecM<T, MAX>`
91///   must not be longer than `MAX`), since a violation would make the
92///   encoding exceed any precomputed size bound. This includes the implicit
93///   `u32::MAX` upper limit on variable-length arrays and strings: the
94///   checked path returns [`WriteError::InvalidArrayLength`] for lengths
95///   exceeding `u32::MAX`; the unchecked path only `debug_assert!`s this.
96///
97/// Violations are caught by `debug_assert!` in debug builds; in release
98/// builds they are undefined behavior.
99///
100/// # Example
101///
102/// ```rust
103/// use xdrs::txs;
104/// use core::mem::MaybeUninit;
105///
106/// let value: u32 = 42;
107///
108/// let mut buf = [MaybeUninit::uninit(); 4];
109///
110/// // SAFETY: a u32 always encodes to exactly 4 TXS bytes.
111/// let written = unsafe { txs::encode_into_unchecked(&value, &mut buf) };
112/// assert_eq!(written, 4);
113/// ```
114pub unsafe fn encode_into_unchecked<T>(value: &T, buf: &mut [MU<u8>]) -> usize
115where
116    T: WriteXDR + ?Sized,
117{
118    let mut writer = UncheckedBufWriter::new(buf);
119
120    // SAFETY: the caller guarantees buf can hold the encoded form of value
121    // and that value respects its declared bounds.
122    unsafe { value.write_xdr_unchecked(&mut writer) };
123
124    writer.written()
125}
126
127#[cfg(feature = "alloc")]
128mod utils_alloc {
129    use crate::txs::buf_writer::*;
130    use crate::*;
131    use alloc::vec::Vec;
132
133    /// Encodes a value as TXS-encoded XDR data, returning an owned vector.
134    ///
135    /// This function serializes the value and returns a `Vec<u8>` containing
136    /// the serialized data.
137    ///
138    /// *Requires feature `alloc`.*
139    ///
140    /// # Example
141    ///
142    /// ```rust
143    /// use xdrs::txs;
144    ///
145    /// let value: u32 = 42;
146    /// let encoded = txs::encode(&value)?;
147    /// # Ok::<(), xdrs::WriteError>(())
148    /// ```
149    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
150    pub fn encode<T>(value: &T) -> WriteResult<Vec<u8>>
151    where
152        T: WriteXDR + ?Sized,
153    {
154        let mut writer = BufWriter::new();
155
156        value.write_xdr(&mut writer)?;
157
158        Ok(writer.into())
159    }
160}
161
162#[cfg(feature = "alloc")]
163pub use utils_alloc::*;