rune_core/item/
internal.rs1use core::hash::{self, Hash};
2use core::str;
3
4use crate::alloc::alloc::Allocator;
5use crate::alloc::{self, Vec};
6
7pub(super) const CRATE: Tag = Tag(0b00);
9pub(super) const STRING: Tag = Tag(0b01);
10pub(super) const ID: Tag = Tag(0b10);
11
12pub(super) const TYPE_BITS: usize = 2;
14pub(super) const TYPE_MASK: usize = (0b1 << TYPE_BITS) - 1;
16pub(super) const TAG_BYTES: usize = 2;
18pub(super) const MAX_DATA: usize = 0b1 << (TAG_BYTES * 8 - TYPE_BITS);
20
21#[derive(PartialEq, Eq, Hash)]
22#[repr(transparent)]
23pub(super) struct Tag(pub(super) u8);
24
25pub(super) fn read_tag(content: &[u8]) -> (Tag, usize) {
31 let &[a, b] = content else {
32 panic!("expected two bytes");
33 };
34
35 let n = u16::from_ne_bytes([a, b]);
36 let n = usize::from(n);
37 (Tag((n & TYPE_MASK) as u8), n >> TYPE_BITS)
38}
39
40pub(super) fn write_tag<A>(output: &mut Vec<u8, A>, Tag(tag): Tag, n: usize) -> alloc::Result<()>
46where
47 A: Allocator,
48{
49 let tag = usize::from(tag);
50
51 debug_assert!(tag <= TYPE_MASK);
52
53 debug_assert!(
54 n < MAX_DATA,
55 "item data overflow, index or string size larger than MAX_DATA"
56 );
57
58 if n >= MAX_DATA {
59 return Err(alloc::Error::CapacityOverflow);
60 }
61
62 let n = u16::try_from((n << TYPE_BITS) | tag).expect("tag out of bounds");
63 let buf = n.to_ne_bytes();
64 output.try_extend_from_slice(&buf[..])?;
65 Ok(())
66}
67
68pub(super) fn write_crate<A>(s: &str, output: &mut Vec<u8, A>) -> alloc::Result<()>
70where
71 A: Allocator,
72{
73 write_tag(output, CRATE, s.len())?;
74 output.try_extend_from_slice(s.as_bytes())?;
75 write_tag(output, CRATE, s.len())?;
76 Ok(())
77}
78
79pub(super) fn write_str<A>(s: &str, output: &mut Vec<u8, A>) -> alloc::Result<()>
81where
82 A: Allocator,
83{
84 write_tag(output, STRING, s.len())?;
85 output.try_extend_from_slice(s.as_bytes())?;
86 write_tag(output, STRING, s.len())?;
87 Ok(())
88}
89
90pub(super) fn hash_str<H>(string: &str, hasher: &mut H)
92where
93 H: hash::Hasher,
94{
95 STRING.hash(hasher);
96 string.hash(hasher);
97}
98
99pub(super) fn read_string(content: &[u8], n: usize) -> (&str, &[u8], &[u8]) {
100 let (buf, content) = content.split_at(n);
101
102 let (tail_tag, content) = content.split_at(TAG_BYTES);
104
105 let s = unsafe { str::from_utf8_unchecked(buf) };
107
108 (s, content, tail_tag)
109}