use std::borrow::Cow;
use std::hash::Hash;
use bytes::Bytes;
#[cfg(feature = "serde")]
pub(crate) mod serde;
#[derive(Debug, Clone, Eq)]
pub enum BytesCow<'a> {
Slice(&'a [u8]),
StaticSlice(&'static [u8]),
Vec(Vec<u8>),
Bytes(Bytes),
}
impl Default for BytesCow<'_> {
fn default() -> Self {
Self::new()
}
}
impl<'a> BytesCow<'a> {
pub fn new() -> Self {
Self::from_static(b"")
}
pub fn from_static(slice: &'static [u8]) -> Self {
Self::StaticSlice(slice)
}
pub fn from_slice(slice: &'a [u8]) -> Self {
Self::Slice(slice)
}
pub fn from_bytes(bytes: Bytes) -> Self {
Self::Bytes(bytes)
}
pub fn from_cow(cow: Cow<'a, [u8]>) -> Self {
match cow {
Cow::Borrowed(slice) => Self::Slice(slice),
Cow::Owned(bytes) => Self::Vec(bytes),
}
}
pub fn from_vec(bytes: Vec<u8>) -> Self {
Self::Vec(bytes)
}
pub fn into_bytes(self) -> Bytes {
match self {
Self::Slice(slice) => Bytes::copy_from_slice(slice),
Self::StaticSlice(slice) => Bytes::from_static(slice),
Self::Vec(bytes) => Bytes::from(bytes),
Self::Bytes(bytes) => bytes,
}
}
pub fn as_bytes(&self) -> &[u8] {
match self {
Self::Slice(slice) => slice,
Self::StaticSlice(slice) => slice,
Self::Vec(bytes) => bytes.as_slice(),
Self::Bytes(bytes) => bytes.as_ref(),
}
}
}
impl<T> PartialEq<T> for BytesCow<'_>
where
T: AsRef<[u8]>,
{
fn eq(&self, other: &T) -> bool {
self.as_bytes() == other.as_ref()
}
}
impl Hash for BytesCow<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state);
}
}
impl AsRef<[u8]> for BytesCow<'_> {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<'a> From<Cow<'a, [u8]>> for BytesCow<'a> {
fn from(cow: Cow<'a, [u8]>) -> Self {
BytesCow::from_cow(cow)
}
}
impl From<Bytes> for BytesCow<'_> {
fn from(bytes: Bytes) -> Self {
BytesCow::from_bytes(bytes)
}
}
impl<'a> From<&'a [u8]> for BytesCow<'a> {
fn from(bytes: &'a [u8]) -> Self {
BytesCow::from_slice(bytes)
}
}
impl From<Vec<u8>> for BytesCow<'_> {
fn from(bytes: Vec<u8>) -> Self {
BytesCow::from_vec(bytes)
}
}
#[cfg(test)]
#[cfg_attr(all(test, coverage_nightly), coverage(off))]
mod tests {
use super::BytesCow;
#[test]
fn constructors() {
let cow = BytesCow::default();
assert_eq!(cow.as_bytes(), b"");
let cow = BytesCow::from_static(b"hello");
assert_eq!(cow.as_bytes(), b"hello");
let cow = BytesCow::from_slice(b"world");
assert_eq!(cow.as_bytes(), b"world");
let cow = BytesCow::from_vec(vec![1, 2, 3]);
assert_eq!(cow.as_bytes(), &[1, 2, 3]);
let cow = BytesCow::from(vec![1, 2, 3]);
assert_eq!(cow.as_bytes(), &[1, 2, 3]);
let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
assert_eq!(cow.as_bytes(), b"foo");
let cow = BytesCow::from(bytes::Bytes::from(vec![7, 8, 9]));
assert_eq!(cow.as_bytes(), &[7, 8, 9]);
let cow = BytesCow::from_cow(std::borrow::Cow::Borrowed(b"bar"));
assert_eq!(cow.as_bytes(), b"bar");
let cow = BytesCow::from_cow(std::borrow::Cow::Owned(vec![10, 11, 12]));
assert_eq!(cow.as_bytes(), &[10, 11, 12]);
let cow = BytesCow::from(std::borrow::Cow::Owned(vec![4, 5, 6]));
assert_eq!(cow.as_bytes(), &[4, 5, 6]);
let cow = BytesCow::from(&b"hello world"[..]);
assert_eq!(cow.as_bytes(), b"hello world");
}
#[test]
fn into_bytes() {
let cow = BytesCow::from_static(b"hello");
assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"hello"));
let cow = BytesCow::from_slice(b"world");
assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"world"));
let cow = BytesCow::from_vec(vec![1, 2, 3]);
assert_eq!(cow.into_bytes(), bytes::Bytes::from(vec![1, 2, 3]));
let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"foo"));
let cow = BytesCow::from_cow(std::borrow::Cow::Borrowed(b"bar"));
assert_eq!(cow.into_bytes(), bytes::Bytes::from_static(b"bar"));
let cow = BytesCow::from_cow(std::borrow::Cow::Owned(vec![10, 11, 12]));
assert_eq!(cow.into_bytes(), bytes::Bytes::from(vec![10, 11, 12]));
}
#[test]
fn as_ref() {
let cow = BytesCow::from_static(b"hello");
assert_eq!(cow.as_ref(), b"hello");
let cow = BytesCow::from_slice(b"world");
assert_eq!(cow.as_ref(), b"world");
let cow = BytesCow::from_vec(vec![1, 2, 3]);
assert_eq!(cow.as_ref(), &[1, 2, 3]);
let cow = BytesCow::from_bytes(bytes::Bytes::from_static(b"foo"));
assert_eq!(cow.as_ref(), b"foo");
}
#[test]
fn partial_eq() {
let cow = BytesCow::from_static(b"hello");
assert!(cow == b"hello");
assert!(cow != b"world");
let cow = BytesCow::from_slice(b"world");
assert!(cow == b"world");
assert!(cow != b"hello");
let cow = BytesCow::from_vec(vec![1, 2, 3]);
assert!(cow == [1, 2, 3]);
assert!(cow != [4, 5, 6]);
}
#[test]
fn hash() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
b"hello".hash(&mut hasher);
let expected_hash = hasher.finish();
let cow = BytesCow::from_static(b"hello");
let mut hasher = DefaultHasher::new();
cow.hash(&mut hasher);
assert_eq!(hasher.finish(), expected_hash);
}
}