use std::{borrow, cmp, fmt, hash, mem, ops};
use crate::{Buf, BytesMut, buf::IntoIter, debug, storage::INLINE_CAP, storage::Storage};
pub struct Bytes {
pub(crate) storage: Storage,
}
impl Bytes {
#[inline]
pub const fn new() -> Bytes {
Bytes {
storage: Storage::empty(),
}
}
#[inline]
#[must_use]
pub const fn from_static(bytes: &'static [u8]) -> Bytes {
Bytes {
storage: Storage::from_static(bytes),
}
}
#[inline]
pub fn len(&self) -> usize {
self.storage.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.storage.is_empty()
}
pub fn is_inline(&self) -> bool {
self.storage.is_inline()
}
#[must_use]
pub fn copy_from_slice(data: &[u8]) -> Self {
Bytes {
storage: Storage::from_slice(data),
}
}
#[must_use]
pub fn slice(&self, range: impl ops::RangeBounds<usize>) -> Bytes {
self.slice_checked(range)
.expect("Requires that `begin <= end` and `end <= self.len()`")
}
#[must_use]
pub fn slice_checked(&self, range: impl ops::RangeBounds<usize>) -> Option<Bytes> {
use std::ops::Bound;
let len = self.len();
let begin = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => len,
};
if begin <= end && end <= len {
if end - begin <= INLINE_CAP {
Some(Bytes {
storage: Storage::from_slice(&self[begin..end]),
})
} else {
let mut ret = self.clone();
unsafe {
ret.storage.set_end(end);
ret.storage.set_start(begin);
}
Some(ret)
}
} else {
None
}
}
#[must_use]
pub fn slice_ref(&self, subset: &[u8]) -> Bytes {
self.slice_ref_checked(subset)
.expect("Given `sub` slice is not contained within the `Bytes` buffer")
}
#[must_use]
pub fn slice_ref_checked(&self, subset: &[u8]) -> Option<Bytes> {
let bytes_p = self.as_ptr() as usize;
let bytes_len = self.len();
let sub_p = subset.as_ptr() as usize;
let sub_len = subset.len();
if sub_p >= bytes_p && sub_p + sub_len <= bytes_p + bytes_len {
let sub_offset = sub_p - bytes_p;
Some(self.slice(sub_offset..(sub_offset + sub_len)))
} else {
None
}
}
#[must_use]
pub fn split_off(&mut self, at: usize) -> Bytes {
self.split_off_checked(at)
.expect("at value must be <= self.len()`")
}
#[must_use]
pub fn split_off_checked(&mut self, at: usize) -> Option<Bytes> {
if at <= self.len() {
if at == self.len() {
Some(Bytes::new())
} else if at == 0 {
Some(mem::take(self))
} else {
Some(Bytes {
storage: self.storage.split_off(at, true),
})
}
} else {
None
}
}
#[must_use]
pub fn split_to(&mut self, at: usize) -> Bytes {
self.split_to_checked(at)
.expect("at value must be <= self.len()`")
}
#[must_use]
pub fn split_to_checked(&mut self, at: usize) -> Option<Bytes> {
if at <= self.len() {
if at == self.len() {
Some(mem::take(self))
} else if at == 0 {
Some(Bytes::new())
} else {
Some(Bytes {
storage: self.storage.split_to(at),
})
}
} else {
None
}
}
#[inline]
pub fn advance_to(&mut self, cnt: usize) {
unsafe {
self.storage.set_start(cnt);
}
}
#[inline]
pub fn truncate(&mut self, len: usize) {
self.storage.truncate(len, true);
}
#[inline]
pub fn trimdown(&mut self) {
self.storage.trimdown();
}
#[inline]
pub fn clear(&mut self) {
self.storage = Storage::empty();
}
pub fn iter(&'_ self) -> std::slice::Iter<'_, u8> {
self.chunk().iter()
}
#[inline]
#[doc(hidden)]
pub fn info(&self) -> crate::info::Info {
self.storage.info()
}
}
impl Buf for Bytes {
#[inline]
fn remaining(&self) -> usize {
self.len()
}
#[inline]
fn chunk(&self) -> &[u8] {
self.storage.as_ref()
}
#[inline]
fn advance(&mut self, cnt: usize) {
self.advance_to(cnt);
}
}
impl bytes::buf::Buf for Bytes {
#[inline]
fn remaining(&self) -> usize {
self.len()
}
#[inline]
fn chunk(&self) -> &[u8] {
self.storage.as_ref()
}
#[inline]
fn advance(&mut self, cnt: usize) {
self.advance_to(cnt);
}
}
impl Clone for Bytes {
fn clone(&self) -> Bytes {
Bytes {
storage: self.storage.clone(),
}
}
}
impl AsRef<[u8]> for Bytes {
#[inline]
fn as_ref(&self) -> &[u8] {
self.storage.as_ref()
}
}
impl ops::Deref for Bytes {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.storage.as_ref()
}
}
impl From<&Bytes> for Bytes {
fn from(src: &Bytes) -> Bytes {
src.clone()
}
}
impl From<Vec<u8>> for Bytes {
fn from(src: Vec<u8>) -> Bytes {
Bytes {
storage: Storage::from_slice(&src),
}
}
}
impl From<String> for Bytes {
fn from(src: String) -> Bytes {
Bytes {
storage: Storage::from_slice(src.as_bytes()),
}
}
}
impl From<&'static [u8]> for Bytes {
fn from(src: &'static [u8]) -> Bytes {
Bytes::from_static(src)
}
}
impl From<&'static str> for Bytes {
fn from(src: &'static str) -> Bytes {
Bytes::from_static(src.as_bytes())
}
}
impl<'a, const N: usize> From<&'a [u8; N]> for Bytes {
fn from(src: &'a [u8; N]) -> Bytes {
Bytes::copy_from_slice(src)
}
}
impl FromIterator<u8> for Bytes {
fn from_iter<T: IntoIterator<Item = u8>>(into_iter: T) -> Self {
BytesMut::from_iter(into_iter).freeze()
}
}
impl<'a> FromIterator<&'a u8> for Bytes {
fn from_iter<T: IntoIterator<Item = &'a u8>>(into_iter: T) -> Self {
BytesMut::from_iter(into_iter).freeze()
}
}
impl Eq for Bytes {}
impl PartialEq for Bytes {
fn eq(&self, other: &Bytes) -> bool {
self.storage.as_ref() == other.storage.as_ref()
}
}
impl PartialOrd for Bytes {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Bytes {
fn cmp(&self, other: &Bytes) -> cmp::Ordering {
self.storage.as_ref().cmp(other.storage.as_ref())
}
}
impl Default for Bytes {
#[inline]
fn default() -> Bytes {
Bytes::new()
}
}
impl fmt::Debug for Bytes {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&debug::BsDebug(self.storage.as_ref()), fmt)
}
}
impl hash::Hash for Bytes {
fn hash<H>(&self, state: &mut H)
where
H: hash::Hasher,
{
let s: &[u8] = self.as_ref();
s.hash(state);
}
}
impl borrow::Borrow<[u8]> for Bytes {
fn borrow(&self) -> &[u8] {
self.as_ref()
}
}
impl IntoIterator for Bytes {
type Item = u8;
type IntoIter = IntoIter<Bytes>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
impl<'a> IntoIterator for &'a Bytes {
type Item = &'a u8;
type IntoIter = std::slice::Iter<'a, u8>;
fn into_iter(self) -> Self::IntoIter {
self.as_ref().iter()
}
}
impl PartialEq<[u8]> for Bytes {
fn eq(&self, other: &[u8]) -> bool {
self.storage.as_ref() == other
}
}
impl<const N: usize> PartialEq<[u8; N]> for Bytes {
fn eq(&self, other: &[u8; N]) -> bool {
self.storage.as_ref() == other.as_ref()
}
}
impl PartialOrd<[u8]> for Bytes {
fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
self.storage.as_ref().partial_cmp(other)
}
}
impl<const N: usize> PartialOrd<[u8; N]> for Bytes {
fn partial_cmp(&self, other: &[u8; N]) -> Option<cmp::Ordering> {
self.storage.as_ref().partial_cmp(other.as_ref())
}
}
impl PartialEq<Bytes> for [u8] {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl<const N: usize> PartialEq<Bytes> for [u8; N] {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl<const N: usize> PartialEq<Bytes> for &[u8; N] {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for [u8] {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl<const N: usize> PartialOrd<Bytes> for [u8; N] {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl PartialEq<str> for Bytes {
fn eq(&self, other: &str) -> bool {
self.storage.as_ref() == other.as_bytes()
}
}
impl PartialOrd<str> for Bytes {
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
self.storage.as_ref().partial_cmp(other.as_bytes())
}
}
impl PartialEq<Bytes> for str {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for str {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl PartialEq<Vec<u8>> for Bytes {
fn eq(&self, other: &Vec<u8>) -> bool {
*self == other[..]
}
}
impl PartialOrd<Vec<u8>> for Bytes {
fn partial_cmp(&self, other: &Vec<u8>) -> Option<cmp::Ordering> {
self.storage.as_ref().partial_cmp(&other[..])
}
}
impl PartialEq<Bytes> for Vec<u8> {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for Vec<u8> {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl PartialEq<String> for Bytes {
fn eq(&self, other: &String) -> bool {
*self == other[..]
}
}
impl PartialOrd<String> for Bytes {
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
self.storage.as_ref().partial_cmp(other.as_bytes())
}
}
impl PartialEq<Bytes> for String {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for String {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl PartialEq<Bytes> for &[u8] {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for &[u8] {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl PartialEq<Bytes> for &str {
fn eq(&self, other: &Bytes) -> bool {
*other == *self
}
}
impl PartialOrd<Bytes> for &str {
fn partial_cmp(&self, other: &Bytes) -> Option<cmp::Ordering> {
other.partial_cmp(self)
}
}
impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes
where
Bytes: PartialEq<T>,
{
fn eq(&self, other: &&'a T) -> bool {
*self == **other
}
}
impl<'a, T: ?Sized> PartialOrd<&'a T> for Bytes
where
Bytes: PartialOrd<T>,
{
fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
self.partial_cmp(&**other)
}
}
#[cfg(test)]
#[allow(unused_must_use)]
mod tests {
use std::collections::HashMap;
use super::*;
use crate::BufMut;
const LONG: &[u8] = b"mary had a1 little la2mb, little lamb, little lamb, little lamb, little lamb, little lamb \
mary had a little lamb, little lamb, little lamb, little lamb, little lamb, little lamb \
mary had a little lamb, little lamb, little lamb, little lamb, little lamb, little lamb \0";
#[test]
#[allow(
clippy::op_ref,
clippy::len_zero,
clippy::nonminimal_bool,
clippy::unnecessary_fallible_conversions
)]
fn bytes() {
let mut b = Bytes::from(LONG.to_vec());
b.advance_to(10);
assert_eq!(&b, &LONG[10..]);
b.advance_to(10);
assert_eq!(&b[..], &LONG[20..]);
assert_eq!(&b, &LONG[20..]);
b.clear();
assert!(b.is_inline());
assert!(b.is_empty());
assert!(b.len() == 0);
let mut b = Bytes::from(LONG);
b.advance_to(10);
assert_eq!(&b, &LONG[10..]);
b.advance_to(10);
assert_eq!(&b[..], &LONG[20..]);
assert_eq!(&b, &LONG[20..]);
b.clear();
assert!(b.is_empty());
assert!(b.len() == 0);
let mut b = Bytes::from(LONG);
b.split_off(10);
assert_eq!(&b, &LONG[..10]);
b.advance_to(5);
assert_eq!(&b, &LONG[5..10]);
let mut b = Bytes::copy_from_slice(&LONG[..15]);
assert!(b.is_inline());
b.split_off(10);
assert_eq!(&b, &LONG[..10]);
b.advance_to(1);
assert_eq!(&b, &LONG[1..10]);
let b = Bytes::from(b"123");
assert!(&b"12"[..] > &b);
assert!("123" == &b);
assert!("12" > &b);
let b = Bytes::from(&Bytes::from(LONG));
assert_eq!(b, LONG);
let b = Bytes::from(BytesMut::from(LONG));
assert_eq!(b, LONG);
let mut b: Bytes = BytesMut::try_from(b).unwrap().freeze();
assert_eq!(b, LONG);
assert!(!(b > b));
assert_eq!(<Bytes as Buf>::remaining(&b), LONG.len());
assert_eq!(<Bytes as Buf>::chunk(&b), LONG);
<Bytes as Buf>::advance(&mut b, 10);
assert_eq!(Buf::chunk(&b), &LONG[10..]);
<Bytes as Buf>::advance(&mut b, 10);
assert_eq!(Buf::chunk(&b), &LONG[20..]);
let mut h: HashMap<Bytes, usize> = HashMap::default();
h.insert(b.clone(), 1);
assert_eq!(h.get(&b), Some(&1));
let mut b = BytesMut::try_from(LONG).unwrap();
assert_eq!(b, LONG);
assert_eq!(<BytesMut as Buf>::remaining(&b), LONG.len());
assert_eq!(<BytesMut as BufMut>::remaining_mut(&b), 0);
assert_eq!(<BytesMut as Buf>::chunk(&b), LONG);
<BytesMut as Buf>::advance(&mut b, 10);
assert_eq!(<BytesMut as Buf>::chunk(&b), &LONG[10..]);
let mut b = BytesMut::with_capacity(12);
<BytesMut as BufMut>::put_i8(&mut b, 1);
assert_eq!(b, b"\x01".as_ref());
<BytesMut as BufMut>::put_u8(&mut b, 2);
assert_eq!(b, b"\x01\x02".as_ref());
<BytesMut as BufMut>::put_slice(&mut b, b"12345");
assert_eq!(b, b"\x01\x0212345".as_ref());
<BytesMut as BufMut>::chunk_mut(&mut b).write_byte(0, b'1');
unsafe { <BytesMut as BufMut>::advance_mut(&mut b, 1) };
assert_eq!(b, b"\x01\x02123451".as_ref());
let mut iter = Bytes::from(LONG.to_vec()).into_iter();
assert_eq!(iter.next(), Some(LONG[0]));
assert_eq!(iter.next(), Some(LONG[1]));
assert_eq!(iter.next(), Some(LONG[2]));
assert_eq!(iter.next(), Some(LONG[3]));
assert_eq!(iter.get_ref(), &LONG[4..]);
assert_eq!(iter.get_mut(), &LONG[4..]);
let b = iter.into_inner();
assert_eq!(b, &LONG[4..]);
}
}