use core::{
hash::{Hash, Hasher},
marker::PhantomData,
ops::{Range, RangeBounds},
};
use bytes::{Buf, Bytes};
use std::{borrow::Cow, boxed::Box, string::String, sync::Arc, vec::Vec};
use crate::{
BytesMut, OutOfBounds, RangeOutOfBounds,
buffer::{Buffer, INLINE_CAP},
};
use super::strategy::ImmutableStorage;
pub(crate) fn visible_subslice_range(container: &[u8], subset: &[u8]) -> Option<Range<usize>> {
if subset.is_empty() {
return Some(0..0);
}
contained_address_range(
container.as_ptr().addr(),
container.len(),
subset.as_ptr().addr(),
subset.len(),
)
}
fn contained_address_range(
container_start: usize,
container_len: usize,
subset_start: usize,
subset_len: usize,
) -> Option<Range<usize>> {
let container_end = container_start.checked_add(container_len)?;
let subset_end = subset_start.checked_add(subset_len)?;
if subset_start < container_start || subset_end > container_end {
return None;
}
Some(subset_start.checked_sub(container_start)?..subset_end.checked_sub(container_start)?)
}
mod cmp;
mod fmt;
mod from;
mod iter;
mod ops;
#[cfg(feature = "arbitrary")]
mod arbitrary;
#[cfg(feature = "borsh")]
mod borsh;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde")]
mod serde;
#[repr(transparent)]
pub struct RawBytes<S> {
pub(crate) repr: Repr,
_strategy: PhantomData<S>,
}
impl<S> Clone for RawBytes<S> {
#[cfg_attr(not(coverage), inline(always))]
fn clone(&self) -> Self {
match &self.repr {
Repr::Inline(_) => unsafe { core::ptr::read(self as *const RawBytes<S>) },
Repr::Heap(bytes) => Self {
repr: Repr::Heap(bytes.clone()),
_strategy: PhantomData,
},
}
}
}
impl<S> RawBytes<S> {
#[inline]
pub const fn new() -> Self {
Self::inline(Buffer::new())
}
#[inline]
pub const fn new_inline(bytes: &[u8]) -> Self {
let blen = bytes.len();
assert!(blen <= INLINE_CAP);
Self::inline(unsafe { Buffer::copy_from_slice(bytes) })
}
#[inline]
pub const fn from_static(bytes: &'static [u8]) -> Self {
if bytes.len() <= INLINE_CAP {
return Self::new_inline(bytes);
}
Self::heap(Bytes::from_static(bytes))
}
#[cfg_attr(not(coverage), inline(always))]
pub const fn is_inline(&self) -> bool {
matches!(self.repr, Repr::Inline(..))
}
#[cfg_attr(not(coverage), inline(always))]
pub const fn is_heap(&self) -> bool {
matches!(self.repr, Repr::Heap(..))
}
#[inline]
pub fn unwrap_inline(self) -> Buffer {
match self.repr {
Repr::Inline(b) => b,
Repr::Heap(_) => panic!("called `Bytes::unwrap_inline()` on a heap allocated buffer"),
}
}
#[inline]
pub fn try_unwrap_inline(self) -> Result<Buffer, Bytes> {
match self.repr {
Repr::Inline(b) => Ok(b),
Repr::Heap(b) => Err(b),
}
}
#[inline]
pub fn unwrap_heap(self) -> Bytes {
match self.repr {
Repr::Inline(_) => panic!("called `Bytes::unwrap_heap()` on an inline buffer"),
Repr::Heap(b) => b,
}
}
#[inline]
pub fn try_unwrap_heap(self) -> Result<Bytes, Buffer> {
match self.repr {
Repr::Inline(b) => Err(b),
Repr::Heap(b) => Ok(b),
}
}
}
impl<S> RawBytes<S>
where
Self: ImmutableStorage,
{
#[inline]
pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
ImmutableStorage::slice(self, range)
}
pub fn try_slice(&self, range: impl RangeBounds<usize>) -> Result<Self, RangeOutOfBounds> {
ImmutableStorage::try_slice(self, range)
}
pub fn slice_ref(&self, subset: &[u8]) -> Self {
self
.try_slice_ref(subset)
.expect("slice_ref subset must be contained in the current visible view")
}
pub fn try_slice_ref(&self, subset: &[u8]) -> Option<Self> {
if subset.is_empty() {
return Some(Self::new());
}
let range = visible_subslice_range(self.as_ref(), subset)?;
self.try_slice(range).ok()
}
#[must_use = "consider RawBytes::truncate if you don't need the other half"]
pub fn split_off(&mut self, at: usize) -> Self {
ImmutableStorage::split_off(self, at)
}
#[cfg_attr(not(coverage), inline(always))]
pub fn try_split_off(&mut self, at: usize) -> Result<Self, OutOfBounds> {
let len = self.len();
if at > len {
return Err(OutOfBounds::new(at, len));
}
Ok(self.split_off(at))
}
#[must_use = "consider RawBytes::advance if you don't need the other half"]
pub fn split_to(&mut self, at: usize) -> Self {
ImmutableStorage::split_to(self, at)
}
#[cfg_attr(not(coverage), inline(always))]
pub fn try_split_to(&mut self, at: usize) -> Result<Self, OutOfBounds> {
let len = self.len();
if at > len {
return Err(OutOfBounds::new(at, len));
}
Ok(self.split_to(at))
}
#[cfg_attr(not(coverage), inline(always))]
pub fn truncate(&mut self, new_len: usize) {
ImmutableStorage::truncate(self, new_len);
}
#[cfg_attr(not(coverage), inline(always))]
pub fn clear(&mut self) {
ImmutableStorage::clear(self)
}
#[cfg_attr(not(coverage), inline(always))]
pub fn try_advance(&mut self, cnt: usize) -> Result<(), OutOfBounds> {
let len = self.len();
if cnt > len {
return Err(OutOfBounds::new(cnt, len));
}
ImmutableStorage::advance(self, cnt);
Ok(())
}
}
impl<S> RawBytes<S> {
#[cfg_attr(not(coverage), inline(always))]
const fn new_in(repr: Repr) -> Self {
Self {
repr,
_strategy: PhantomData,
}
}
#[cfg_attr(not(coverage), inline(always))]
pub(crate) const fn inline(storage: Buffer) -> Self {
Self::new_in(Repr::inline(storage))
}
#[cfg_attr(not(coverage), inline(always))]
pub(crate) const fn heap(bytes: Bytes) -> Self {
Self::new_in(Repr::Heap(bytes))
}
#[cfg_attr(not(coverage), inline(always))]
pub fn is_unique(&self) -> bool {
self.repr.is_unique()
}
#[cfg_attr(not(coverage), inline(always))]
pub const fn len(&self) -> usize {
self.repr.len()
}
#[cfg_attr(not(coverage), inline(always))]
pub const fn is_empty(&self) -> bool {
self.repr.is_empty()
}
#[inline]
pub fn copy_from_slice(bytes: impl AsRef<[u8]>) -> Self {
Self::new_in(Repr::new(bytes.as_ref()))
}
#[cfg_attr(not(coverage), inline(always))]
pub fn as_slice(&self) -> &[u8] {
self.repr.as_slice()
}
pub fn try_into_mut(self) -> Result<BytesMut, Self> {
match self.repr {
Repr::Inline(storage) => Ok(BytesMut::from_inline(storage)),
Repr::Heap(bytes) => match bytes.try_into_mut() {
Ok(bytes) => Ok(BytesMut::from_bytes_mut(bytes)),
Err(bytes) => Err(Self::heap(bytes)),
},
}
}
pub fn try_into_buffer(self) -> Result<Buffer, Self> {
if self.len() > INLINE_CAP {
return Err(self);
}
match self.repr {
Repr::Inline(storage) => Ok(storage),
Repr::Heap(bytes) => {
let visible: &[u8] = bytes.as_ref();
Ok(Buffer::try_from(visible).expect("length checked before conversion"))
}
}
}
#[inline]
pub fn into_vec(self) -> Vec<u8> {
self.repr.into_vec()
}
#[inline]
pub fn into_boxed_slice(self) -> Box<[u8]> {
self.into_vec().into_boxed_slice()
}
#[inline]
pub fn into_bytes(self) -> Bytes {
self.repr.into_bytes()
}
#[inline]
pub fn into_arc(self) -> Arc<[u8]> {
self.repr.into_arc()
}
#[inline]
pub fn to_vec(&self) -> Vec<u8> {
self.as_slice().to_vec()
}
#[inline]
pub fn to_boxed_slice(&self) -> Box<[u8]> {
self.as_slice().into()
}
}
impl<S> Default for RawBytes<S> {
#[cfg_attr(not(coverage), inline(always))]
fn default() -> Self {
Self::new()
}
}
impl<S> Buf for RawBytes<S>
where
Self: ImmutableStorage,
{
#[inline]
fn remaining(&self) -> usize {
self.len()
}
#[inline]
fn chunk(&self) -> &[u8] {
self.as_slice()
}
#[cfg_attr(not(coverage), inline(always))]
fn advance(&mut self, cnt: usize) {
ImmutableStorage::advance(self, cnt);
}
#[cfg_attr(not(coverage), inline(always))]
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
ImmutableStorage::copy_to_bytes(self, len)
}
fn get_int(&mut self, nbytes: usize) -> i64 {
crate::buffer::sign_extend(::bytes::Buf::get_uint(self, nbytes), nbytes)
}
fn get_int_le(&mut self, nbytes: usize) -> i64 {
crate::buffer::sign_extend(::bytes::Buf::get_uint_le(self, nbytes), nbytes)
}
fn get_int_ne(&mut self, nbytes: usize) -> i64 {
crate::buffer::sign_extend(::bytes::Buf::get_uint_ne(self, nbytes), nbytes)
}
fn try_get_int(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
::bytes::Buf::try_get_uint(self, nbytes).map(|value| crate::buffer::sign_extend(value, nbytes))
}
fn try_get_int_le(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
::bytes::Buf::try_get_uint_le(self, nbytes)
.map(|value| crate::buffer::sign_extend(value, nbytes))
}
fn try_get_int_ne(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
::bytes::Buf::try_get_uint_ne(self, nbytes)
.map(|value| crate::buffer::sign_extend(value, nbytes))
}
}
#[derive(Clone, Debug)]
pub(crate) enum Repr {
Inline(Buffer),
Heap(Bytes),
}
impl Repr {
#[cfg_attr(not(coverage), inline(always))]
pub(crate) const fn inline(storage: Buffer) -> Self {
Self::Inline(storage)
}
#[inline]
fn new(bytes: &[u8]) -> Self {
if let Some(inline) = Self::new_on_stack(bytes) {
inline
} else {
Self::Heap(Bytes::copy_from_slice(bytes))
}
}
#[inline]
fn from_vec(vec: Vec<u8>) -> Self {
if let Some(inline) = Self::new_on_stack(&vec) {
inline
} else {
Self::Heap(Bytes::from(vec))
}
}
#[inline]
fn from_box(vec: Box<[u8]>) -> Self {
if let Some(inline) = Self::new_on_stack(&vec) {
inline
} else {
Self::Heap(Bytes::from(vec))
}
}
#[inline]
fn from_arc(vec: Arc<[u8]>) -> Self {
if let Some(inline) = Self::new_on_stack(&vec) {
inline
} else {
Self::Heap(Bytes::copy_from_slice(vec.as_ref()))
}
}
#[inline]
const fn new_on_stack(bytes: &[u8]) -> Option<Self> {
if bytes.len() <= INLINE_CAP {
Some(Self::Inline(unsafe { Buffer::copy_from_slice(bytes) }))
} else {
None
}
}
#[cfg_attr(not(coverage), inline(always))]
const fn len(&self) -> usize {
match self {
Self::Inline(storage) => storage.remaining(),
Self::Heap(bytes) => bytes.len(),
}
}
#[cfg_attr(not(coverage), inline(always))]
const fn is_empty(&self) -> bool {
match self {
Self::Inline(storage) => storage.remaining() == 0,
Self::Heap(bytes) => bytes.is_empty(),
}
}
#[cfg_attr(not(coverage), inline(always))]
fn is_unique(&self) -> bool {
match self {
Self::Inline { .. } => false,
Self::Heap(bytes) => bytes.is_unique(),
}
}
#[cfg_attr(not(coverage), inline(always))]
fn as_slice(&self) -> &[u8] {
match self {
Self::Inline(storage) => storage.as_slice(),
Self::Heap(bytes) => bytes.as_ref(),
}
}
#[inline]
fn ptr_eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Inline { .. }, Self::Inline { .. }) => false,
(Self::Heap(a), Self::Heap(b)) => a.len() == b.len() && a.as_ptr() == b.as_ptr(),
_ => false,
}
}
#[inline]
fn into_vec(self) -> Vec<u8> {
match self {
Self::Inline(storage) => storage.to_vec(),
Self::Heap(bytes) => bytes.into(),
}
}
#[inline]
fn into_bytes(self) -> Bytes {
match self {
Self::Inline(storage) => Bytes::copy_from_slice(storage.as_slice()),
Self::Heap(bytes) => bytes,
}
}
#[inline]
fn into_arc(self) -> Arc<[u8]> {
match self {
Self::Inline(storage) => Arc::from(storage.as_slice()),
Self::Heap(bytes) => Arc::from(Vec::<u8>::from(bytes)),
}
}
}
#[cfg(test)]
mod tests {
use super::contained_address_range;
#[test]
fn contained_address_range_checks_bounds_and_overflow() {
assert_eq!(contained_address_range(10, 8, 10, 3), Some(0..3));
assert_eq!(contained_address_range(10, 8, 14, 4), Some(4..8));
assert_eq!(contained_address_range(10, 8, 9, 1), None);
assert_eq!(contained_address_range(10, 8, 17, 2), None);
assert_eq!(
contained_address_range(usize::MAX - 1, 2, usize::MAX - 1, 1),
None
);
assert_eq!(contained_address_range(0, 1, usize::MAX, 2), None);
}
}