use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use rustc_hash::FxHashMap;
#[derive(Debug, Clone, Eq)]
pub enum TokenBytes {
Static(&'static [u8]),
Owned(Box<[u8]>),
}
impl TokenBytes {
#[inline]
pub fn as_slice(&self) -> &[u8] {
match self {
TokenBytes::Static(b) => b,
TokenBytes::Owned(b) => b,
}
}
}
impl Deref for TokenBytes {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl Borrow<[u8]> for TokenBytes {
#[inline]
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl Hash for TokenBytes {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl PartialEq for TokenBytes {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl PartialEq<[u8]> for TokenBytes {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl From<Vec<u8>> for TokenBytes {
#[inline]
fn from(bytes: Vec<u8>) -> Self {
TokenBytes::Owned(bytes.into_boxed_slice())
}
}
impl From<&'static [u8]> for TokenBytes {
#[inline]
fn from(bytes: &'static [u8]) -> Self {
TokenBytes::Static(bytes)
}
}
impl AsRef<[u8]> for TokenBytes {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
pub type Encoder = FxHashMap<TokenBytes, u32>;
pub type Decoder = FxHashMap<u32, TokenBytes>;
pub fn encoder_from_owned(map: FxHashMap<Vec<u8>, u32>) -> Encoder {
map.into_iter()
.map(|(bytes, id)| (TokenBytes::from(bytes), id))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::hash_map::DefaultHasher;
fn hash_of<T: Hash + ?Sized>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
#[test]
fn hashes_identically_to_the_bare_slice() {
let bytes: &'static [u8] = b"hello";
assert_eq!(hash_of(&TokenBytes::Static(bytes)), hash_of(bytes));
assert_eq!(
hash_of(&TokenBytes::Owned(bytes.to_vec().into_boxed_slice())),
hash_of(bytes)
);
}
#[test]
fn static_and_owned_are_the_same_key() {
let static_key = TokenBytes::Static(b"token");
let owned_key = TokenBytes::from(b"token".to_vec());
assert_eq!(static_key, owned_key);
assert_eq!(hash_of(&static_key), hash_of(&owned_key));
let mut map: Encoder = Encoder::default();
map.insert(static_key, 7);
assert_eq!(map.get(&owned_key), Some(&7));
assert_eq!(
map.get(b"token".as_slice()),
Some(&7),
"slice lookup failed"
);
}
#[test]
fn lookup_by_slice_finds_both_variants() {
let mut map: Encoder = Encoder::default();
map.insert(TokenBytes::Static(b"a"), 1);
map.insert(TokenBytes::from(b"b".to_vec()), 2);
assert_eq!(map.get(b"a".as_slice()), Some(&1));
assert_eq!(map.get(b"b".as_slice()), Some(&2));
assert_eq!(map.get(b"c".as_slice()), None);
}
#[test]
fn the_empty_token_is_a_usable_key() {
let mut map: Encoder = Encoder::default();
map.insert(TokenBytes::Static(b""), 50256);
assert_eq!(map.get(b"".as_slice()), Some(&50256));
}
#[test]
fn owned_conversion_preserves_bytes() {
let key = TokenBytes::from(vec![0xE2, 0x96, 0x81]);
assert_eq!(key.as_slice(), &[0xE2, 0x96, 0x81]);
assert_eq!(&*key, &[0xE2, 0x96, 0x81]);
}
}