use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::ops::{Deref, DerefMut}; #[cfg(feature = "alloc")] use alloc::borrow::ToOwned; #[cfg(feature = "alloc")] use alloc::boxed::Box; #[cfg(any(feature = "std", feature = "alloc"))] use crate::ByteBuf; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; /// Wrapper around `[u8]` to serialize and deserialize efficiently. /// /// ``` /// use std::collections::HashMap; /// use std::io; /// /// use serde_bytes::Bytes; /// /// fn print_encoded_cache() -> bincode::Result<()> { /// let mut cache = HashMap::new(); /// cache.insert(3, Bytes::new(b"three")); /// cache.insert(2, Bytes::new(b"two")); /// cache.insert(1, Bytes::new(b"one")); /// /// bincode::serialize_into(&mut io::stdout(), &cache) /// } /// # /// # fn main() { /// # print_encoded_cache().unwrap(); /// # } /// ``` #[derive(Eq, Ord)] #[cfg_attr(not(doc), repr(transparent))] pub struct Bytes { bytes: [u8], } impl Bytes { /// Wrap an existing `&[u8]`. pub fn new(bytes: &[u8]) -> &Self { unsafe { &*(bytes as *const [u8] as *const Bytes) } } } impl Debug for Bytes { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&self.bytes, f) } } impl AsRef<[u8]> for Bytes { fn as_ref(&self) -> &[u8] { &self.bytes } } impl AsMut<[u8]> for Bytes { fn as_mut(&mut self) -> &mut [u8] { &mut self.bytes } } impl Deref for Bytes { type Target = [u8]; fn deref(&self) -> &Self::Target { &self.bytes } } impl DerefMut for Bytes { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.bytes } } #[cfg(any(feature = "std", feature = "alloc"))] impl ToOwned for Bytes { type Owned = ByteBuf; fn to_owned(&self) -> Self::Owned { ByteBuf::from(&self.bytes) } } #[cfg(any(feature = "std", feature = "alloc"))] impl From> for Box { fn from(bytes: Box<[u8]>) -> Self { unsafe { Box::from_raw(Box::into_raw(bytes) as *mut Bytes) } } } impl<'a> Default for &'a Bytes { fn default() -> Self { Bytes::new(&[]) } } #[cfg(any(feature = "std", feature = "alloc"))] impl Default for Box { fn default() -> Self { ByteBuf::new().into_boxed_bytes() } } impl PartialEq for Bytes where Rhs: ?Sized + AsRef<[u8]>, { fn eq(&self, other: &Rhs) -> bool { self.as_ref().eq(other.as_ref()) } } impl PartialOrd for Bytes where Rhs: ?Sized + AsRef<[u8]>, { fn partial_cmp(&self, other: &Rhs) -> Option { self.as_ref().partial_cmp(other.as_ref()) } } impl Hash for Bytes { fn hash(&self, state: &mut H) { self.bytes.hash(state); } } impl<'a> IntoIterator for &'a Bytes { type Item = &'a u8; type IntoIter = <&'a [u8] as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.bytes.iter() } } impl<'a> IntoIterator for &'a mut Bytes { type Item = &'a mut u8; type IntoIter = <&'a mut [u8] as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.bytes.iter_mut() } } impl Serialize for Bytes { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_bytes(&self.bytes) } } impl<'a, 'de: 'a> Deserialize<'de> for &'a Bytes { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { // serde::Deserialize for &[u8] is already optimized, so simply forward to that. Deserialize::deserialize(deserializer).map(Bytes::new) } }