zerotrie/builder/
bytestr.rs

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
5use core::borrow::Borrow;
6
7#[cfg(feature = "serde")]
8use alloc::boxed::Box;
9
10/// A struct transparent over `[u8]` with convenient helper functions.
11#[repr(transparent)]
12#[derive(PartialEq, Eq, PartialOrd, Ord)]
13pub(crate) struct ByteStr([u8]);
14
15impl ByteStr {
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
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
30    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")]
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
42    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
47    pub fn empty() -> &'static Self {
48        Self::from_bytes(&[])
49    }
50
51    #[allow(dead_code)] // not used in all features
52    pub const fn as_bytes(&self) -> &[u8] {
53        &self.0
54    }
55
56    pub const fn len(&self) -> usize {
57        self.0.len()
58    }
59
60    #[allow(dead_code)] // not used in all features
61    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
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.
76    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`.
81    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]`
96    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
110impl Borrow<[u8]> for ByteStr {
111    fn borrow(&self) -> &[u8] {
112        self.as_bytes()
113    }
114}
115
116#[cfg(feature = "alloc")]
117impl Borrow<[u8]> for alloc::boxed::Box<ByteStr> {
118    fn borrow(&self) -> &[u8] {
119        self.as_bytes()
120    }
121}