httproxide_h3/qpack/
vas.rs1pub type RelativeIndex = usize;
71pub type AbsoluteIndex = usize;
72
73#[derive(Debug, PartialEq)]
74pub enum Error {
75 RelativeIndex(usize),
76 PostbaseIndex(usize),
77 Index(usize),
78}
79
80#[derive(Debug, Default)]
81pub struct VirtualAddressSpace {
82 inserted: usize,
83 dropped: usize,
84 delta: usize,
85}
86
87impl VirtualAddressSpace {
88 pub fn add(&mut self) -> AbsoluteIndex {
89 self.inserted += 1;
90 self.delta += 1;
91 self.inserted
92 }
93
94 pub fn drop(&mut self) {
95 self.dropped += 1;
96 self.delta -= 1;
97 }
98
99 pub fn relative(&self, index: RelativeIndex) -> Result<usize, Error> {
100 if self.inserted < index || self.delta == 0 || self.inserted - index <= self.dropped {
101 Err(Error::RelativeIndex(index))
102 } else {
103 Ok(self.inserted - self.dropped - index - 1)
104 }
105 }
106
107 pub fn evicted(&self, index: AbsoluteIndex) -> bool {
108 index != 0 && index <= self.dropped
109 }
110
111 pub fn relative_base(&self, base: usize, index: RelativeIndex) -> Result<usize, Error> {
112 if self.delta == 0 || index > base || base - index <= self.dropped {
113 Err(Error::RelativeIndex(index))
114 } else {
115 Ok(base - self.dropped - index - 1)
116 }
117 }
118
119 pub fn post_base(&self, base: usize, index: RelativeIndex) -> Result<usize, Error> {
120 if self.delta == 0 || base + index >= self.inserted || base + index < self.dropped {
121 Err(Error::PostbaseIndex(index))
122 } else {
123 Ok(base + index - self.dropped)
124 }
125 }
126
127 pub fn index(&self, index: usize) -> Result<usize, Error> {
128 if index >= self.delta {
129 Err(Error::Index(index))
130 } else {
131 Ok(index + self.dropped + 1)
132 }
133 }
134
135 pub fn largest_ref(&self) -> usize {
136 self.inserted - self.dropped
137 }
138
139 pub fn total_inserted(&self) -> usize {
140 self.inserted
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use proptest::proptest;
148
149 #[test]
150 fn test_no_relative_index_when_empty() {
151 let vas = VirtualAddressSpace::default();
152 let res = vas.relative_base(0, 0);
153 assert_eq!(res, Err(Error::RelativeIndex(0)));
154 }
155
156 #[test]
157 fn test_relative_underflow_protected() {
158 let mut vas = VirtualAddressSpace::default();
159 vas.add();
160 assert_eq!(vas.relative(2), Err(Error::RelativeIndex(2)));
161 }
162
163 proptest! {
164 #[test]
165 fn test_first_insertion_without_drop(
166 ref count in 1..2200usize
167 ) {
168 let mut vas = VirtualAddressSpace::default();
169 vas.add();
170 (1..*count).for_each(|_| { vas.add(); });
171
172 assert_eq!(vas.relative_base(*count, count - 1), Ok(0), "{:?}", vas);
173 }
174
175 #[test]
176 fn test_first_insertion_with_drop(
177 ref count in 2..2200usize
178 ) {
179 let mut vas = VirtualAddressSpace::default();
180 vas.add();
181 (1..*count).for_each(|_| { vas.add(); });
182 (0..*count - 1).for_each(|_| vas.drop());
183
184 assert_eq!(vas.relative_base(*count, count - 1), Err(Error::RelativeIndex(count - 1)), "{:?}", vas);
185 }
186
187 #[test]
188 fn test_last_insertion_without_drop(
189 ref count in 1..2200usize
190 ) {
191 let mut vas = VirtualAddressSpace::default();
192 (1..*count).for_each(|_| { vas.add(); });
193 vas.add();
194
195 assert_eq!(vas.relative_base(*count, 0), Ok(count -1),
196 "{:?}", vas);
197 }
198
199 #[test]
200 fn test_last_insertion_with_drop(
201 ref count in 2..2200usize
202 ) {
203 let mut vas = VirtualAddressSpace::default();
204 (0..*count - 1).for_each(|_| { vas.add(); });
205 vas.add();
206 (0..*count - 1).for_each(|_| { vas.drop(); });
207
208 assert_eq!(vas.relative_base(*count, 0), Ok(0),
209 "{:?}", vas);
210 }
211 }
212
213 #[test]
214 fn test_post_base_index() {
215 let mut vas = VirtualAddressSpace::default();
226 (0..7).for_each(|_| {
227 vas.add();
228 });
229
230 assert_eq!(vas.post_base(4, 1), Ok(5));
231 }
232
233 #[test]
234 fn largest_ref() {
235 let mut vas = VirtualAddressSpace::default();
236 (0..7).for_each(|_| {
237 vas.add();
238 });
239 assert_eq!(vas.largest_ref(), 7);
240 }
241
242 #[test]
243 fn relative() {
244 let mut vas = VirtualAddressSpace::default();
245
246 (0..7).for_each(|_| {
247 vas.add();
248 });
249
250 assert_eq!(vas.relative(0), Ok(6));
251 assert_eq!(vas.relative(1), Ok(5));
252 assert_eq!(vas.relative(6), Ok(0));
253 assert_eq!(vas.relative(7), Err(Error::RelativeIndex(7)));
254 }
255
256 #[test]
257 fn absolute_from_real_index() {
258 let mut vas = VirtualAddressSpace::default();
259 assert_eq!(vas.index(0), Err(Error::Index(0)));
260 vas.add();
261 assert_eq!(vas.index(0), Ok(1));
262 vas.add();
263 vas.drop();
264 assert_eq!(vas.index(0), Ok(2));
265 vas.drop();
266 assert_eq!(vas.index(0), Err(Error::Index(0)));
267 vas.add();
268 vas.add();
269 assert_eq!(vas.index(0), Ok(3));
270 assert_eq!(vas.index(1), Ok(4));
271 assert_eq!(vas.index(2), Err(Error::Index(2)));
272 }
273
274 #[test]
275 fn evicted() {
276 let mut vas = VirtualAddressSpace::default();
277 assert_eq!(vas.evicted(0), false);
278 assert_eq!(vas.evicted(1), false);
279 vas.add();
280 vas.add();
281 assert_eq!(vas.evicted(1), false);
282 vas.drop();
283 assert_eq!(vas.evicted(0), false);
284 assert_eq!(vas.evicted(1), true);
285 assert_eq!(vas.evicted(2), false);
286 vas.drop();
287 assert_eq!(vas.evicted(2), true);
288 }
289}