rune_core/item/
internal.rs

1use core::hash::{self, Hash};
2use core::str;
3
4use crate::alloc::alloc::Allocator;
5use crate::alloc::{self, Vec};
6
7// Types available.
8pub(super) const CRATE: Tag = Tag(0b00);
9pub(super) const STRING: Tag = Tag(0b01);
10pub(super) const ID: Tag = Tag(0b10);
11
12/// How many bits the type of a tag takes up.
13pub(super) const TYPE_BITS: usize = 2;
14/// Mask of the type of a tag.
15pub(super) const TYPE_MASK: usize = (0b1 << TYPE_BITS) - 1;
16/// Total tag size in bytes.
17pub(super) const TAG_BYTES: usize = 2;
18/// Max size of data stored.
19pub(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
25/// Read a single byte.
26///
27/// # Panics
28///
29/// Panics if the byte is not available.
30pub(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
40/// Helper function to write an identifier.
41///
42/// # Panics
43///
44/// Panics if the provided size cannot fit withing an identifier.
45pub(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
68/// Internal function to write only the crate of a component.
69pub(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
79/// Internal function to write only the string of a component.
80pub(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
90/// Internal function to hash the given string.
91pub(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    // consume the head tag.
103    let (tail_tag, content) = content.split_at(TAG_BYTES);
104
105    // Safety: we control the construction of the item.
106    let s = unsafe { str::from_utf8_unchecked(buf) };
107
108    (s, content, tail_tag)
109}