core_json/
io.rs

1//! IO primitives around bytes.
2
3use core::{marker::PhantomData, fmt::Debug};
4
5/// An item which is like a `&[u8]`.
6///
7/// This should be a reference to a buffer for which references are cheap to work with.
8#[allow(clippy::len_without_is_empty)]
9pub trait BytesLike<'bytes>: Sized + Debug {
10  /// The type for errors when interacting with these bytes.
11  type Error: Sized + Copy + Debug;
12
13  /// The type representing the length of a _read_ `BytesLike`, if a `BytesLike` does not
14  /// inherently know its length.
15  ///
16  /// This should be `usize` or `()`.
17  type ExternallyTrackedLength: Sized + Copy + Debug;
18
19  /// The length of these bytes.
20  fn len(&self, len: Self::ExternallyTrackedLength) -> usize;
21
22  /// Peak at a byte.
23  fn peek(&self, i: usize) -> Result<u8, Self::Error>;
24
25  /// Read a fixed amount of bytes from the container.
26  ///
27  /// This MUST return `Ok((len, slice))` where `slice` is the expected length or `Err(_)`.
28  fn read_bytes(
29    &mut self,
30    bytes: usize,
31  ) -> Result<(Self::ExternallyTrackedLength, Self), Self::Error>;
32
33  /// Read a fixed amount of bytes from the container into a slice.
34  /*
35    We _could_ provide this method around `read_bytes` but it'd be a very inefficient
36    default implementation. It's best to require callers provide the implementation.
37  */
38  fn read_into_slice(&mut self, slice: &mut [u8]) -> Result<(), Self::Error>;
39
40  /// Read a byte from the container.
41  #[inline(always)]
42  fn read_byte(&mut self) -> Result<u8, Self::Error> {
43    let mut buf = [0; 1];
44    self.read_into_slice(&mut buf)?;
45    Ok(buf[0])
46  }
47
48  /// Advance the container by a certain amount of bytes.
49  #[inline(always)]
50  fn advance(&mut self, bytes: usize) -> Result<(), Self::Error> {
51    self.read_bytes(bytes).map(|_| ())
52  }
53}
54
55/// An error when working with `&[u8]`.
56#[derive(Clone, Copy, Debug)]
57#[allow(dead_code)]
58pub enum SliceError {
59  /// The blob was short, as discovered when trying to read `{0}` bytes.
60  Short(usize),
61}
62
63impl<'bytes> BytesLike<'bytes> for &'bytes [u8] {
64  type Error = SliceError;
65
66  type ExternallyTrackedLength = ();
67
68  #[inline(always)]
69  fn len(&self, (): ()) -> usize {
70    <[u8]>::len(self)
71  }
72
73  #[inline(always)]
74  fn peek(&self, i: usize) -> Result<u8, Self::Error> {
75    self.get(i).ok_or_else(|| SliceError::Short((i - <[u8]>::len(self)).saturating_add(1))).copied()
76  }
77
78  #[inline(always)]
79  fn read_bytes(
80    &mut self,
81    bytes: usize,
82  ) -> Result<(Self::ExternallyTrackedLength, Self), Self::Error> {
83    if <[u8]>::len(self) < bytes {
84      Err(SliceError::Short(bytes))?;
85    }
86    let res = &self[.. bytes];
87    *self = &self[bytes ..];
88    Ok(((), res))
89  }
90
91  #[inline(always)]
92  fn read_into_slice(&mut self, slice: &mut [u8]) -> Result<(), Self::Error> {
93    slice.copy_from_slice(self.read_bytes(slice.len())?.1);
94    Ok(())
95  }
96}
97
98/// A collection of bytes with an associated length.
99///
100/// This avoids defining `BytesLike::len` which lets us relax the requirement `BytesLike` knows its
101/// length before it has reached its end.
102#[derive(Debug)]
103pub(crate) struct String<'bytes, B: BytesLike<'bytes>> {
104  pub(crate) len: B::ExternallyTrackedLength,
105  pub(crate) bytes: B,
106  pub(crate) _encoding: PhantomData<&'bytes ()>,
107}
108
109impl<'bytes, B: BytesLike<'bytes>> String<'bytes, B> {
110  /// The length of this string.
111  #[inline(always)]
112  pub(crate) fn len(&self) -> usize {
113    self.bytes.len(self.len)
114  }
115
116  /// Consume this into its underlying bytes.
117  #[inline(always)]
118  pub(crate) fn consume(self) -> B {
119    self.bytes
120  }
121}