moq_json/stream/
decoder.rs1use std::marker::PhantomData;
4
5use serde::de::DeserializeOwned;
6
7use super::Config;
8use crate::Result;
9
10pub struct Decoder<T> {
17 flate: Option<moq_flate::Decoder>,
19 compression: bool,
20 _marker: PhantomData<fn() -> T>,
21}
22
23impl<T> Decoder<T> {
24 pub fn new(config: Config) -> Self {
26 Self {
27 flate: config.compression.is_deflate().then(moq_flate::Decoder::new),
28 compression: config.compression.is_deflate(),
29 _marker: PhantomData,
30 }
31 }
32
33 pub fn reset(&mut self) {
35 self.flate = self.compression.then(moq_flate::Decoder::new);
36 }
37}
38
39impl<T: DeserializeOwned> Decoder<T> {
40 pub fn decode(&mut self, payload: &[u8]) -> Result<T> {
42 Ok(match self.flate.as_mut() {
43 Some(flate) => serde_json::from_slice(&flate.frame(payload)?)?,
44 None => serde_json::from_slice(payload)?,
45 })
46 }
47}
48
49#[cfg(test)]
50mod test {
51 use super::super::{Config, Encoder};
52 use super::*;
53 use crate::Compression;
54 use serde_json::{Value, json};
55
56 fn cfg(compression: bool) -> Config {
57 Config {
58 compression: if compression {
59 Compression::Deflate
60 } else {
61 Compression::None
62 },
63 }
64 }
65
66 fn roundtrip(compression: bool, values: &[Value]) -> Vec<Value> {
68 let mut encoder = Encoder::<Value>::new(cfg(compression));
69 let mut decoder = Decoder::<Value>::new(cfg(compression));
70
71 values
72 .iter()
73 .map(|value| {
74 let record = encoder.encode(value).unwrap();
75 let decoded = decoder.decode(record.payload()).unwrap();
76 record.commit();
77 decoded
78 })
79 .collect()
80 }
81
82 #[test]
83 fn plaintext_roundtrip_in_order() {
84 let values: Vec<Value> = (0..5).map(|n| json!({ "n": n })).collect();
85 assert_eq!(roundtrip(false, &values), values);
86 }
87
88 #[test]
89 fn compressed_roundtrip_in_order() {
90 let values: Vec<Value> = (0..20).map(|n| json!({ "group": n, "pts": n * 2_000 })).collect();
91 assert_eq!(roundtrip(true, &values), values);
92 }
93
94 #[test]
95 fn the_shared_window_shrinks_repetitive_records() {
96 let mut encoder = Encoder::<Value>::new(cfg(true));
97 let sizes: Vec<usize> = (0..8)
98 .map(|n| {
99 let record = encoder.encode(&json!({ "group": n, "pts": n * 2_000 })).unwrap();
100 let len = record.payload().len();
101 record.commit();
102 len
103 })
104 .collect();
105
106 let raw = serde_json::to_vec(&json!({ "group": 7, "pts": 14_000 })).unwrap().len();
107 assert!(
108 *sizes.last().unwrap() < raw / 2,
109 "windowed record {} should be far below its raw size {raw}",
110 sizes.last().unwrap()
111 );
112 }
113
114 #[test]
117 fn reset_starts_a_cold_window_on_both_sides() {
118 let mut encoder = Encoder::<Value>::new(cfg(true));
119 let mut decoder = Decoder::<Value>::new(cfg(true));
120
121 for n in 0..4 {
122 let record = encoder.encode(&json!({ "n": n })).unwrap();
123 assert_eq!(decoder.decode(record.payload()).unwrap(), json!({ "n": n }));
124 record.commit();
125 }
126
127 encoder.reset();
128 decoder.reset();
129
130 let record = encoder.encode(&json!({ "n": 99 })).unwrap();
131 assert_eq!(decoder.decode(record.payload()).unwrap(), json!({ "n": 99 }));
132 record.commit();
133 }
134}
135
136#[cfg(test)]
137mod desync_test {
138 use super::super::{Config, Encoder};
139 use super::*;
140 use crate::Compression;
141 use serde_json::{Value, json};
142
143 fn deflate() -> Config {
144 Config {
145 compression: Compression::Deflate,
146 }
147 }
148
149 #[test]
153 fn an_uncommitted_compressed_record_stops_the_encoder() {
154 let mut encoder = Encoder::<Value>::new(deflate());
155 encoder.encode(&json!({ "n": 0 })).unwrap().commit();
156
157 drop(encoder.encode(&json!({ "n": 1 })).unwrap());
159
160 assert!(matches!(encoder.encode(&json!({ "n": 2 })), Err(crate::Error::Desync)));
161
162 encoder.reset();
164 let record = encoder.encode(&json!({ "n": 2 })).unwrap();
165 let mut decoder = Decoder::<Value>::new(deflate());
166 assert_eq!(decoder.decode(record.payload()).unwrap(), json!({ "n": 2 }));
167 record.commit();
168 }
169
170 #[test]
173 fn an_uncommitted_plaintext_record_does_not_stop_the_encoder() {
174 let mut encoder = Encoder::<Value>::new(Config::default());
175 drop(encoder.encode(&json!({ "n": 0 })).unwrap());
176
177 let record = encoder
178 .encode(&json!({ "n": 1 }))
179 .expect("plaintext records are independent");
180 let mut decoder = Decoder::<Value>::new(Config::default());
181 assert_eq!(decoder.decode(record.payload()).unwrap(), json!({ "n": 1 }));
182 record.commit();
183 }
184}