use core::fmt::Debug;
use core::ops::{Deref, Range};
#[allow(clippy::len_without_is_empty)]
pub trait Source {
type Slice<'a>: PartialEq + Eq + Debug
where
Self: 'a;
fn len(&self) -> usize;
fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
where
Chunk: self::Chunk<'a>;
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn read_byte_unchecked(&self, offset: usize) -> u8;
#[cfg(feature = "forbid_unsafe")]
fn read_byte(&self, offset: usize) -> u8;
fn slice(&self, range: Range<usize>) -> Option<Self::Slice<'_>>;
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self::Slice<'_>;
#[inline]
fn find_boundary(&self, index: usize) -> usize {
index
}
fn is_boundary(&self, index: usize) -> bool;
}
impl Source for str {
type Slice<'a> = &'a str;
#[inline]
fn len(&self) -> usize {
self.len()
}
#[inline]
fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
where
Chunk: self::Chunk<'a>,
{
#[cfg(not(feature = "forbid_unsafe"))]
if offset + (Chunk::SIZE - 1) < self.len() {
Some(unsafe { Chunk::from_ptr(self.as_ptr().add(offset)) })
} else {
None
}
#[cfg(feature = "forbid_unsafe")]
Chunk::from_slice(self.as_bytes().slice(offset..Chunk::SIZE + offset)?)
}
#[inline]
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn read_byte_unchecked(&self, offset: usize) -> u8 {
Chunk::from_ptr(self.as_ptr().add(offset))
}
#[inline]
#[cfg(feature = "forbid_unsafe")]
fn read_byte(&self, offset: usize) -> u8 {
self.as_bytes()[offset]
}
#[inline]
fn slice(&self, range: Range<usize>) -> Option<&str> {
self.get(range)
}
#[cfg(not(feature = "forbid_unsafe"))]
#[inline]
unsafe fn slice_unchecked(&self, range: Range<usize>) -> &str {
debug_assert!(
range.start <= self.len() && range.end <= self.len(),
"Reading out of bounds {:?} for {}!",
range,
self.len()
);
self.get_unchecked(range)
}
#[inline]
fn find_boundary(&self, mut index: usize) -> usize {
while !self.is_char_boundary(index) {
index += 1;
}
index
}
#[inline]
fn is_boundary(&self, index: usize) -> bool {
self.is_char_boundary(index)
}
}
impl Source for [u8] {
type Slice<'a> = &'a [u8];
#[inline]
fn len(&self) -> usize {
self.len()
}
#[inline]
fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
where
Chunk: self::Chunk<'a>,
{
#[cfg(not(feature = "forbid_unsafe"))]
if offset + (Chunk::SIZE - 1) < self.len() {
Some(unsafe { Chunk::from_ptr(self.as_ptr().add(offset)) })
} else {
None
}
#[cfg(feature = "forbid_unsafe")]
Chunk::from_slice(self.slice(offset..Chunk::SIZE + offset)?)
}
#[inline]
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn read_byte_unchecked(&self, offset: usize) -> u8 {
Chunk::from_ptr(self.as_ptr().add(offset))
}
#[inline]
#[cfg(feature = "forbid_unsafe")]
fn read_byte(&self, offset: usize) -> u8 {
self[offset]
}
#[inline]
fn slice(&self, range: Range<usize>) -> Option<&[u8]> {
self.get(range)
}
#[cfg(not(feature = "forbid_unsafe"))]
#[inline]
unsafe fn slice_unchecked(&self, range: Range<usize>) -> &[u8] {
debug_assert!(
range.start <= self.len() && range.end <= self.len(),
"Reading out of bounds {:?} for {}!",
range,
self.len()
);
self.get_unchecked(range)
}
#[inline]
fn is_boundary(&self, index: usize) -> bool {
index <= self.len()
}
}
impl<T> Source for T
where
T: Deref,
<T as Deref>::Target: Source,
{
type Slice<'a>
= <T::Target as Source>::Slice<'a>
where
T: 'a;
fn len(&self) -> usize {
self.deref().len()
}
fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
where
Chunk: self::Chunk<'a>,
{
self.deref().read(offset)
}
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn read_byte_unchecked(&self, offset: usize) -> u8 {
self.deref().read_byte_unchecked(offset)
}
#[cfg(feature = "forbid_unsafe")]
fn read_byte(&self, offset: usize) -> u8 {
self.deref().read_byte(offset)
}
fn slice(&self, range: Range<usize>) -> Option<Self::Slice<'_>> {
self.deref().slice(range)
}
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn slice_unchecked(&self, range: Range<usize>) -> Self::Slice<'_> {
self.deref().slice_unchecked(range)
}
fn is_boundary(&self, index: usize) -> bool {
self.deref().is_boundary(index)
}
fn find_boundary(&self, index: usize) -> usize {
self.deref().find_boundary(index)
}
}
pub trait Chunk<'source>: Sized + Copy + PartialEq + Eq {
const SIZE: usize;
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn from_ptr(ptr: *const u8) -> Self;
#[cfg(feature = "forbid_unsafe")]
fn from_slice(s: &'source [u8]) -> Option<Self>;
}
#[allow(clippy::needless_lifetimes)]
impl<'source> Chunk<'source> for u8 {
const SIZE: usize = 1;
#[inline]
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn from_ptr(ptr: *const u8) -> Self {
*ptr
}
#[inline]
#[cfg(feature = "forbid_unsafe")]
fn from_slice(s: &'source [u8]) -> Option<Self> {
s.first().copied()
}
}
impl<'source, const N: usize> Chunk<'source> for &'source [u8; N] {
const SIZE: usize = N;
#[inline]
#[cfg(not(feature = "forbid_unsafe"))]
unsafe fn from_ptr(ptr: *const u8) -> Self {
&*(ptr as *const [u8; N])
}
#[inline]
#[cfg(feature = "forbid_unsafe")]
fn from_slice(s: &'source [u8]) -> Option<Self> {
s.slice(0..Self::SIZE).and_then(|x| x.try_into().ok())
}
}