summaryrefslogtreecommitdiffstats
path: root/third_party/rust/neqo-qpack/src/prefix.rs
blob: 0085de0df91814aa148217e8d0930adddb201352 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Copy, Clone, Debug)]
pub struct Prefix {
    #[allow(unknown_lints)] // available with Rust v1.75
    #[allow(clippy::struct_field_names)]
    prefix: u8,
    len: u8,
    mask: u8,
}

impl Prefix {
    pub fn new(prefix: u8, len: u8) -> Self {
        // len should never be larger than 7.
        // Most of Prefixes are instantiated as consts bellow. The only place where this
        // construcrtor is used is in tests and when literals are encoded and the Huffman
        // bit is added to one of the consts bellow. create_prefix guaranty that all const
        // have len < 7 so we can safely assert that len is <=7.
        assert!(len <= 7);
        assert!((len == 0) || (prefix & ((1 << (8 - len)) - 1) == 0));
        Self {
            prefix,
            len,
            mask: if len == 0 {
                0xFF
            } else {
                ((1 << len) - 1) << (8 - len)
            },
        }
    }

    pub fn len(self) -> u8 {
        self.len
    }

    pub fn prefix(self) -> u8 {
        self.prefix
    }

    pub fn cmp_prefix(self, b: u8) -> bool {
        (b & self.mask) == self.prefix
    }
}

#[macro_export]
macro_rules! create_prefix {
    ($n:ident) => {
        pub const $n: Prefix = Prefix {
            prefix: 0x0,
            len: 0,
            mask: 0xFF,
        };
    };
    ($n:ident, $v:expr, $l:expr) => {
        static_assertions::const_assert!($l < 7);
        static_assertions::const_assert!($v & ((1 << (8 - $l)) - 1) == 0);
        pub const $n: Prefix = Prefix {
            prefix: $v,
            len: $l,
            mask: ((1 << $l) - 1) << (8 - $l),
        };
    };
    ($n:ident, $v:expr, $l:expr, $m:expr) => {
        static_assertions::const_assert!($l < 7);
        static_assertions::const_assert!($v & ((1 << (8 - $l)) - 1) == 0);
        static_assertions::const_assert!((((1 << $l) - 1) << (8 - $l)) >= $m);
        pub const $n: Prefix = Prefix {
            prefix: $v,
            len: $l,
            mask: $m,
        };
    };
}

create_prefix!(NO_PREFIX);
//=====================================================================
// Decoder instructions prefix
//=====================================================================

// | 1 |      Stream ID (7+)       |
create_prefix!(DECODER_HEADER_ACK, 0x80, 1);

// | 0 | 1 |     Stream ID (6+)    |
create_prefix!(DECODER_STREAM_CANCELLATION, 0x40, 2);

// | 0 | 0 |     Increment (6+)    |
create_prefix!(DECODER_INSERT_COUNT_INCREMENT, 0x00, 2);

//=====================================================================
// Encoder instructions prefix
//=====================================================================

// | 0 | 0 | 1 |   Capacity (5+)   |
create_prefix!(ENCODER_CAPACITY, 0x20, 3);

// | 1 | T |    Name Index (6+)    |
// T == 1 static
// T == 0 dynamic
create_prefix!(ENCODER_INSERT_WITH_NAME_REF_STATIC, 0xC0, 2);
create_prefix!(ENCODER_INSERT_WITH_NAME_REF_DYNAMIC, 0x80, 2);

// | 0 | 1 | H | Name Length (5+)  |
// H is not relevant for decoding this prefix, therefore the mask is 1100 0000 = 0xC0
create_prefix!(ENCODER_INSERT_WITH_NAME_LITERAL, 0x40, 2);

// | 0 | 0 | 0 |    Index (5+)     |
create_prefix!(ENCODER_DUPLICATE, 0x00, 3);

//=====================================================================
// Header block encoding prefixes
//=====================================================================

create_prefix!(BASE_PREFIX_POSITIVE, 0x00, 1);
create_prefix!(BASE_PREFIX_NEGATIVE, 0x80, 1);

// | 1 | T |  index(6+) |
// T == 1 static
// T == 0 dynamic
create_prefix!(HEADER_FIELD_INDEX_STATIC, 0xC0, 2);
create_prefix!(HEADER_FIELD_INDEX_DYNAMIC, 0x80, 2);

// | 0 | 0 | 0 | 1 |  Index(4+) |
create_prefix!(HEADER_FIELD_INDEX_DYNAMIC_POST, 0x10, 4);

// | 0 | 1 | N | T |  Index(4+) |
// T == 1 static
// T == 0 dynamic
// N is ignored, therefore the mask is 1101 0000 = 0xD0
create_prefix!(HEADER_FIELD_LITERAL_NAME_REF_STATIC, 0x50, 4, 0xD0);
create_prefix!(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC, 0x40, 4, 0xD0);

// | 0 | 0 | 0 | 0 | N |  Index(3+) |
// N is ignored, therefore the mask is 1111 0000 = 0xF0
create_prefix!(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST, 0x00, 5, 0xF0);

// | 0 | 0 | 1 | N | H |  Index(3+) |
// N is ignored and H is not relevant for decoding this prefix, therefore the mask is 1110 0000 =
// 0xE0
create_prefix!(HEADER_FIELD_LITERAL_NAME_LITERAL, 0x20, 4, 0xE0);