1use core::ops; 2 3/// A specialized copy-on-write byte string. 4/// 5/// The purpose of this type is to permit usage of a "borrowed or owned 6/// byte string" in a way that keeps std/no-std compatibility. That is, in 7/// no-std mode, this type devolves into a simple &[u8] with no owned variant 8/// available. We can't just use a plain Cow because Cow is not in core. 9#[derive(Clone, Debug)] 10pub struct CowBytes<'a>(Imp<'a>); 11 12// N.B. We don't use std::borrow::Cow here since we can get away with a 13// Box<[u8]> for our use case, which is 1/3 smaller than the Vec<u8> that 14// a Cow<[u8]> would use. 15#[cfg(feature = "std")] 16#[derive(Clone, Debug)] 17enum Imp<'a> { 18 Borrowed(&'a [u8]), 19 Owned(Box<[u8]>), 20} 21 22#[cfg(not(feature = "std"))] 23#[derive(Clone, Debug)] 24struct Imp<'a>(&'a [u8]); 25 26impl<'a> ops::Deref for CowBytes<'a> { 27 type Target = [u8]; 28 29 #[inline(always)] 30 fn deref(&self) -> &[u8] { 31 self.as_slice() 32 } 33} 34 35impl<'a> CowBytes<'a> { 36 /// Create a new borrowed CowBytes. 37 #[inline(always)] 38 pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &'a B) -> CowBytes<'a> { 39 CowBytes(Imp::new(bytes.as_ref())) 40 } 41 42 /// Create a new owned CowBytes. 43 #[cfg(feature = "std")] 44 #[inline(always)] 45 pub fn new_owned(bytes: Box<[u8]>) -> CowBytes<'static> { 46 CowBytes(Imp::Owned(bytes)) 47 } 48 49 /// Return a borrowed byte string, regardless of whether this is an owned 50 /// or borrowed byte string internally. 51 #[inline(always)] 52 pub fn as_slice(&self) -> &[u8] { 53 self.0.as_slice() 54 } 55 56 /// Return an owned version of this copy-on-write byte string. 57 /// 58 /// If this is already an owned byte string internally, then this is a 59 /// no-op. Otherwise, the internal byte string is copied. 60 #[cfg(feature = "std")] 61 #[inline(always)] 62 pub fn into_owned(self) -> CowBytes<'static> { 63 match self.0 { 64 Imp::Borrowed(b) => CowBytes::new_owned(Box::from(b)), 65 Imp::Owned(b) => CowBytes::new_owned(b), 66 } 67 } 68} 69 70impl<'a> Imp<'a> { 71 #[cfg(feature = "std")] 72 #[inline(always)] 73 pub fn new(bytes: &'a [u8]) -> Imp<'a> { 74 Imp::Borrowed(bytes) 75 } 76 77 #[cfg(not(feature = "std"))] 78 #[inline(always)] 79 pub fn new(bytes: &'a [u8]) -> Imp<'a> { 80 Imp(bytes) 81 } 82 83 #[cfg(feature = "std")] 84 #[inline(always)] 85 pub fn as_slice(&self) -> &[u8] { 86 match self { 87 Imp::Owned(ref x) => x, 88 Imp::Borrowed(x) => x, 89 } 90 } 91 92 #[cfg(not(feature = "std"))] 93 #[inline(always)] 94 pub fn as_slice(&self) -> &[u8] { 95 self.0 96 } 97} 98