Skip to main content

xdrs/
heapless.rs

1use crate::cxs;
2use crate::read_xdr::ReadXDR;
3use crate::serialize::reader::{ReadError, ReadResult, Reader};
4use crate::serialize::writer::{WriteResult, Writer};
5use crate::serialize::writer_unchecked::WriterUnchecked;
6use crate::txs;
7use crate::valid_u32::*;
8use crate::write_xdr::WriteXDR;
9
10use heapless::String;
11use heapless::Vec;
12
13impl<'r, const N: usize> ReadXDR<'r> for Vec<u8, N> {
14    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
15        let () = ValidU32::<N>::OK;
16
17        let bytes = r.read_opaque_variable(N as u32)?;
18
19        let mut s = Vec::new();
20        s.extend_from_slice(bytes)
21            .map_err(|_| ReadError::max_length_exceeded())?;
22
23        Ok(s)
24    }
25}
26
27impl<const N: usize> WriteXDR for Vec<u8, N> {
28    fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
29        let () = ValidU32::<N>::OK;
30
31        w.write_opaque_variable(self.as_slice())
32    }
33
34    unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
35        let () = ValidU32::<N>::OK;
36
37        // SAFETY: a heapless Vec<u8, N> never exceeds N <= u32::MAX
38        // elements; the caller guarantees buffer space.
39        unsafe { w.write_opaque_variable(self.as_slice()) }
40    }
41}
42
43impl<'r, T, const N: usize> ReadXDR<'r> for Vec<T, N>
44where
45    T: ReadXDR<'r>,
46{
47    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
48        let () = ValidU32::<N>::OK;
49
50        let len = r.read_u32()? as usize;
51        if len > N {
52            return Err(ReadError::max_length_exceeded());
53        }
54
55        let mut vec = Vec::new();
56        for _ in 0..len {
57            vec.push(<T as ReadXDR>::read_xdr(r)?)
58                .map_err(|_| ReadError::max_length_exceeded())?;
59        }
60
61        Ok(vec)
62    }
63}
64
65impl<T, const N: usize> WriteXDR for Vec<T, N>
66where
67    T: WriteXDR,
68{
69    fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
70        let () = ValidU32::<N>::OK;
71
72        w.write_u32(self.len() as u32)?;
73        for elt in self {
74            elt.write_xdr(w)?;
75        }
76        Ok(())
77    }
78
79    unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
80        let () = ValidU32::<N>::OK;
81
82        // SAFETY: the caller guarantees space for the length prefix and
83        // every element.
84        unsafe {
85            w.write_u32(self.len() as u32);
86            for elt in self {
87                elt.write_xdr_unchecked(w);
88            }
89        }
90    }
91}
92
93impl<'r, const N: usize> ReadXDR<'r> for String<N> {
94    fn read_xdr<R: Reader<'r>>(r: &mut R) -> ReadResult<Self> {
95        let () = ValidU32::<N>::OK;
96
97        let bytes = r.read_opaque_variable(N as u32)?;
98        let slice = str::from_utf8(bytes).map_err(|_| ReadError::bad_utf8())?;
99
100        let mut s = String::new();
101        s.push_str(slice)
102            .map_err(|_| ReadError::max_length_exceeded())?;
103
104        Ok(s)
105    }
106}
107
108impl<const N: usize> WriteXDR for String<N> {
109    fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
110        let () = ValidU32::<N>::OK;
111
112        w.write_opaque_variable(self.as_bytes())
113    }
114
115    unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
116        let () = ValidU32::<N>::OK;
117
118        // SAFETY: a heapless String<N> never exceeds N <= u32::MAX bytes;
119        // the caller guarantees buffer space.
120        unsafe { w.write_opaque_variable(self.as_bytes()) }
121    }
122}
123
124// -- Worst-case size bounds --
125//
126// heapless containers store their elements inline (no heap indirection), so
127// unlike `VecM<T, MAX>` a recursive type through them is impossible by
128// construction, and naming the element's bound cannot form a const-eval
129// cycle — the same argument as arrays. Bounds are therefore exact.
130//
131// A capacity `N` that exceeds `u32::MAX` cannot be length-prefixed, so it
132// bounds to `None` (such values can never be fully encoded), mirroring
133// `max_size_opaque_fixed`.
134//
135// As with the read/write impls above, the `Vec<u8, N>` and `Vec<T, N>` impl
136// pairs are disjoint because `u8` does not implement the trait.
137
138impl<const N: usize> cxs::ConstMaxSize for Vec<u8, N> {
139    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
140        None
141    } else {
142        cxs::const_writer::max_size_opaque_variable(N as u32)
143    };
144}
145
146impl<T: cxs::ConstMaxSize, const N: usize> cxs::ConstMaxSize for Vec<T, N> {
147    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
148        None
149    } else {
150        cxs::const_writer::max_size_add(
151            Some(cxs::const_writer::size_u32(N as u32)),
152            cxs::const_writer::max_size_array(N, T::MAX_SIZE),
153        )
154    };
155}
156
157impl<const N: usize> cxs::ConstMaxSize for String<N> {
158    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
159        None
160    } else {
161        cxs::const_writer::max_size_opaque_variable(N as u32)
162    };
163}
164
165impl<const N: usize> txs::ConstMaxSize for Vec<u8, N> {
166    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
167        None
168    } else {
169        txs::const_writer::max_size_opaque_variable(N as u32)
170    };
171}
172
173impl<T: txs::ConstMaxSize, const N: usize> txs::ConstMaxSize for Vec<T, N> {
174    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
175        None
176    } else {
177        txs::const_writer::max_size_add(
178            Some(txs::const_writer::size_u32(N as u32)),
179            txs::const_writer::max_size_array(N, T::MAX_SIZE),
180        )
181    };
182}
183
184impl<const N: usize> txs::ConstMaxSize for String<N> {
185    const MAX_SIZE: Option<usize> = if N > u32::MAX as usize {
186        None
187    } else {
188        txs::const_writer::max_size_opaque_variable(N as u32)
189    };
190}