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.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, records: Vec<T>) -> Result<()> {
181 if offset > MAX_INDEX {
182 return Err(Error::Json("window offset exceeds the safe integer range".into()));
183 }
184 let len = u64::try_from(records.len()).map_err(|_| Error::Json("window length exceeds u64".into()))?;
185 let end = offset
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 => offset,
193 Some(delivered) => {
194 if offset < self.front || end < delivered {
195 return Err(Error::Json("window header moved backwards".into()));
196 }
197
198 let popped = self.front..delivered.min(offset);
202 if !popped.is_empty() {
203 self.events.push_back(Queued::Event(Event::Pop(popped)));
204 }
205 let skipped = delivered..offset;
206 if !skipped.is_empty() {
207 self.events.push_back(Queued::Event(Event::Skip(skipped)));
208 }
209 delivered
210 }
211 };
212
213 let skip = usize::try_from(delivered.saturating_sub(offset))
215 .map_err(|_| Error::Json("window length exceeds usize".into()))?;
216 let mut records = records.into_iter();
217 if skip > 0 {
218 records.nth(skip - 1);
219 }
220 if !records.as_slice().is_empty() {
221 self.events.push_back(Queued::Push {
222 index: offset + skip as u64,
223 records,
224 });
225 }
226
227 self.front = offset;
228 self.len = end - offset;
229 self.delivered = Some(delivered.max(end));
230 Ok(())
231 }
232
233 fn apply_push(&mut self, record: T) -> Result<()> {
235 let delivered = self.delivered.expect("group header positioned the decoder");
236
237 let index = self
238 .front
239 .checked_add(self.len)
240 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
241 let end = index
242 .checked_add(1)
243 .filter(|end| *end <= MAX_INDEX)
244 .ok_or_else(|| Error::Json("window range exceeds the safe integer range".into()))?;
245 self.len = end - self.front;
246
247 if index >= delivered {
248 self.events
249 .push_back(Queued::Event(Event::Push { index, value: record }));
250 self.delivered = Some(end);
251 }
252
253 Ok(())
254 }
255
256 fn apply_pop(&mut self, count: u64) -> Result<()> {
258 let delivered = self.delivered.expect("group header positioned the decoder");
259 if count > self.len {
260 return Err(Error::Json(format!(
261 "pop of {count} exceeds the {} record(s) in the window",
262 self.len
263 )));
264 }
265
266 let end = self
267 .front
268 .checked_add(count)
269 .ok_or_else(|| Error::Json("window range exceeds u64".into()))?;
270 let popped = self.front..delivered.min(end);
271 if !popped.is_empty() {
272 self.events.push_back(Queued::Event(Event::Pop(popped)));
273 }
274 let skipped = delivered.max(self.front)..end;
275 if !skipped.is_empty() {
276 self.events.push_back(Queued::Event(Event::Skip(skipped)));
277 }
278
279 self.front = end;
280 self.len -= count;
281 self.delivered = Some(delivered.max(self.front));
282
283 Ok(())
284 }
285}
286
287impl<T> Group<'_, T> {
288 pub fn next_event(&mut self) -> Option<Event<T>> {
290 self.decoder.next_event()
291 }
292
293 pub fn range(&self) -> std::ops::Range<u64> {
295 self.decoder.range()
296 }
297}
298
299impl<T: DeserializeOwned> Group<'_, T> {
300 pub fn decode(&mut self, payload: &[u8]) -> Result<()> {
302 self.decoder.decode(&mut self.codec, payload)
303 }
304}