rune_core/item/
internal.rsuse core::hash::{self, Hash};
use core::str;
use crate::alloc::alloc::Allocator;
use crate::alloc::{self, Vec};
pub(super) const CRATE: Tag = Tag(0b00);
pub(super) const STRING: Tag = Tag(0b01);
pub(super) const ID: Tag = Tag(0b10);
pub(super) const TYPE_BITS: usize = 2;
pub(super) const TYPE_MASK: usize = (0b1 << TYPE_BITS) - 1;
pub(super) const TAG_BYTES: usize = 2;
pub(super) const MAX_DATA: usize = 0b1 << (TAG_BYTES * 8 - TYPE_BITS);
#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
pub(super) struct Tag(pub(super) u8);
pub(super) fn read_tag(content: &[u8]) -> (Tag, usize) {
let &[a, b] = content else {
panic!("expected two bytes");
};
let n = u16::from_ne_bytes([a, b]);
let n = usize::from(n);
(Tag((n & TYPE_MASK) as u8), n >> TYPE_BITS)
}
pub(super) fn write_tag<A: Allocator>(
output: &mut Vec<u8, A>,
Tag(tag): Tag,
n: usize,
) -> alloc::Result<()> {
let tag = usize::from(tag);
debug_assert!(tag <= TYPE_MASK);
debug_assert!(
n < MAX_DATA,
"item data overflow, index or string size larger than MAX_DATA"
);
if n >= MAX_DATA {
return Err(alloc::Error::CapacityOverflow);
}
let n = u16::try_from(n << TYPE_BITS | tag).expect("tag out of bounds");
let buf = n.to_ne_bytes();
output.try_extend_from_slice(&buf[..])?;
Ok(())
}
pub(super) fn write_crate<A: Allocator>(s: &str, output: &mut Vec<u8, A>) -> alloc::Result<()> {
write_tag(output, CRATE, s.len())?;
output.try_extend_from_slice(s.as_bytes())?;
write_tag(output, CRATE, s.len())?;
Ok(())
}
pub(super) fn write_str<A: Allocator>(s: &str, output: &mut Vec<u8, A>) -> alloc::Result<()> {
write_tag(output, STRING, s.len())?;
output.try_extend_from_slice(s.as_bytes())?;
write_tag(output, STRING, s.len())?;
Ok(())
}
pub(super) fn hash_str<H>(string: &str, hasher: &mut H)
where
H: hash::Hasher,
{
STRING.hash(hasher);
string.hash(hasher);
}
pub(super) fn read_string(content: &[u8], n: usize) -> (&str, &[u8], &[u8]) {
let (buf, content) = content.split_at(n);
let (tail_tag, content) = content.split_at(TAG_BYTES);
let s = unsafe { str::from_utf8_unchecked(buf) };
(s, content, tail_tag)
}