moq_json/window/
decoder.rs1use std::collections::VecDeque;
4
5use serde::de::DeserializeOwned;
6
7use super::encoder::MAX_INDEX;
8use super::op::{Header, Op};
9use crate::{Error, Result};
10
11#[derive(Debug, Clone, Default)]
13#[non_exhaustive]
14pub struct ConsumerConfig {
15 pub compression: bool,
18}
19
20impl ConsumerConfig {
21 pub fn with_compression(mut self, compression: bool) -> Self {
23 self.compression = compression;
24 self
25 }
26}
27
28#[derive(Debug, Clone, PartialEq)]
33#[non_exhaustive]
34pub enum Event<T> {
35 Push {
37 index: u64,
39 value: T,
41 },
42
43 Pop(std::ops::Range<u64>),
45
46 Skip(std::ops::Range<u64>),
49}
50
51enum Queued<T> {
53 Event(Event<T>),
54 Push { index: u64, records: std::vec::IntoIter<T> },
55}
56
57pub struct Group<'a, T> {
59 decoder: &'a mut Decoder<T>,
60 codec: Codec,
61}
62
63pub(super) struct Codec {
65 flate: Option<moq_flate::Decoder>,
67
68 positioned: bool,
70}
71
72impl Codec {
73 pub(super) fn new() -> Self {
74 Self {
75 flate: None,
76 positioned: false,
77 }
78 }
79}
80
81pub struct Decoder<T> {
91 config: ConsumerConfig,
92
93 front: u64,
95
96 len: u64,
98
99 delivered: Option<u64>,
102
103 events: VecDeque<Queued<T>>,
105}
106
107impl<T> Decoder<T> {
108 pub fn new(config: ConsumerConfig) -> Self {
110 Self {
111 config,
112 front: 0,
113 len: 0,
114 delivered: None,
115 events: VecDeque::new(),
116 }
117 }
118
119 pub fn group(&mut self) -> Group<'_, T> {
121 Group {
122 decoder: self,
123 codec: Codec::new(),
124 }
125 }
126
127 pub fn next_event(&mut self) -> Option<Event<T>> {
133 match self.events.pop_front()? {
134 Queued::Event(event) => Some(event),
135 Queued::Push { index, mut records } => {
136 let value = records.next().expect("queued push batch is not empty");
137 if !records.as_slice().is_empty() {
138 self.events.push_front(Queued::Push {
139 index: index + 1,
140 records,
141 });
142 }
143 Some(Event::Push { index, value })
144 }
145 }
146 }
147
148 pub fn range(&self) -> std::ops::Range<u64> {
150 self.front..self.front + self.len
151 }
152}
153
154impl<T: DeserializeOwned> Decoder<T> {
155 pub(super) fn decode(&mut self, group: &mut Codec, payload: &[u8]) -> Result<()> {
157 let inflated = match self.config.compression {
158 true => Some(group.flate.get_or_insert_with(moq_flate::Decoder::new).frame(payload)?),
159 false => None,
160 };
161 let bytes = inflated.as_deref().unwrap_or(payload);
162
163 if !group.positioned {
164 let header: Header<T> = serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_slice(bytes))
165 .map_err(|err| Error::Json(err.to_string()))?;
166 self.apply_header(header.offset, header.start.unwrap_or(header.offset), header.records)?;
167 group.positioned = true;
168 return Ok(());
169 }
170
171 match serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_slice(bytes))
172 .map_err(|err| Error::Json(err.to_string()))?
173 {
174 Op::Push(record) => self.apply_push(record),
175 Op::Pop(count) => self.apply_pop(count),
176 }
177 }
178
179 fn apply_header(&mut self, offset: u64, start: u64, records: Vec<T>) -> Result<()> {
181 if offset > MAX_INDEX {
182 return Err(Error::Json("window offset exceeds the safe integer range".into()));
183 }
184 if start < offset {
185 return Err(Error::Json("window checkpoint starts before its offset".into()));
186 }
187 let len = u64::try_from(records.len()).map_err(|_| Error::Json("window length exceeds u64".into()))?;
188 let end = start
189 .checked_add(len)
190 .filter(|end| *end <= MAX_INDEX)
191 .ok_or_else(|| Error::Json("window range exceeds the safe integer range".into()))?;
192
193 let delivered = match self.delivered {
194 None => {
196 if offset < start {
197 self.events.push_back(Queued::Event(Event::Skip(offset..start)));
198 }
199 offset
200 }
201 Some(delivered) => {
202 if offset < self.front || end < delivered {
203 return Err(Error::Json("window header moved backwards".into()));
204 }
205
206 let popped = self.front..delivered.min(offset);
210 if !popped.is_empty() {
211 self.events.push_back(Queued::Event(Event::Pop(popped)));
212 }
213 let skipped = delivered..start;
214 if !skipped.is_empty() {
215 self.events.push_back(Queued::Event(Event::Skip(skipped)));
216 }
217 delivered
218 }
219 };
220
221 let skip = usize::try_from(delivered.saturating_sub(start))
223 .map_err(|_| Error::Json("window length exceeds usize".into()))?;
224 let mut records = records.into_iter();
225 if skip > 0 {
226 records.nth(skip - 1);
227 }
228 if !records.as_slice().is_empty() {
229 self.events.push_back(Queued::Push {
230 index: start + skip as u64,
231 records,
232 });
233 }
234
235 self.front = offset;
236 self.len = end - offset;
237 self.delivered = Some(delivered.max(end));
238 Ok(())
239 }
240
241 fn apply_push(&mut self, record: T) -> Result<()> {
243 let delivered = self.delivered.expect("group header positioned the decoder");
244
245 let index = self
246 .front
247 .checked_add(self.len)
248 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
249 let end = index
250 .checked_add(1)
251 .filter(|end| *end <= MAX_INDEX)
252 .ok_or_else(|| Error::Json("window range exceeds the safe integer range".into()))?;
253 self.len = end - self.front;
254
255 if index >= delivered {
256 self.events
257 .push_back(Queued::Event(Event::Push { index, value: record }));
258 self.delivered = Some(end);
259 }
260
261 Ok(())
262 }
263
264 fn apply_pop(&mut self, count: u64) -> Result<()> {
266 let delivered = self.delivered.expect("group header positioned the decoder");
267 if count > self.len {
268 return Err(Error::Json(format!(
269 "pop of {count} exceeds the {} record(s) in the window",
270 self.len
271 )));
272 }
273
274 let end = self
275 .front
276 .checked_add(count)
277 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
278 let popped = self.front..delivered.min(end);
279 if !popped.is_empty() {
280 self.events.push_back(Queued::Event(Event::Pop(popped)));
281 }
282 let skipped = delivered.max(self.front)..end;
283 if !skipped.is_empty() {
284 self.events.push_back(Queued::Event(Event::Skip(skipped)));
285 }
286
287 self.front = end;
288 self.len -= count;
289 self.delivered = Some(delivered.max(self.front));
290
291 Ok(())
292 }
293}
294
295impl<T> Group<'_, T> {
296 pub fn next_event(&mut self) -> Option<Event<T>> {
298 self.decoder.next_event()
299 }
300
301 pub fn range(&self) -> std::ops::Range<u64> {
303 self.decoder.range()
304 }
305}
306
307impl<T: DeserializeOwned> Group<'_, T> {
308 pub fn decode(&mut self, payload: &[u8]) -> Result<()> {
310 self.decoder.decode(&mut self.codec, payload)
311 }
312}