firmion_output_buffer/output_buffer.rs
1// Output buffer abstraction for creating the raw binary image.
2//
3// OutputBuffer accumulates the binary image in a Vec<u8> during the exec
4// phase. Sequential append operations build the image in pass 1; random-
5// access patch writes let extensions overwrite their pre-reserved zero-filled
6// slots in pass 2. The completed image is written to disk in a single call.
7//
8
9// Don't clutter upstream docs.rs for an otherwise private library.
10#![doc(hidden)]
11
12use std::fs::File;
13use std::io::{self, Read, Write};
14
15pub struct OutputBuffer {
16 data: Vec<u8>,
17}
18
19impl Default for OutputBuffer {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl OutputBuffer {
26 pub fn new() -> Self {
27 Self { data: Vec::new() }
28 }
29
30 /// Appends bytes to the buffer. Infallible.
31 pub fn append(&mut self, bytes: &[u8]) {
32 self.data.extend_from_slice(bytes);
33 }
34
35 /// Appends count zero bytes. Infallible.
36 /// Reserves space for extension output slots before pass 2 patches them.
37 pub fn append_zeros(&mut self, count: usize) {
38 self.data.resize(self.data.len() + count, 0);
39 }
40
41 /// Reads exactly byte_count bytes from source and appends them.
42 /// Caller seeks source to the correct file position before calling.
43 pub fn append_from_file(&mut self, source: &mut File, byte_count: u64) -> io::Result<()> {
44 let start = self.data.len();
45 self.data.resize(start + byte_count as usize, 0);
46 source.read_exact(&mut self.data[start..])?;
47 Ok(())
48 }
49
50 /// Returns a slice of the buffer at [start..end].
51 /// Used to build ParamArg::Slice values for extension Slice params.
52 pub fn slice(&self, start: usize, end: usize) -> &[u8] {
53 &self.data[start..end]
54 }
55
56 /// Overwrites the bytes at offset with data.
57 /// Used by execute_extensions to patch extension output into the image.
58 /// Panics if offset + data.len() exceeds len(): the caller guarantees
59 /// the slot was pre-reserved, so out-of-bounds is a compiler bug.
60 pub fn patch(&mut self, offset: usize, data: &[u8]) {
61 self.data[offset..offset + data.len()].copy_from_slice(data);
62 }
63
64 /// Returns the current byte count.
65 pub fn len(&self) -> usize {
66 self.data.len()
67 }
68
69 /// Returns true when the buffer holds no bytes.
70 pub fn is_empty(&self) -> bool {
71 self.data.is_empty()
72 }
73
74 /// Writes the entire buffer to file in one call.
75 pub fn write_to_file(&self, file: &mut File) -> io::Result<()> {
76 file.write_all(&self.data)
77 }
78}