1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 use core::borrow::Borrow; 6 7 #[cfg(feature = "serde")] 8 use alloc::boxed::Box; 9 10 /// A struct transparent over `[u8]` with convenient helper functions. 11 #[repr(transparent)] 12 #[derive(PartialEq, Eq, PartialOrd, Ord)] 13 pub(crate) struct ByteStr([u8]); 14 15 impl ByteStr { from_byte_slice_with_value<'a, 'l>( input: &'l [(&'a [u8], usize)], ) -> &'l [(&'a ByteStr, usize)]16 pub const fn from_byte_slice_with_value<'a, 'l>( 17 input: &'l [(&'a [u8], usize)], 18 ) -> &'l [(&'a ByteStr, usize)] { 19 // Safety: [u8] and ByteStr have the same layout and invariants 20 unsafe { core::mem::transmute(input) } 21 } 22 from_str_slice_with_value<'a, 'l>( input: &'l [(&'a str, usize)], ) -> &'l [(&'a ByteStr, usize)]23 pub const fn from_str_slice_with_value<'a, 'l>( 24 input: &'l [(&'a str, usize)], 25 ) -> &'l [(&'a ByteStr, usize)] { 26 // Safety: str and ByteStr have the same layout, and ByteStr is less restrictive 27 unsafe { core::mem::transmute(input) } 28 } 29 from_bytes(input: &[u8]) -> &Self30 pub fn from_bytes(input: &[u8]) -> &Self { 31 // Safety: [u8] and ByteStr have the same layout and invariants 32 unsafe { core::mem::transmute(input) } 33 } 34 35 #[cfg(feature = "serde")] from_boxed_bytes(input: Box<[u8]>) -> Box<Self>36 pub fn from_boxed_bytes(input: Box<[u8]>) -> Box<Self> { 37 // Safety: [u8] and ByteStr have the same layout and invariants 38 unsafe { core::mem::transmute(input) } 39 } 40 41 #[allow(dead_code)] // may want this in the future from_str(input: &str) -> &Self42 pub fn from_str(input: &str) -> &Self { 43 Self::from_bytes(input.as_bytes()) 44 } 45 46 #[allow(dead_code)] // may want this in the future empty() -> &'static Self47 pub fn empty() -> &'static Self { 48 Self::from_bytes(&[]) 49 } 50 51 #[allow(dead_code)] // not used in all features as_bytes(&self) -> &[u8]52 pub const fn as_bytes(&self) -> &[u8] { 53 &self.0 54 } 55 len(&self) -> usize56 pub const fn len(&self) -> usize { 57 self.0.len() 58 } 59 60 #[allow(dead_code)] // not used in all features is_all_ascii(&self) -> bool61 pub fn is_all_ascii(&self) -> bool { 62 for byte in self.0.iter() { 63 if !byte.is_ascii() { 64 return false; 65 } 66 } 67 true 68 } 69 70 #[allow(dead_code)] // may want this in the future byte_at(&self, index: usize) -> Option<u8>71 pub(crate) fn byte_at(&self, index: usize) -> Option<u8> { 72 self.0.get(index).copied() 73 } 74 75 /// Returns the byte at the given index, panicking if out of bounds. byte_at_or_panic(&self, index: usize) -> u876 pub(crate) const fn byte_at_or_panic(&self, index: usize) -> u8 { 77 self.0[index] 78 } 79 80 /// Const function to evaluate `self < other`. is_less_then(&self, other: &Self) -> bool81 pub(crate) const fn is_less_then(&self, other: &Self) -> bool { 82 let mut i = 0; 83 while i < self.len() && i < other.len() { 84 if self.0[i] < other.0[i] { 85 return true; 86 } 87 if self.0[i] > other.0[i] { 88 return false; 89 } 90 i += 1; 91 } 92 self.len() < other.len() 93 } 94 95 /// Const function to evaluate `self[..prefix_len] == other[..prefix_len]` prefix_eq(&self, other: &ByteStr, prefix_len: usize) -> bool96 pub(crate) const fn prefix_eq(&self, other: &ByteStr, prefix_len: usize) -> bool { 97 assert!(prefix_len <= self.len()); 98 assert!(prefix_len <= other.len()); 99 let mut i = 0; 100 while i < prefix_len { 101 if self.0[i] != other.0[i] { 102 return false; 103 } 104 i += 1; 105 } 106 true 107 } 108 } 109 110 impl Borrow<[u8]> for ByteStr { borrow(&self) -> &[u8]111 fn borrow(&self) -> &[u8] { 112 self.as_bytes() 113 } 114 } 115 116 #[cfg(feature = "alloc")] 117 impl Borrow<[u8]> for alloc::boxed::Box<ByteStr> { borrow(&self) -> &[u8]118 fn borrow(&self) -> &[u8] { 119 self.as_bytes() 120 } 121 } 122