use core::fmt;
use crate::Context;
mod sealed {
pub trait Sealed {}
impl Sealed for super::SliceCursor<'_> {}
impl Sealed for super::MutSliceCursor<'_, '_> {}
impl<'de, C> Sealed for &mut C where C: ?Sized + super::Cursor<'de> {}
}
pub trait Cursor<'de>: self::sealed::Sealed {
type Mut<'this>: Cursor<'de>
where
Self: 'this;
type TryClone: Cursor<'de>;
fn borrow_mut(&mut self) -> Self::Mut<'_>;
fn try_clone(&self) -> Option<Self::TryClone>;
#[doc(hidden)]
fn remaining(&self) -> usize;
#[doc(hidden)]
fn peek(&self) -> Option<u8>;
#[doc(hidden)]
fn read_byte<C>(&mut self, cx: C) -> Result<u8, C::Error>
where
C: Context;
#[doc(hidden)]
fn read_slice<C>(&mut self, cx: C, n: usize) -> Result<&'de [u8], C::Error>
where
C: Context;
#[doc(hidden)]
#[inline]
fn skip<C>(&mut self, cx: C, n: usize) -> Result<(), C::Error>
where
C: Context,
{
self.read_slice(cx, n)?;
Ok(())
}
#[doc(hidden)]
#[inline]
fn is_exhausted<C>(&mut self, _: C) -> bool
where
C: Context,
{
self.remaining() == 0
}
}
#[derive(Clone)]
pub struct SliceCursor<'de> {
data: &'de [u8],
}
impl<'de> SliceCursor<'de> {
#[inline]
pub(crate) fn new(data: &'de [u8]) -> Self {
Self { data }
}
}
impl<'de> Cursor<'de> for SliceCursor<'de> {
type Mut<'this>
= &'this mut Self
where
Self: 'this;
type TryClone = SliceCursor<'de>;
#[inline]
fn borrow_mut(&mut self) -> Self::Mut<'_> {
self
}
#[inline]
fn try_clone(&self) -> Option<Self::TryClone> {
Some(SliceCursor { data: self.data })
}
#[inline]
fn remaining(&self) -> usize {
self.data.len()
}
#[inline]
fn peek(&self) -> Option<u8> {
self.data.first().copied()
}
#[inline]
fn read_byte<C>(&mut self, cx: C) -> Result<u8, C::Error>
where
C: Context,
{
let [first, tail @ ..] = self.data else {
return Err(cx.message(Underflow { n: 1, remaining: 0 }));
};
self.data = tail;
cx.advance(1);
Ok(*first)
}
#[inline]
fn read_slice<C>(&mut self, cx: C, n: usize) -> Result<&'de [u8], C::Error>
where
C: Context,
{
if self.data.len() < n {
return Err(cx.message(Underflow {
n,
remaining: self.data.len(),
}));
}
let (head, tail) = self.data.split_at(n);
self.data = tail;
cx.advance(n);
Ok(head)
}
}
pub struct MutSliceCursor<'a, 'de> {
data: &'a mut &'de [u8],
}
impl<'a, 'de> MutSliceCursor<'a, 'de> {
#[inline]
pub(crate) fn new(data: &'a mut &'de [u8]) -> Self {
Self { data }
}
}
impl<'de> Cursor<'de> for MutSliceCursor<'_, 'de> {
type Mut<'this>
= &'this mut Self
where
Self: 'this;
type TryClone = SliceCursor<'de>;
#[inline]
fn borrow_mut(&mut self) -> Self::Mut<'_> {
self
}
#[inline]
fn try_clone(&self) -> Option<Self::TryClone> {
Some(SliceCursor { data: self.data })
}
#[inline]
fn remaining(&self) -> usize {
self.data.len()
}
#[inline]
fn peek(&self) -> Option<u8> {
self.data.first().copied()
}
#[inline]
fn read_byte<C>(&mut self, cx: C) -> Result<u8, C::Error>
where
C: Context,
{
let [first, tail @ ..] = *self.data else {
return Err(cx.message(Underflow { n: 1, remaining: 0 }));
};
*self.data = tail;
cx.advance(1);
Ok(*first)
}
#[inline]
fn read_slice<C>(&mut self, cx: C, n: usize) -> Result<&'de [u8], C::Error>
where
C: Context,
{
if self.data.len() < n {
return Err(cx.message(Underflow {
n,
remaining: self.data.len(),
}));
}
let (head, tail) = self.data.split_at(n);
*self.data = tail;
cx.advance(n);
Ok(head)
}
}
impl<'de, P> Cursor<'de> for &mut P
where
P: ?Sized + Cursor<'de>,
{
type Mut<'this>
= P::Mut<'this>
where
Self: 'this;
type TryClone = P::TryClone;
#[inline]
fn borrow_mut(&mut self) -> Self::Mut<'_> {
(**self).borrow_mut()
}
#[inline]
fn try_clone(&self) -> Option<Self::TryClone> {
(**self).try_clone()
}
#[inline]
fn remaining(&self) -> usize {
(**self).remaining()
}
#[inline]
fn peek(&self) -> Option<u8> {
(**self).peek()
}
#[inline]
fn read_byte<C>(&mut self, cx: C) -> Result<u8, C::Error>
where
C: Context,
{
(**self).read_byte(cx)
}
#[inline]
fn read_slice<C>(&mut self, cx: C, n: usize) -> Result<&'de [u8], C::Error>
where
C: Context,
{
(**self).read_slice(cx, n)
}
#[inline]
fn skip<C>(&mut self, cx: C, n: usize) -> Result<(), C::Error>
where
C: Context,
{
(**self).skip(cx, n)
}
#[inline]
fn is_exhausted<C>(&mut self, cx: C) -> bool
where
C: Context,
{
(**self).is_exhausted(cx)
}
}
mod into_sealed {
pub trait Sealed {}
impl Sealed for &[u8] {}
impl Sealed for &str {}
impl Sealed for &mut &[u8] {}
}
pub trait IntoCursor<'de>: self::into_sealed::Sealed {
type Cursor: Cursor<'de>;
fn into_cursor(self) -> Self::Cursor;
}
impl<'de> IntoCursor<'de> for &'de [u8] {
type Cursor = SliceCursor<'de>;
#[inline]
fn into_cursor(self) -> Self::Cursor {
SliceCursor::new(self)
}
}
impl<'de> IntoCursor<'de> for &'de str {
type Cursor = SliceCursor<'de>;
#[inline]
fn into_cursor(self) -> Self::Cursor {
SliceCursor::new(self.as_bytes())
}
}
impl<'a, 'de> IntoCursor<'de> for &'a mut &'de [u8] {
type Cursor = MutSliceCursor<'a, 'de>;
#[inline]
fn into_cursor(self) -> Self::Cursor {
MutSliceCursor::new(self)
}
}
struct Underflow {
n: usize,
remaining: usize,
}
impl fmt::Display for Underflow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Underflow { n, remaining } = self;
write!(
f,
"Tried to read {n} bytes from JSONB input, with {remaining} bytes remaining"
)
}
}