Skip to main content

reliakit_codec/
decode.rs

1//! Decoding traits and sources.
2
3use crate::CodecError;
4
5/// Source for canonical encoded bytes.
6pub trait DecodeSource {
7    /// Reads exactly enough bytes to fill `out` or returns an error.
8    fn read_exact(&mut self, out: &mut [u8]) -> Result<(), CodecError>;
9
10    /// Returns the unread byte count when the source can know it cheaply.
11    ///
12    /// Streaming sources may return `None`. Slice-backed sources return
13    /// `Some(_)`, allowing decoders to reject impossible length prefixes before
14    /// allocating.
15    fn remaining_len(&self) -> Option<usize> {
16        None
17    }
18}
19
20/// Trait for strict canonical binary decoding.
21pub trait CanonicalDecode: Sized {
22    /// Decodes `Self` from `reader` using the crate's canonical binary format.
23    fn decode<R: DecodeSource + ?Sized>(reader: &mut R) -> Result<Self, CodecError>;
24}
25
26/// Decode source backed by an immutable byte slice.
27#[derive(Debug, Clone)]
28pub struct SliceReader<'a> {
29    input: &'a [u8],
30    offset: usize,
31}
32
33impl<'a> SliceReader<'a> {
34    /// Creates a new reader over `input`.
35    pub const fn new(input: &'a [u8]) -> Self {
36        Self { input, offset: 0 }
37    }
38
39    /// Returns the number of unread bytes.
40    pub const fn remaining(&self) -> usize {
41        self.input.len() - self.offset
42    }
43
44    /// Returns `true` if all bytes have been consumed.
45    pub const fn is_empty(&self) -> bool {
46        self.remaining() == 0
47    }
48}
49
50impl DecodeSource for SliceReader<'_> {
51    fn read_exact(&mut self, out: &mut [u8]) -> Result<(), CodecError> {
52        let end = self
53            .offset
54            .checked_add(out.len())
55            .ok_or_else(|| CodecError::length_overflow("read offset overflow"))?;
56        let bytes = self
57            .input
58            .get(self.offset..end)
59            .ok_or_else(CodecError::unexpected_eof)?;
60        out.copy_from_slice(bytes);
61        self.offset = end;
62        Ok(())
63    }
64
65    fn remaining_len(&self) -> Option<usize> {
66        Some(self.remaining())
67    }
68}