diff --git a/wincode/src/io/cursor.rs b/wincode/src/io/cursor.rs index 0eab555c..52a6af2b 100644 --- a/wincode/src/io/cursor.rs +++ b/wincode/src/io/cursor.rs @@ -141,6 +141,8 @@ impl<'a, T> Reader<'a> for Cursor where T: AsRef<[u8]>, { + const BORROW_KINDS: u8 = BorrowKind::CallSite.mask(); + #[inline] fn copy_into_slice(&mut self, dst: &mut [MaybeUninit]) -> ReadResult<()> { let src = self.advance_slice_checked(dst.len())?; diff --git a/wincode/src/io/mod.rs b/wincode/src/io/mod.rs index 2d21fbc5..fedcdf4a 100644 --- a/wincode/src/io/mod.rs +++ b/wincode/src/io/mod.rs @@ -8,7 +8,8 @@ use { thiserror::Error, }; -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] +#[repr(u8)] pub enum BorrowKind { /// Borrowed from the call site, not extending past it. CallSite, @@ -18,6 +19,13 @@ pub enum BorrowKind { BackingMut, } +impl BorrowKind { + #[inline] + pub const fn mask(self) -> u8 { + 1u8 << (self as u8) + } +} + impl core::fmt::Display for BorrowKind { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { @@ -62,6 +70,35 @@ pub(super) const fn transpose( /// compatible with readers that don't support borrowing, if possible. /// - Returns [`ReadError::UnsupportedBorrow`] for readers that do not support borrowing. pub trait Reader<'a> { + /// Borrow capabilities of this reader. + /// + /// A bitmask of [`BorrowKind`] values indicating which kinds of borrows are supported. + /// + /// Users of [`Reader`] can call [`Reader::supports_borrow`] to check if a borrow kind + /// is supported. + const BORROW_KINDS: u8 = 0; + + /// Checks if this reader supports the given borrow kind. + /// + /// # Examples + /// ``` + /// # use wincode::io::{Reader, BorrowKind, Cursor}; + /// # + /// let reader = [1, 2, 3, 4, 5]; + /// assert!(reader.as_slice().supports_borrow(BorrowKind::Backing)); + /// + /// let mut reader = [1, 2, 3, 4, 5]; + /// assert!(reader.as_mut_slice().supports_borrow(BorrowKind::BackingMut)); + /// + /// let reader = Cursor::new([1, 2, 3, 4, 5]); + /// assert!(reader.supports_borrow(BorrowKind::CallSite)); + /// assert!(!reader.supports_borrow(BorrowKind::Backing)); + /// ``` + #[inline] + fn supports_borrow(&self, kind: BorrowKind) -> bool { + Self::BORROW_KINDS & kind.mask() != 0 + } + /// Return exactly `N` bytes as `&[u8; N]` without advancing. /// /// Errors if fewer than `N` bytes are available. @@ -270,6 +307,8 @@ pub trait Reader<'a> { } impl<'a, R: Reader<'a> + ?Sized> Reader<'a> for &mut R { + const BORROW_KINDS: u8 = R::BORROW_KINDS; + #[inline(always)] fn by_ref(&mut self) -> impl Reader<'a> { &mut **self diff --git a/wincode/src/io/slice.rs b/wincode/src/io/slice.rs index 172c8b31..2495cf0f 100644 --- a/wincode/src/io/slice.rs +++ b/wincode/src/io/slice.rs @@ -71,6 +71,8 @@ impl<'a, T> SliceUnchecked<'a, T> { } impl<'a> Reader<'a> for SliceUnchecked<'a, u8> { + const BORROW_KINDS: u8 = BorrowKind::Backing.mask() | BorrowKind::CallSite.mask(); + #[inline] fn copy_into_slice(&mut self, buf: &mut [MaybeUninit]) -> ReadResult<()> { // SAFETY: by constructing `SliceUnchecked`, caller guarantees @@ -171,6 +173,9 @@ impl<'a, T> SliceMutUnchecked<'a, T> { } impl<'a> Reader<'a> for SliceMutUnchecked<'a, u8> { + const BORROW_KINDS: u8 = + BorrowKind::Backing.mask() | BorrowKind::BackingMut.mask() | BorrowKind::CallSite.mask(); + #[inline] fn copy_into_slice(&mut self, buf: &mut [MaybeUninit]) -> ReadResult<()> { // SAFETY: by constructing `SliceMutUnchecked`, caller guarantees @@ -260,6 +265,8 @@ impl<'b, T> SliceScopedUnchecked<'_, 'b, T> { } impl<'a> Reader<'a> for SliceScopedUnchecked<'a, '_, u8> { + const BORROW_KINDS: u8 = BorrowKind::CallSite.mask(); + #[inline(always)] fn copy_into_slice(&mut self, buf: &mut [MaybeUninit]) -> ReadResult<()> { self.inner.copy_into_slice(buf) @@ -292,6 +299,8 @@ impl<'a> Reader<'a> for SliceScopedUnchecked<'a, '_, u8> { } impl<'a> Reader<'a> for &'a [u8] { + const BORROW_KINDS: u8 = BorrowKind::Backing.mask() | BorrowKind::CallSite.mask(); + #[inline] fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> { let Some(src) = advance_slice_checked(self, len) else { @@ -357,6 +366,9 @@ impl<'a> Reader<'a> for &'a [u8] { } impl<'a> Reader<'a> for &'a mut [u8] { + const BORROW_KINDS: u8 = + BorrowKind::Backing.mask() | BorrowKind::BackingMut.mask() | BorrowKind::CallSite.mask(); + #[inline(always)] unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult> { let Some(window) = advance_slice_mut_checked(self, n_bytes) else {