-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathaligned_vec.rs
More file actions
111 lines (95 loc) · 2.97 KB
/
aligned_vec.rs
File metadata and controls
111 lines (95 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! 64-byte aligned storage for bytecode.
//!
//! Bytecode sections are 64-byte aligned internally. For this alignment to be
//! meaningful at runtime, the buffer itself must start at a 64-byte boundary.
//! Standard `Vec<u8>` provides no alignment guarantees for `u8`.
use std::ops::Deref;
/// Alignment for bytecode buffers (matches `SECTION_ALIGN`).
pub const ALIGN: usize = 64;
/// 64-byte aligned block for bytecode storage.
#[repr(C, align(64))]
#[derive(Clone, Copy)]
struct Block([u8; 64]);
/// Immutable 64-byte aligned byte storage.
///
/// Uses `Vec<Block>` internally — Vec guarantees element alignment,
/// so the data starts at a 64-byte boundary. No custom allocator needed.
pub struct AlignedVec {
blocks: Vec<Block>,
len: usize,
}
impl AlignedVec {
/// Copy bytes into aligned storage.
pub fn copy_from_slice(bytes: &[u8]) -> Self {
if bytes.is_empty() {
return Self {
blocks: Vec::new(),
len: 0,
};
}
let num_blocks = bytes.len().div_ceil(64);
let mut blocks = vec![Block([0; 64]); num_blocks];
// Copy block by block to stay safe
for (i, chunk) in bytes.chunks(64).enumerate() {
blocks[i].0[..chunk.len()].copy_from_slice(chunk);
}
Self {
blocks,
len: bytes.len(),
}
}
/// Read a file into aligned storage.
pub fn from_file(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
let bytes = std::fs::read(path)?;
Ok(Self::copy_from_slice(&bytes))
}
/// Number of bytes stored.
pub fn len(&self) -> usize {
self.len
}
/// Check if empty.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// View as byte slice.
pub fn as_slice(&self) -> &[u8] {
if self.blocks.is_empty() {
return &[];
}
if self.len > self.blocks.len() * 64 {
panic!(
"AlignedVec invariant violated: len {} exceeds capacity {}",
self.len,
self.blocks.len() * 64
);
}
// SAFETY: Block is repr(C) with only [u8; 64], so pointer cast is valid.
// We only expose `len` bytes, which were initialized in copy_from_slice.
unsafe { std::slice::from_raw_parts(self.blocks.as_ptr() as *const u8, self.len) }
}
}
impl Deref for AlignedVec {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl Clone for AlignedVec {
fn clone(&self) -> Self {
Self {
blocks: self.blocks.clone(),
len: self.len,
}
}
}
impl std::fmt::Debug for AlignedVec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AlignedVec")
.field("len", &self.len)
.field(
"aligned",
&(self.blocks.as_ptr() as usize).is_multiple_of(ALIGN),
)
.finish()
}
}