1#[cfg(feature = "alloc")]
12use alloc::vec::Vec;
13
14use core::mem::MaybeUninit as MU;
15
16pub unsafe trait Reader<'r>: Sized {
31 fn read_i64(&mut self) -> ReadResult<i64>;
33
34 fn read_i32(&mut self) -> ReadResult<i32>;
36
37 fn read_i16(&mut self) -> ReadResult<i16>;
39
40 fn read_u64(&mut self) -> ReadResult<u64>;
42
43 fn read_u32(&mut self) -> ReadResult<u32>;
45
46 fn read_u16(&mut self) -> ReadResult<u16>;
48
49 fn read_f32(&mut self) -> ReadResult<f32>;
51
52 fn read_f64(&mut self) -> ReadResult<f64>;
54
55 fn read_opaque_fixed(&mut self, len: usize) -> ReadResult<&'r [u8]>;
60
61 fn read_opaque_variable(&mut self, max: u32) -> ReadResult<&'r [u8]>;
63
64 fn read_bool(&mut self) -> ReadResult<bool> {
66 match self.read_i32()? {
67 0 => Ok(false),
68 1 => Ok(true),
69 _ => Err(ReadError::bad_bool()),
70 }
71 }
72
73 fn read_opaque_fixed_into<'a>(
79 &mut self,
80 dst: &'a mut [MU<u8>],
81 len: u32,
82 ) -> ReadResult<&'a mut [u8]> {
83 debug_assert_eq!(dst.len(), len as usize);
84
85 const _: () = assert!(core::mem::size_of::<usize>() >= core::mem::size_of::<u32>());
86
87 let data = self.read_opaque_fixed(len as usize)?;
88
89 let initialized = dst.write_copy_of_slice(data);
92
93 Ok(initialized)
94 }
95
96 fn read_opaque_variable_into<'a>(
102 &mut self,
103 dst: &'a mut [MU<u8>],
104 max: u32,
105 ) -> ReadResult<&'a mut [u8]> {
106 debug_assert!(dst.len() >= max as usize);
107
108 let len = self.read_u32()?;
109
110 if len > max {
111 return Err(ReadError::max_length_exceeded());
112 }
113
114 self.read_opaque_fixed_into(&mut dst[..len as usize], len)
116 }
117
118 #[cfg(feature = "alloc")]
122 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
123 fn read_opaque_fixed_owned(&mut self, len: u32) -> ReadResult<Vec<u8>> {
124 let bytes = self.read_opaque_fixed(len as usize)?;
125 let buf = Vec::from(bytes); Ok(buf)
127 }
128
129 #[cfg(feature = "alloc")]
133 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
134 fn read_opaque_variable_owned(&mut self, max: u32) -> ReadResult<Vec<u8>> {
135 let bytes = self.read_opaque_variable(max)?;
136 let buf = Vec::from(bytes); Ok(buf)
138 }
139}
140
141pub type ReadResult<T> = core::result::Result<T, ReadError>;
143
144#[cfg(feature = "detailed-errors")]
146#[derive(Copy, Clone, Debug)]
147pub enum ReadError {
148 SourceEmpty {
150 requested: usize,
152 remaining: usize,
154 },
155
156 SourceRemaining {
158 remaining: u64,
160 },
161
162 InvalidHeaderByte {
165 h: u8,
167 },
168
169 IntegerOutOfRange,
171
172 BadBool,
174
175 BadDiscriminator(i32),
177
178 MaxLengthExceeded,
181
182 NonZeroPadding,
185
186 BadUTF8,
188
189 NotMinimalEncoding,
192}
193
194#[cfg(not(feature = "detailed-errors"))]
200#[derive(Copy, Clone, Debug)]
201pub struct ReadError;
202
203impl ReadError {
204 #[doc(hidden)]
205 #[inline]
206 pub fn source_empty(requested: usize, remaining: usize) -> Self {
207 #[cfg(feature = "detailed-errors")]
208 {
209 Self::SourceEmpty {
210 requested,
211 remaining,
212 }
213 }
214 #[cfg(not(feature = "detailed-errors"))]
215 {
216 let _ = (requested, remaining);
217 Self
218 }
219 }
220
221 #[doc(hidden)]
222 #[inline]
223 pub fn source_remaining(remaining: u64) -> Self {
224 #[cfg(feature = "detailed-errors")]
225 {
226 Self::SourceRemaining { remaining }
227 }
228 #[cfg(not(feature = "detailed-errors"))]
229 {
230 let _ = remaining;
231 Self
232 }
233 }
234
235 #[doc(hidden)]
236 #[inline]
237 pub fn invalid_header_byte(h: u8) -> Self {
238 #[cfg(feature = "detailed-errors")]
239 {
240 Self::InvalidHeaderByte { h }
241 }
242 #[cfg(not(feature = "detailed-errors"))]
243 {
244 let _ = h;
245 Self
246 }
247 }
248
249 #[doc(hidden)]
250 #[inline]
251 pub fn integer_out_of_range() -> Self {
252 #[cfg(feature = "detailed-errors")]
253 {
254 Self::IntegerOutOfRange
255 }
256 #[cfg(not(feature = "detailed-errors"))]
257 {
258 Self
259 }
260 }
261
262 #[doc(hidden)]
263 #[inline]
264 pub fn bad_bool() -> Self {
265 #[cfg(feature = "detailed-errors")]
266 {
267 Self::BadBool
268 }
269 #[cfg(not(feature = "detailed-errors"))]
270 {
271 Self
272 }
273 }
274
275 #[doc(hidden)]
276 #[inline]
277 pub fn bad_discriminator(discriminant: i32) -> Self {
278 #[cfg(feature = "detailed-errors")]
279 {
280 Self::BadDiscriminator(discriminant)
281 }
282 #[cfg(not(feature = "detailed-errors"))]
283 {
284 let _ = discriminant;
285 Self
286 }
287 }
288
289 #[doc(hidden)]
290 #[inline]
291 pub fn max_length_exceeded() -> Self {
292 #[cfg(feature = "detailed-errors")]
293 {
294 Self::MaxLengthExceeded
295 }
296 #[cfg(not(feature = "detailed-errors"))]
297 {
298 Self
299 }
300 }
301
302 #[doc(hidden)]
303 #[inline]
304 pub fn non_zero_padding() -> Self {
305 #[cfg(feature = "detailed-errors")]
306 {
307 Self::NonZeroPadding
308 }
309 #[cfg(not(feature = "detailed-errors"))]
310 {
311 Self
312 }
313 }
314
315 #[doc(hidden)]
316 #[inline]
317 pub fn bad_utf8() -> Self {
318 #[cfg(feature = "detailed-errors")]
319 {
320 Self::BadUTF8
321 }
322 #[cfg(not(feature = "detailed-errors"))]
323 {
324 Self
325 }
326 }
327
328 #[doc(hidden)]
329 #[inline]
330 pub fn not_minimal_encoding() -> Self {
331 #[cfg(feature = "detailed-errors")]
332 {
333 Self::NotMinimalEncoding
334 }
335 #[cfg(not(feature = "detailed-errors"))]
336 {
337 Self
338 }
339 }
340}
341
342#[cfg(feature = "detailed-errors")]
343impl core::fmt::Display for ReadError {
344 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
345 match self {
346 ReadError::SourceEmpty {
347 requested,
348 remaining,
349 } => write!(
350 f,
351 "unexpected end of input (requested: {requested}, remaining: {remaining})"
352 ),
353 ReadError::SourceRemaining { remaining } => {
354 write!(f, "input remaining after decoding: {remaining} bytes")
355 }
356 ReadError::InvalidHeaderByte { h } => write!(f, "invalid header byte: 0x{h:02x}"),
357 ReadError::IntegerOutOfRange => write!(f, "decoded integer out of range"),
358 ReadError::BadBool => write!(f, "bad bool value"),
359 ReadError::BadDiscriminator(d) => write!(f, "unexpected discriminator value: {d}"),
360 ReadError::MaxLengthExceeded => write!(f, "length exceeds array maximum"),
361 ReadError::NonZeroPadding => write!(f, "non-zero XDR padding"),
362 ReadError::BadUTF8 => write!(f, "bad UTF8"),
363 ReadError::NotMinimalEncoding => write!(f, "not the minimal-size encoding"),
364 }
365 }
366}
367
368#[cfg(not(feature = "detailed-errors"))]
369impl core::fmt::Display for ReadError {
370 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
371 f.write_str("XDR decoding failed")
372 }
373}
374
375impl core::error::Error for ReadError {}