rusty_chunkenc/
chunks.rs

1use nom::{bytes::complete::tag, multi::many1, sequence::tuple, IResult};
2
3use crate::chunk::{read_chunk, Chunk};
4
5/// A Prometheus chunks disk format.
6///
7/// It contains a version number, always 1 for now, and a list of chunks.
8#[derive(Debug)]
9pub struct ChunksDiskFormat {
10    version: u8,
11    chunks: Vec<Chunk>,
12    file_index: Option<u64>,
13    addr: Option<*const u8>,
14}
15
16impl ChunksDiskFormat {
17    /// Creates a new chunks disk format with the given chunks and file index.
18    ///
19    /// The file index is used to compute the chunk references.
20    /// Set it to None if you don't use the chunk references.
21    pub fn new(chunks: Vec<Chunk>, file_index: Option<u64>) -> Self {
22        Self {
23            version: 1,
24            chunks,
25            file_index,
26            addr: None,
27        }
28    }
29
30    /// Returns the version number of the chunks disk format (always 1).
31    pub fn version(&self) -> u8 {
32        self.version
33    }
34
35    /// Returns the chunks.
36    pub fn chunks(&self) -> &[Chunk] {
37        &self.chunks
38    }
39
40    fn set_addr(&mut self, addr: *const u8) {
41        self.addr = Some(addr);
42    }
43
44    fn set_file_index(&mut self, file_index: u64) {
45        self.file_index = Some(file_index);
46    }
47
48    fn compute_chunk_refs(&mut self) {
49        let chunks_addr = match self.addr {
50            Some(addr) => addr,
51            None => return,
52        };
53        let file_index = match self.file_index {
54            Some(file_index) => file_index,
55            None => return,
56        };
57        for chunk in self.chunks.iter_mut() {
58            chunk.compute_chunk_ref(file_index, chunks_addr);
59        }
60    }
61}
62
63impl PartialEq for ChunksDiskFormat {
64    fn eq(&self, other: &Self) -> bool {
65        self.version == other.version
66            && self.chunks == other.chunks
67            && self.file_index == other.file_index
68    }
69}
70
71fn read_chunks_disk_format(input: &[u8]) -> IResult<&[u8], ChunksDiskFormat> {
72    let (remaining_input, (_, mut chunks_disk_format)) = tuple((
73        // Chunks on disk start with 0x85BD40DD
74        tag([0x85, 0xBD, 0x40, 0xDD]),
75        read_version_one,
76    ))(input)?;
77
78    chunks_disk_format.set_addr(input.as_ptr());
79
80    Ok((remaining_input, chunks_disk_format))
81}
82
83fn read_version_one(input: &[u8]) -> IResult<&[u8], ChunksDiskFormat> {
84    let (remaining_input, (_, _, chunks)) = tuple((
85        // Read the version byte, that is 1
86        tag([1u8]),
87        // 3 bytes of 0 for padding
88        tag([0u8; 3]),
89        // Chunks follow each other
90        many1(read_chunk),
91    ))(input)?;
92
93    Ok((
94        remaining_input,
95        ChunksDiskFormat {
96            version: 1,
97            chunks,
98            file_index: None,
99            addr: None,
100        },
101    ))
102}
103
104/// Reads the chunks disk format from the input data.
105///
106/// The file index is used to compute the chunk references.
107/// Set it to None, if you don't use the chunk references.
108///
109/// It returns the remaining input data and the chunks disk format.
110pub fn read_chunks(input: &[u8], file_index: Option<u64>) -> IResult<&[u8], ChunksDiskFormat> {
111    let (remaining_input, mut chunks_disk_format) = read_chunks_disk_format(input)?;
112    if let Some(file_index) = file_index {
113        chunks_disk_format.set_file_index(file_index);
114    }
115    chunks_disk_format.compute_chunk_refs();
116    Ok((remaining_input, chunks_disk_format))
117}