1 use 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)] 10 pub 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)] 17 enum Imp<'a> { 18 Borrowed(&'a [u8]), 19 Owned(Box<[u8]>), 20 } 21 22 #[cfg(not(feature = "std"))] 23 #[derive(Clone, Debug)] 24 struct Imp<'a>(&'a [u8]); 25 26 impl<'a> ops::Deref for CowBytes<'a> { 27 type Target = [u8]; 28 29 #[inline(always)] deref(&self) -> &[u8]30 fn deref(&self) -> &[u8] { 31 self.as_slice() 32 } 33 } 34 35 impl<'a> CowBytes<'a> { 36 /// Create a new borrowed CowBytes. 37 #[inline(always)] new<B: ?Sized + AsRef<[u8]>>(bytes: &'a B) -> CowBytes<'a>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)] new_owned(bytes: Box<[u8]>) -> CowBytes<'static>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)] as_slice(&self) -> &[u8]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)] into_owned(self) -> CowBytes<'static>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 70 impl<'a> Imp<'a> { 71 #[cfg(feature = "std")] 72 #[inline(always)] new(bytes: &'a [u8]) -> Imp<'a>73 pub fn new(bytes: &'a [u8]) -> Imp<'a> { 74 Imp::Borrowed(bytes) 75 } 76 77 #[cfg(not(feature = "std"))] 78 #[inline(always)] new(bytes: &'a [u8]) -> Imp<'a>79 pub fn new(bytes: &'a [u8]) -> Imp<'a> { 80 Imp(bytes) 81 } 82 83 #[cfg(feature = "std")] 84 #[inline(always)] as_slice(&self) -> &[u8]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)] as_slice(&self) -> &[u8]94 pub fn as_slice(&self) -> &[u8] { 95 self.0 96 } 97 } 98