Skip to main content

modelvault_core/segments/
writer.rs

1//! Append [`SegmentHeader`] + payload bytes to a [`crate::storage::Store`], maintaining a running write cursor.
2//!
3//! Used by publish and write paths to extend the segment log; header fields `payload_len` and
4//! `payload_crc32c` are filled from `payload` before encoding.
5
6use crate::checksum::crc32c;
7use crate::error::DbError;
8use crate::segments::header::SegmentHeader;
9use crate::storage::Store;
10
11/// Sequential segment writer: holds the store and the next byte offset to write.
12pub struct SegmentWriter<'a, S: Store> {
13    store: &'a mut S,
14    offset: u64,
15}
16
17impl<'a, S: Store> SegmentWriter<'a, S> {
18    /// Start writing at `offset` (usually current file length or `segment_start`).
19    pub fn new(store: &'a mut S, offset: u64) -> Self {
20        Self { store, offset }
21    }
22
23    /// Current end offset (next write starts here).
24    pub fn offset(&self) -> u64 {
25        self.offset
26    }
27
28    /// Write one segment: encoded header (with `payload_len` / CRC filled from `payload`), then `payload`.
29    ///
30    /// Returns the **start** offset of this segment (where the header began).
31    pub fn append(&mut self, header: SegmentHeader, payload: &[u8]) -> Result<u64, DbError> {
32        let header = SegmentHeader {
33            payload_len: payload.len() as u64,
34            payload_crc32c: crc32c(payload),
35            ..header
36        };
37        let encoded = header.encode();
38
39        let start = self.offset;
40        self.store.write_all_at(self.offset, &encoded)?;
41        self.offset += encoded.len() as u64;
42        self.store.write_all_at(self.offset, payload)?;
43        self.offset += payload.len() as u64;
44
45        Ok(start)
46    }
47}