1use crate::orderbook::book_change_event::PriceLevelChangedEvent;
24use crate::orderbook::trade::TradeResult;
25
26#[derive(Debug)]
28pub struct SerializationError {
29 pub message: String,
31}
32
33impl std::fmt::Display for SerializationError {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "event serialization error: {}", self.message)
36 }
37}
38
39impl std::error::Error for SerializationError {}
40
41pub trait EventSerializer: Send + Sync + std::fmt::Debug {
53 fn serialize_trade(&self, trade: &TradeResult) -> Result<Vec<u8>, SerializationError>;
59
60 fn serialize_book_change(
66 &self,
67 event: &PriceLevelChangedEvent,
68 ) -> Result<Vec<u8>, SerializationError>;
69
70 fn deserialize_trade(&self, data: &[u8]) -> Result<TradeResult, SerializationError>;
77
78 fn deserialize_book_change(
85 &self,
86 data: &[u8],
87 ) -> Result<PriceLevelChangedEvent, SerializationError>;
88
89 #[must_use]
94 fn content_type(&self) -> &'static str;
95}
96
97#[derive(Debug, Clone, Copy, Default)]
109pub struct JsonEventSerializer;
110
111impl JsonEventSerializer {
112 #[must_use]
114 #[inline]
115 pub fn new() -> Self {
116 Self
117 }
118}
119
120impl EventSerializer for JsonEventSerializer {
121 fn serialize_trade(&self, trade: &TradeResult) -> Result<Vec<u8>, SerializationError> {
122 serde_json::to_vec(trade).map_err(|e| SerializationError {
123 message: e.to_string(),
124 })
125 }
126
127 fn serialize_book_change(
128 &self,
129 event: &PriceLevelChangedEvent,
130 ) -> Result<Vec<u8>, SerializationError> {
131 serde_json::to_vec(event).map_err(|e| SerializationError {
132 message: e.to_string(),
133 })
134 }
135
136 fn deserialize_trade(&self, data: &[u8]) -> Result<TradeResult, SerializationError> {
137 serde_json::from_slice(data).map_err(|e| SerializationError {
138 message: e.to_string(),
139 })
140 }
141
142 fn deserialize_book_change(
143 &self,
144 data: &[u8],
145 ) -> Result<PriceLevelChangedEvent, SerializationError> {
146 serde_json::from_slice(data).map_err(|e| SerializationError {
147 message: e.to_string(),
148 })
149 }
150
151 #[inline]
152 fn content_type(&self) -> &'static str {
153 "application/json"
154 }
155}
156
157#[cfg(feature = "bincode")]
178#[derive(Debug, Clone, Copy, Default)]
179pub struct BincodeEventSerializer;
180
181#[cfg(feature = "bincode")]
182impl BincodeEventSerializer {
183 #[must_use]
185 #[inline]
186 pub fn new() -> Self {
187 Self
188 }
189}
190
191#[cfg(feature = "bincode")]
192impl EventSerializer for BincodeEventSerializer {
193 fn serialize_trade(&self, trade: &TradeResult) -> Result<Vec<u8>, SerializationError> {
194 bincode::serde::encode_to_vec(trade, bincode::config::standard()).map_err(|e| {
195 SerializationError {
196 message: e.to_string(),
197 }
198 })
199 }
200
201 fn serialize_book_change(
202 &self,
203 event: &PriceLevelChangedEvent,
204 ) -> Result<Vec<u8>, SerializationError> {
205 bincode::serde::encode_to_vec(event, bincode::config::standard()).map_err(|e| {
206 SerializationError {
207 message: e.to_string(),
208 }
209 })
210 }
211
212 fn deserialize_trade(&self, data: &[u8]) -> Result<TradeResult, SerializationError> {
213 let (value, bytes_read) =
214 bincode::serde::decode_from_slice::<TradeResult, _>(data, bincode::config::standard())
215 .map_err(|e| SerializationError {
216 message: e.to_string(),
217 })?;
218 if bytes_read != data.len() {
219 return Err(SerializationError {
220 message: format!(
221 "trailing bytes after trade payload: consumed {bytes_read} of {}",
222 data.len()
223 ),
224 });
225 }
226 Ok(value)
227 }
228
229 fn deserialize_book_change(
230 &self,
231 data: &[u8],
232 ) -> Result<PriceLevelChangedEvent, SerializationError> {
233 let (value, bytes_read) = bincode::serde::decode_from_slice::<PriceLevelChangedEvent, _>(
234 data,
235 bincode::config::standard(),
236 )
237 .map_err(|e| SerializationError {
238 message: e.to_string(),
239 })?;
240 if bytes_read != data.len() {
241 return Err(SerializationError {
242 message: format!(
243 "trailing bytes after book-change payload: consumed {bytes_read} of {}",
244 data.len()
245 ),
246 });
247 }
248 Ok(value)
249 }
250
251 #[inline]
252 fn content_type(&self) -> &'static str {
253 "application/x-bincode"
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use pricelevel::{Id, MatchResult, Side};
261
262 fn make_trade_result() -> TradeResult {
263 let order_id = Id::new_uuid();
264 let match_result = MatchResult::new(order_id, 100);
265 TradeResult::new("BTC/USD".to_string(), match_result)
266 }
267
268 fn make_book_change() -> PriceLevelChangedEvent {
269 PriceLevelChangedEvent {
270 side: Side::Buy,
271 price: 50_000_000,
272 quantity: 1_000,
273 engine_seq: 0,
274 }
275 }
276
277 #[test]
280 fn test_json_serialize_trade() {
281 let serializer = JsonEventSerializer::new();
282 let trade = make_trade_result();
283 let result = serializer.serialize_trade(&trade);
284 assert!(result.is_ok());
285 let bytes = result.unwrap_or_default();
286 assert!(!bytes.is_empty());
287
288 let json_str = String::from_utf8(bytes).unwrap_or_default();
289 assert!(json_str.contains("BTC/USD"));
290 }
291
292 #[test]
293 fn test_json_roundtrip_trade() {
294 let serializer = JsonEventSerializer::new();
295 let trade = make_trade_result();
296 let bytes = serializer.serialize_trade(&trade);
297 assert!(bytes.is_ok());
298 let bytes = bytes.unwrap_or_default();
299
300 let decoded = serializer.deserialize_trade(&bytes);
301 assert!(decoded.is_ok());
302 let decoded = decoded.unwrap_or_else(|_| make_trade_result());
303 assert_eq!(decoded.symbol, trade.symbol);
304 assert_eq!(decoded.total_maker_fees, trade.total_maker_fees);
305 assert_eq!(decoded.total_taker_fees, trade.total_taker_fees);
306 }
307
308 #[test]
309 fn test_json_serialize_book_change() {
310 let serializer = JsonEventSerializer::new();
311 let event = make_book_change();
312 let result = serializer.serialize_book_change(&event);
313 assert!(result.is_ok());
314 let bytes = result.unwrap_or_default();
315 assert!(!bytes.is_empty());
316 }
317
318 #[test]
319 fn test_json_roundtrip_book_change() {
320 let serializer = JsonEventSerializer::new();
321 let event = make_book_change();
322 let bytes = serializer.serialize_book_change(&event);
323 assert!(bytes.is_ok());
324 let bytes = bytes.unwrap_or_default();
325
326 let decoded = serializer.deserialize_book_change(&bytes);
327 assert!(decoded.is_ok());
328 let decoded = decoded.unwrap_or_else(|_| make_book_change());
329 assert_eq!(decoded, event);
330 }
331
332 #[test]
333 fn test_json_content_type() {
334 let serializer = JsonEventSerializer::new();
335 assert_eq!(serializer.content_type(), "application/json");
336 }
337
338 #[test]
339 fn test_json_deserialize_trade_error() {
340 let serializer = JsonEventSerializer::new();
341 let result = serializer.deserialize_trade(b"not valid json");
342 assert!(result.is_err());
343 }
344
345 #[test]
346 fn test_json_deserialize_book_change_error() {
347 let serializer = JsonEventSerializer::new();
348 let result = serializer.deserialize_book_change(b"not valid json");
349 assert!(result.is_err());
350 }
351
352 #[test]
353 fn test_serialization_error_display() {
354 let err = SerializationError {
355 message: "test error".to_string(),
356 };
357 let display = format!("{err}");
358 assert!(display.contains("event serialization error"));
359 assert!(display.contains("test error"));
360 }
361
362 #[cfg(feature = "bincode")]
365 mod bincode_tests {
366 use super::*;
367
368 #[test]
369 fn test_bincode_serialize_trade() {
370 let serializer = BincodeEventSerializer::new();
371 let trade = make_trade_result();
372 let result = serializer.serialize_trade(&trade);
373 assert!(result.is_ok());
374 let bytes = result.unwrap_or_default();
375 assert!(!bytes.is_empty());
376
377 let json_serializer = JsonEventSerializer::new();
379 let json_bytes = json_serializer.serialize_trade(&trade).unwrap_or_default();
380 assert!(
381 bytes.len() < json_bytes.len(),
382 "bincode ({}) should be smaller than json ({})",
383 bytes.len(),
384 json_bytes.len()
385 );
386 }
387
388 #[test]
389 fn test_bincode_roundtrip_trade() {
390 let serializer = BincodeEventSerializer::new();
391 let trade = make_trade_result();
392 let bytes = serializer.serialize_trade(&trade);
393 assert!(bytes.is_ok());
394 let bytes = bytes.unwrap_or_default();
395
396 let decoded = serializer.deserialize_trade(&bytes);
397 assert!(decoded.is_ok());
398 let decoded = decoded.unwrap_or_else(|_| make_trade_result());
399 assert_eq!(decoded.symbol, trade.symbol);
400 assert_eq!(decoded.total_maker_fees, trade.total_maker_fees);
401 assert_eq!(decoded.total_taker_fees, trade.total_taker_fees);
402 }
403
404 #[test]
405 fn test_bincode_serialize_book_change() {
406 let serializer = BincodeEventSerializer::new();
407 let event = make_book_change();
408 let result = serializer.serialize_book_change(&event);
409 assert!(result.is_ok());
410 let bytes = result.unwrap_or_default();
411 assert!(!bytes.is_empty());
412 }
413
414 #[test]
415 fn test_bincode_roundtrip_book_change() {
416 let serializer = BincodeEventSerializer::new();
417 let event = make_book_change();
418 let bytes = serializer.serialize_book_change(&event);
419 assert!(bytes.is_ok());
420 let bytes = bytes.unwrap_or_default();
421
422 let decoded = serializer.deserialize_book_change(&bytes);
423 assert!(decoded.is_ok());
424 let decoded = decoded.unwrap_or_else(|_| make_book_change());
425 assert_eq!(decoded, event);
426 }
427
428 #[test]
429 fn test_bincode_content_type() {
430 let serializer = BincodeEventSerializer::new();
431 assert_eq!(serializer.content_type(), "application/x-bincode");
432 }
433
434 #[test]
435 fn test_bincode_deserialize_trade_error() {
436 let serializer = BincodeEventSerializer::new();
437 let result = serializer.deserialize_trade(b"\x00\x01");
438 assert!(result.is_err());
439 }
440
441 #[test]
442 fn test_bincode_deserialize_book_change_error() {
443 let serializer = BincodeEventSerializer::new();
444 let result = serializer.deserialize_book_change(b"\x00\x01");
445 assert!(result.is_err());
446 }
447
448 #[test]
449 fn test_bincode_smaller_than_json_book_change() {
450 let event = make_book_change();
451 let bincode_ser = BincodeEventSerializer::new();
452 let json_ser = JsonEventSerializer::new();
453
454 let bin_bytes = bincode_ser
455 .serialize_book_change(&event)
456 .unwrap_or_default();
457 let json_bytes = json_ser.serialize_book_change(&event).unwrap_or_default();
458
459 assert!(
460 bin_bytes.len() < json_bytes.len(),
461 "bincode ({}) should be smaller than json ({})",
462 bin_bytes.len(),
463 json_bytes.len()
464 );
465 }
466 }
467}