Skip to main content

chapter_tgz/
encode.rs

1use crate::decode;
2
3pub(crate) const MAX_BYTES_FINAL: usize = 28;
4pub(crate) const MAX_BYTES_NONFINAL: usize = 23;
5
6pub(crate) struct Bits {
7    bitpos: u8,
8    packed: [u8; MAX_BYTES_FINAL],
9}
10
11impl Bits {
12    pub(crate) const fn new() -> Self {
13        Bits {
14            bitpos: 0,
15            packed: [0u8; MAX_BYTES_FINAL],
16        }
17    }
18
19    pub(crate) const fn push(&mut self, val: u8, len: u8) {
20        self.packed[(self.bitpos / 8) as usize] |= val << (self.bitpos % 8);
21        if val.leading_zeros() < (self.bitpos % 8) as u32 {
22            self.packed[(self.bitpos / 8 + 1) as usize] |= val >> (8 - self.bitpos % 8);
23        }
24        self.bitpos += len;
25    }
26
27    pub(crate) fn as_slice(&self) -> &[u8] {
28        &self.packed[..self.bitpos.div_ceil(8) as usize]
29    }
30}
31
32macro_rules! push {
33    ($bits:ident, $($lit:literal)+) => {
34        $(
35            $bits.push(
36                const {
37                    match u8::from_str_radix(stringify!($lit), 2) {
38                        Ok(val) => val,
39                        Err(_) => panic!(),
40                    }
41                },
42                stringify!($lit).len() as u8,
43            );
44        )+
45    };
46}
47
48pub(crate) fn encode(bfinal: bool, payload: u64) -> Bits {
49    {
    match (&payload, &0) {
        (left_val, right_val) => {
            if *left_val == *right_val {
                let kind = ::core::panicking::AssertKind::Ne;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_ne!(payload, 0);
50
51    let mut bits = Bits::new();
52    bits.push(u8::from(bfinal), 1); // BFINAL
53    bits.push(const {
            match u8::from_str_radix("10", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "10".len() as u8);push!(bits, 10); // BTYPE (dynamic)
54    bits.push(const {
            match u8::from_str_radix("00000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "00000".len() as u8);push!(bits, 00000); // HLIT (257+0)
55    bits.push(const {
            match u8::from_str_radix("00000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "00000".len() as u8);push!(bits, 00000); // HDIST (1+0)
56    bits.push(const {
            match u8::from_str_radix("1110", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "1110".len() as u8);push!(bits, 1110); // HCLEN (4+14);
57
58    // Code lengths for the code length alphabet
59    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 16 -> none (copy the previous code length 3 - 6 times)
60    bits.push(const {
            match u8::from_str_radix("001", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "001".len() as u8);push!(bits, 001); // 17 -> '0' (repeat a code length of 0 for 3 - 10 times)
61    bits.push(const {
            match u8::from_str_radix("010", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "010".len() as u8);push!(bits, 010); // 18 -> '11' (repeat a code length of 0 for 11 - 138 times)
62    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 0 -> none
63    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 8 -> none
64    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 7 -> none
65    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 9 -> none
66    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 6 -> none
67    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 10 -> none
68    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 5 -> none
69    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 11 -> none
70    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 4 -> none
71    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 12 -> none
72    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 3 -> none
73    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 13 -> none
74    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 2 -> none
75    bits.push(const {
            match u8::from_str_radix("000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "000".len() as u8);push!(bits, 000); // 14 -> none
76    bits.push(const {
            match u8::from_str_radix("010", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "010".len() as u8);push!(bits, 010); // 1 -> '01'
77
78    /*
79    push!(bits, 000); // 15 -> none
80    */
81
82    // Code lengths for the literal/length alphabet
83    let mut rest = payload;
84    let mut zeros = 0;
85    while rest != 0 {
86        bits.push(const {
            match u8::from_str_radix("0", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "0".len() as u8);push!(bits, 0);
87        bits.push(rest as u8 & 0b111, 3);
88        zeros += 3 + (rest & 0b111);
89        rest >>= 3;
90    }
91    match zeros {
92        4..=97 => {
93            // two big repetitions, at least 21 zeros in the second; 18 bits
94            bits.push(const {
            match u8::from_str_radix("1111111", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "1111111".len() as u8);push!(bits, 11 1111111);
95            bits.push(const {
            match u8::from_str_radix("11", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "11".len() as u8);push!(bits, 11);
96            bits.push((256 - (zeros + 138) - 11) as u8, 7);
97        }
98        98..=107 => {
99            // one big, two little repetitions; 17 bits
100            bits.push(const {
            match u8::from_str_radix("11", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "11".len() as u8);push!(bits, 11);
101            bits.push((256 - (zeros + 20) - 11) as u8, 7);
102            bits.push(const {
            match u8::from_str_radix("111", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "111".len() as u8);push!(bits, 0 111);
103            bits.push(const {
            match u8::from_str_radix("111", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "111".len() as u8);push!(bits, 0 111);
104        }
105        108..=117 => {
106            // one big, one little repetition; 13 bits
107            bits.push(const {
            match u8::from_str_radix("11", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "11".len() as u8);push!(bits, 11);
108            bits.push((256 - (zeros + 10) - 11) as u8, 7);
109            bits.push(const {
            match u8::from_str_radix("111", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "111".len() as u8);push!(bits, 0 111);
110        }
111        118..=214 => {
112            // one big repetition; 9 bits
113            bits.push(const {
            match u8::from_str_radix("11", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "11".len() as u8);push!(bits, 11);
114            bits.push((256 - zeros - 11) as u8, 7);
115        }
116        0..=3 | 215.. => {
117            // payload=1 => zeros=4
118            // payload=max => zeros=214
119            ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
120        }
121    }
122
123    bits.push(const {
            match u8::from_str_radix("01", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "01".len() as u8);push!(bits, 01); // len=8 for symbol=256
124
125    // Code lengths for the distance alphabet
126    bits.push(const {
            match u8::from_str_radix("01", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "01".len() as u8);push!(bits, 01); // len=8 for distance=1
127
128    // End of block (symbol 256)
129    bits.push(const {
            match u8::from_str_radix("0", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "0".len() as u8);push!(bits, 0);
130
131    if !bits.as_slice().starts_with(&decode::prefix(bfinal)) {
    ::core::panicking::panic("assertion failed: bits.as_slice().starts_with(&decode::prefix(bfinal))")
};assert!(bits.as_slice().starts_with(&decode::prefix(bfinal)));
132
133    // Pad to a multiple of 8 bits
134    if !bfinal {
135        match bits.bitpos % 8 {
136            0 => {}
137            n @ (1..=5 | 7) => {
138                bits.push(const {
            match u8::from_str_radix("0", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "0".len() as u8);push!(bits, 0); // BFINAL
139                bits.push(const {
            match u8::from_str_radix("00", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "00".len() as u8);push!(bits, 00); // BTYPE (stored)
140                bits.push(0, (13 - n) % 8); // pad
141                bits.push(const {
            match u8::from_str_radix("00000000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "00000000".len() as u8);push!(bits, 00000000 00000000); // LEN
142                bits.push(const {
            match u8::from_str_radix("11111111", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "11111111".len() as u8);push!(bits, 11111111 11111111); // NLEN
143            }
144            6 => {
145                bits.push(const {
            match u8::from_str_radix("0", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "0".len() as u8);push!(bits, 0); // BFINAL
146                bits.push(const {
            match u8::from_str_radix("01", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "01".len() as u8);push!(bits, 01); // BTYPE (fixed)
147                bits.push(const {
            match u8::from_str_radix("0000000", 2) {
                Ok(val) => val,
                Err(_) => ::core::panicking::panic("explicit panic"),
            }
        }, "0000000".len() as u8);push!(bits, 0000000); // end-of-block
148            }
149            8.. => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
150        }
151    }
152
153    bits
154}