Skip to main content

hash_roll/
pigz.rs

1#![cfg(feature = "pigz")]
2use crate::{Chunk, ChunkIncr, ToChunkIncr};
3
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct PigzRsyncable {
6    bits: u8,
7
8    /// directly derived from `bits`
9    mask: u32,
10    /// directly derived from `mask`
11    hit: u32,
12}
13
14impl PigzRsyncable {
15    pub fn with_bits(bits: u8) -> PigzRsyncable {
16        let mask = (1 << bits) - 1;
17        let hit = mask >> 1;
18        PigzRsyncable { bits, mask, hit }
19    }
20}
21
22impl Default for PigzRsyncable {
23    fn default() -> Self {
24        Self::with_bits(12)
25    }
26}
27
28impl Chunk for PigzRsyncable {
29    type SearchState = PigzRsyncableSearchState;
30
31    fn to_search_state(&self) -> Self::SearchState {
32        self.into()
33    }
34
35    fn find_chunk_edge(
36        &self,
37        state: &mut Self::SearchState,
38        data: &[u8],
39    ) -> (Option<usize>, usize) {
40        for i in 0..data.len() {
41            let v = data[i];
42
43            if state.state.add(self, v) {
44                *state = self.to_search_state();
45                return (Some(i + 1), i + 1);
46            }
47        }
48
49        (None, data.len())
50    }
51}
52
53impl From<&PigzRsyncable> for PigzRsyncableIncr {
54    fn from(src: &PigzRsyncable) -> Self {
55        src.clone().into()
56    }
57}
58
59impl ToChunkIncr for PigzRsyncable {
60    type Incr = PigzRsyncableIncr;
61    fn to_chunk_incr(&self) -> Self::Incr {
62        self.into()
63    }
64}
65
66#[derive(Debug, Clone)]
67struct PigzRsyncableState {
68    hash: u32,
69}
70
71impl From<&PigzRsyncable> for PigzRsyncableState {
72    fn from(params: &PigzRsyncable) -> Self {
73        PigzRsyncableState { hash: params.hit }
74    }
75}
76
77/// Intermediate state for [`PigzRsyncable::find_chunk_edge`]
78///
79/// Using this avoids re-computation of data when no edge is found
80#[derive(Debug, Clone)]
81pub struct PigzRsyncableSearchState {
82    state: PigzRsyncableState,
83}
84
85impl From<&PigzRsyncable> for PigzRsyncableSearchState {
86    fn from(params: &PigzRsyncable) -> Self {
87        PigzRsyncableSearchState {
88            state: params.into(),
89        }
90    }
91}
92
93/// Provides an incremental interface to [`PigzRsyncable`]
94///
95/// Performance Note: [`PigzRsyncable`] requires look-back. As a result, [`PigzRsyncableIncr`] internally
96/// buffers data up to the window size. This additional copying may affect performance. If
97/// possible for your use case, use the non-incremental interface.
98///
99/// See [`PigzRsyncable`] for details on the underlying algorithm
100#[derive(Debug, Clone)]
101pub struct PigzRsyncableIncr {
102    params: PigzRsyncable,
103    state: PigzRsyncableState,
104}
105
106impl PigzRsyncableIncr {}
107
108impl From<PigzRsyncable> for PigzRsyncableIncr {
109    fn from(params: PigzRsyncable) -> Self {
110        let state = (&params).into();
111        PigzRsyncableIncr { params, state }
112    }
113}
114
115impl PigzRsyncableState {
116    fn add(&mut self, parent: &PigzRsyncable, v: u8) -> bool {
117        self.hash = ((self.hash << 1) ^ (v as u32)) & parent.mask;
118        self.hash == parent.hit
119    }
120}
121
122impl ChunkIncr for PigzRsyncableIncr {
123    fn push(&mut self, data: &[u8]) -> Option<usize> {
124        for (i, &v) in data.iter().enumerate() {
125            if self.state.add(&self.params, v) {
126                self.state = (&self.params).into();
127                return Some(i + 1);
128            }
129        }
130
131        None
132    }
133}