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> = parse(bytes)?;
165 self.apply_header(header.offset, header.start.unwrap_or(header.offset), header.records)?;
166 group.positioned = true;
167 return Ok(());
168 }
169
170 match parse(bytes)? {
171 Op::Push(record) => self.apply_push(record),
172 Op::Pop(count) => self.apply_pop(count),
173 }
174 }
175
176 fn apply_header(&mut self, offset: u64, start: u64, records: Vec<T>) -> Result<()> {
178 if offset > MAX_INDEX {
179 return Err(Error::Json("window offset exceeds the safe integer range".into()));
180 }
181 if start < offset {
182 return Err(Error::Json("window checkpoint starts before its offset".into()));
183 }
184 let len = u64::try_from(records.len()).map_err(|_| Error::Json("window length exceeds u64".into()))?;
185 let end = start
186 .checked_add(len)
187 .filter(|end| *end <= MAX_INDEX)
188 .ok_or_else(|| Error::Json("window range exceeds the safe integer range".into()))?;
189
190 let delivered = match self.delivered {
191 None => {
193 if offset < start {
194 self.events.push_back(Queued::Event(Event::Skip(offset..start)));
195 }
196 offset
197 }
198 Some(delivered) => {
199 if offset < self.front || end < delivered {
200 return Err(Error::Json("window header moved backwards".into()));
201 }
202
203 let popped = self.front..delivered.min(offset);
207 if !popped.is_empty() {
208 self.events.push_back(Queued::Event(Event::Pop(popped)));
209 }
210 let skipped = delivered..start;
211 if !skipped.is_empty() {
212 self.events.push_back(Queued::Event(Event::Skip(skipped)));
213 }
214 delivered
215 }
216 };
217
218 let skip = usize::try_from(delivered.saturating_sub(start))
220 .map_err(|_| Error::Json("window length exceeds usize".into()))?;
221 let mut records = records.into_iter();
222 if skip > 0 {
223 records.nth(skip - 1);
224 }
225 if !records.as_slice().is_empty() {
226 self.events.push_back(Queued::Push {
227 index: start + skip as u64,
228 records,
229 });
230 }
231
232 self.front = offset;
233 self.len = end - offset;
234 self.delivered = Some(delivered.max(end));
235 Ok(())
236 }
237
238 fn apply_push(&mut self, record: T) -> Result<()> {
240 let delivered = self.delivered.expect("group header positioned the decoder");
241
242 let index = self
243 .front
244 .checked_add(self.len)
245 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
246 let end = index
247 .checked_add(1)
248 .filter(|end| *end <= MAX_INDEX)
249 .ok_or_else(|| Error::Json("window range exceeds the safe integer range".into()))?;
250 self.len = end - self.front;
251
252 if index >= delivered {
253 self.events
254 .push_back(Queued::Event(Event::Push { index, value: record }));
255 self.delivered = Some(end);
256 }
257
258 Ok(())
259 }
260
261 fn apply_pop(&mut self, count: u64) -> Result<()> {
263 let delivered = self.delivered.expect("group header positioned the decoder");
264 if count > self.len {
265 return Err(Error::Json(format!(
266 "pop of {count} exceeds the {} record(s) in the window",
267 self.len
268 )));
269 }
270
271 let end = self
272 .front
273 .checked_add(count)
274 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
275 let popped = self.front..delivered.min(end);
276 if !popped.is_empty() {
277 self.events.push_back(Queued::Event(Event::Pop(popped)));
278 }
279 let skipped = delivered.max(self.front)..end;
280 if !skipped.is_empty() {
281 self.events.push_back(Queued::Event(Event::Skip(skipped)));
282 }
283
284 self.front = end;
285 self.len -= count;
286 self.delivered = Some(delivered.max(self.front));
287
288 Ok(())
289 }
290}
291
292fn parse<T: DeserializeOwned>(bytes: &[u8]) -> Result<T> {
294 serde_json::from_slice(bytes).map_err(|err| {
297 let tracked = serde_path_to_error::deserialize::<_, T>(&mut serde_json::Deserializer::from_slice(bytes));
298 Error::Json(tracked.err().map_or_else(|| err.to_string(), |err| err.to_string()))
299 })
300}
301
302impl<T> Group<'_, T> {
303 pub fn next_event(&mut self) -> Option<Event<T>> {
305 self.decoder.next_event()
306 }
307
308 pub fn range(&self) -> std::ops::Range<u64> {
310 self.decoder.range()
311 }
312}
313
314impl<T: DeserializeOwned> Group<'_, T> {
315 pub fn decode(&mut self, payload: &[u8]) -> Result<()> {
317 self.decoder.decode(&mut self.codec, payload)
318 }
319}