rusty_chunkenc/
chunks.rs

1use nom::{bytes::complete::tag, multi::many1, IResult, Parser};
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)) = (
73        // Chunks on disk start with 0x85BD40DD
74        tag(&[0x85, 0xBD, 0x40, 0xDD][..]),
75        read_version_one,
76    )
77        .parse(input)?;
78
79    chunks_disk_format.set_addr(input.as_ptr());
80
81    Ok((remaining_input, chunks_disk_format))
82}
83
84fn read_version_one(input: &[u8]) -> IResult<&[u8], ChunksDiskFormat> {
85    let (remaining_input, (_, _, chunks)) = (
86        // Read the version byte, that is 1
87        tag(&[1u8][..]),
88        // 3 bytes of 0 for padding
89        tag(&[0u8; 3][..]),
90        // Chunks follow each other
91        many1(read_chunk),
92    )
93        .parse(input)?;
94
95    Ok((
96        remaining_input,
97        ChunksDiskFormat {
98            version: 1,
99            chunks,
100            file_index: None,
101            addr: None,
102        },
103    ))
104}
105
106/// Reads the chunks disk format from the input data.
107///
108/// The file index is used to compute the chunk references.
109/// Set it to None, if you don't use the chunk references.
110///
111/// It returns the remaining input data and the chunks disk format.
112pub fn read_chunks(input: &[u8], file_index: Option<u64>) -> IResult<&[u8], ChunksDiskFormat> {
113    let (remaining_input, mut chunks_disk_format) = read_chunks_disk_format(input)?;
114    if let Some(file_index) = file_index {
115        chunks_disk_format.set_file_index(file_index);
116    }
117    chunks_disk_format.compute_chunk_refs();
118    Ok((remaining_input, chunks_disk_format))
119}