nautilus_model/data/
delta.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! An `OrderBookDelta` data type intended to carry book state information.
17
18use std::{collections::HashMap, fmt::Display, hash::Hash};
19
20use indexmap::IndexMap;
21use nautilus_core::{UnixNanos, correctness::FAILED, serialization::Serializable};
22use serde::{Deserialize, Serialize};
23
24use super::{
25    HasTsInit,
26    order::{BookOrder, NULL_ORDER},
27};
28use crate::{
29    enums::{BookAction, RecordFlag},
30    identifiers::InstrumentId,
31    types::{fixed::FIXED_SIZE_BINARY, quantity::check_positive_quantity},
32};
33
34/// Represents a single change/delta in an order book.
35#[repr(C)]
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
37#[serde(tag = "type")]
38#[cfg_attr(
39    feature = "python",
40    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
41)]
42pub struct OrderBookDelta {
43    /// The instrument ID for the book.
44    pub instrument_id: InstrumentId,
45    /// The order book delta action.
46    pub action: BookAction,
47    /// The order to apply.
48    pub order: BookOrder,
49    /// The record flags bit field indicating event end and data information.
50    pub flags: u8,
51    /// The message sequence number assigned at the venue.
52    pub sequence: u64,
53    /// UNIX timestamp (nanoseconds) when the book event occurred.
54    pub ts_event: UnixNanos,
55    /// UNIX timestamp (nanoseconds) when the instance was created.
56    pub ts_init: UnixNanos,
57}
58
59impl OrderBookDelta {
60    /// Creates a new [`OrderBookDelta`] instance with correctness checking.
61    ///
62    /// # Errors
63    ///
64    /// Returns an error if `action` is [`BookAction::Add`] or [`BookAction::Update`] and `size` is not positive (> 0).
65    ///
66    /// # Notes
67    ///
68    /// PyO3 requires a `Result` type for proper error handling and stacktrace printing in Python.
69    pub fn new_checked(
70        instrument_id: InstrumentId,
71        action: BookAction,
72        order: BookOrder,
73        flags: u8,
74        sequence: u64,
75        ts_event: UnixNanos,
76        ts_init: UnixNanos,
77    ) -> anyhow::Result<Self> {
78        if matches!(action, BookAction::Add | BookAction::Update) {
79            check_positive_quantity(order.size, stringify!(order.size))?;
80        }
81
82        Ok(Self {
83            instrument_id,
84            action,
85            order,
86            flags,
87            sequence,
88            ts_event,
89            ts_init,
90        })
91    }
92
93    /// Creates a new [`OrderBookDelta`] instance.
94    ///
95    /// # Panics
96    ///
97    /// Panics if `action` is [`BookAction::Add`] or [`BookAction::Update`] and `size` is not positive (> 0).
98    #[must_use]
99    pub fn new(
100        instrument_id: InstrumentId,
101        action: BookAction,
102        order: BookOrder,
103        flags: u8,
104        sequence: u64,
105        ts_event: UnixNanos,
106        ts_init: UnixNanos,
107    ) -> Self {
108        Self::new_checked(
109            instrument_id,
110            action,
111            order,
112            flags,
113            sequence,
114            ts_event,
115            ts_init,
116        )
117        .expect(FAILED)
118    }
119
120    /// Creates a new [`OrderBookDelta`] instance with a `Clear` action and NULL order.
121    #[must_use]
122    pub fn clear(
123        instrument_id: InstrumentId,
124        sequence: u64,
125        ts_event: UnixNanos,
126        ts_init: UnixNanos,
127    ) -> Self {
128        Self {
129            instrument_id,
130            action: BookAction::Clear,
131            order: NULL_ORDER,
132            flags: RecordFlag::F_SNAPSHOT as u8,
133            sequence,
134            ts_event,
135            ts_init,
136        }
137    }
138
139    /// Returns the metadata for the type, for use with serialization formats.
140    #[must_use]
141    pub fn get_metadata(
142        instrument_id: &InstrumentId,
143        price_precision: u8,
144        size_precision: u8,
145    ) -> HashMap<String, String> {
146        let mut metadata = HashMap::new();
147        metadata.insert("instrument_id".to_string(), instrument_id.to_string());
148        metadata.insert("price_precision".to_string(), price_precision.to_string());
149        metadata.insert("size_precision".to_string(), size_precision.to_string());
150        metadata
151    }
152
153    /// Returns the field map for the type, for use with Arrow schemas.
154    #[must_use]
155    pub fn get_fields() -> IndexMap<String, String> {
156        let mut metadata = IndexMap::new();
157        metadata.insert("action".to_string(), "UInt8".to_string());
158        metadata.insert("side".to_string(), "UInt8".to_string());
159        metadata.insert("price".to_string(), FIXED_SIZE_BINARY.to_string());
160        metadata.insert("size".to_string(), FIXED_SIZE_BINARY.to_string());
161        metadata.insert("order_id".to_string(), "UInt64".to_string());
162        metadata.insert("flags".to_string(), "UInt8".to_string());
163        metadata.insert("sequence".to_string(), "UInt64".to_string());
164        metadata.insert("ts_event".to_string(), "UInt64".to_string());
165        metadata.insert("ts_init".to_string(), "UInt64".to_string());
166        metadata
167    }
168}
169
170impl Display for OrderBookDelta {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(
173            f,
174            "{},{},{},{},{},{},{}",
175            self.instrument_id,
176            self.action,
177            self.order,
178            self.flags,
179            self.sequence,
180            self.ts_event,
181            self.ts_init
182        )
183    }
184}
185
186impl Serializable for OrderBookDelta {}
187
188impl HasTsInit for OrderBookDelta {
189    fn ts_init(&self) -> UnixNanos {
190        self.ts_init
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use std::{
197        collections::hash_map::DefaultHasher,
198        hash::{Hash, Hasher},
199    };
200
201    use nautilus_core::{
202        UnixNanos,
203        serialization::{
204            Serializable,
205            msgpack::{FromMsgPack, ToMsgPack},
206        },
207    };
208    use rstest::rstest;
209
210    use crate::{
211        data::{BookOrder, HasTsInit, OrderBookDelta, stubs::*},
212        enums::{BookAction, OrderSide, RecordFlag},
213        identifiers::InstrumentId,
214        types::{Price, Quantity},
215    };
216
217    fn create_test_delta() -> OrderBookDelta {
218        let order = BookOrder::new(
219            OrderSide::Buy,
220            Price::from("1.0500"),
221            Quantity::from("100000"),
222            12345,
223        );
224        OrderBookDelta::new(
225            InstrumentId::from("EURUSD.SIM"),
226            BookAction::Add,
227            order,
228            0,
229            123,
230            UnixNanos::from(1_000_000_000),
231            UnixNanos::from(2_000_000_000),
232        )
233    }
234
235    #[rstest]
236    fn test_order_book_delta_new() {
237        let delta = create_test_delta();
238
239        assert_eq!(delta.instrument_id, InstrumentId::from("EURUSD.SIM"));
240        assert_eq!(delta.action, BookAction::Add);
241        assert_eq!(delta.order.side, OrderSide::Buy);
242        assert_eq!(delta.order.price, Price::from("1.0500"));
243        assert_eq!(delta.order.size, Quantity::from("100000"));
244        assert_eq!(delta.order.order_id, 12345);
245        assert_eq!(delta.flags, 0);
246        assert_eq!(delta.sequence, 123);
247        assert_eq!(delta.ts_event, UnixNanos::from(1_000_000_000));
248        assert_eq!(delta.ts_init, UnixNanos::from(2_000_000_000));
249    }
250
251    #[rstest]
252    fn test_order_book_delta_new_checked_valid() {
253        let order = BookOrder::new(
254            OrderSide::Sell,
255            Price::from("1.0505"),
256            Quantity::from("50000"),
257            67890,
258        );
259        let result = OrderBookDelta::new_checked(
260            InstrumentId::from("GBPUSD.SIM"),
261            BookAction::Update,
262            order,
263            16,
264            456,
265            UnixNanos::from(500_000_000),
266            UnixNanos::from(1_500_000_000),
267        );
268
269        assert!(result.is_ok());
270        let delta = result.unwrap();
271        assert_eq!(delta.instrument_id, InstrumentId::from("GBPUSD.SIM"));
272        assert_eq!(delta.action, BookAction::Update);
273        assert_eq!(delta.order.side, OrderSide::Sell);
274        assert_eq!(delta.flags, 16);
275    }
276
277    #[rstest]
278    fn test_order_book_delta_new_with_zero_size_panics() {
279        let instrument_id = InstrumentId::from("AAPL.XNAS");
280        let action = BookAction::Add;
281        let price = Price::from("100.00");
282        let zero_size = Quantity::from(0);
283        let side = OrderSide::Buy;
284        let order_id = 123_456;
285        let flags = 0;
286        let sequence = 1;
287        let ts_event = UnixNanos::from(0);
288        let ts_init = UnixNanos::from(1);
289
290        let order = BookOrder::new(side, price, zero_size, order_id);
291
292        let result = std::panic::catch_unwind(|| {
293            let _ = OrderBookDelta::new(
294                instrument_id,
295                action,
296                order,
297                flags,
298                sequence,
299                ts_event,
300                ts_init,
301            );
302        });
303        assert!(result.is_err());
304    }
305
306    #[rstest]
307    fn test_order_book_delta_new_checked_with_zero_size_error() {
308        let instrument_id = InstrumentId::from("AAPL.XNAS");
309        let action = BookAction::Add;
310        let price = Price::from("100.00");
311        let zero_size = Quantity::from(0);
312        let side = OrderSide::Buy;
313        let order_id = 123_456;
314        let flags = 0;
315        let sequence = 1;
316        let ts_event = UnixNanos::from(0);
317        let ts_init = UnixNanos::from(1);
318
319        let order = BookOrder::new(side, price, zero_size, order_id);
320
321        let result = OrderBookDelta::new_checked(
322            instrument_id,
323            action,
324            order,
325            flags,
326            sequence,
327            ts_event,
328            ts_init,
329        );
330
331        assert!(result.is_err());
332        assert!(
333            result
334                .unwrap_err()
335                .to_string()
336                .contains("invalid `Quantity` for 'order.size' not positive")
337        );
338    }
339
340    #[rstest]
341    fn test_order_book_delta_new_checked_delete_with_zero_size_ok() {
342        let order = BookOrder::new(
343            OrderSide::Buy,
344            Price::from("100.00"),
345            Quantity::from(0),
346            123_456,
347        );
348        let result = OrderBookDelta::new_checked(
349            InstrumentId::from("TEST.SIM"),
350            BookAction::Delete,
351            order,
352            0,
353            1,
354            UnixNanos::from(0),
355            UnixNanos::from(1),
356        );
357
358        assert!(result.is_ok());
359    }
360
361    #[rstest]
362    fn test_order_book_delta_clear() {
363        let instrument_id = InstrumentId::from("BTCUSD.CRYPTO");
364        let sequence = 999;
365        let ts_event = UnixNanos::from(3_000_000_000);
366        let ts_init = UnixNanos::from(4_000_000_000);
367
368        let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event, ts_init);
369
370        assert_eq!(delta.instrument_id, instrument_id);
371        assert_eq!(delta.action, BookAction::Clear);
372        assert!(delta.order.price.is_zero());
373        assert!(delta.order.size.is_zero());
374        assert_eq!(delta.order.side, OrderSide::NoOrderSide);
375        assert_eq!(delta.order.order_id, 0);
376        assert_eq!(delta.flags, RecordFlag::F_SNAPSHOT as u8);
377        assert_eq!(delta.sequence, sequence);
378        assert_eq!(delta.ts_event, ts_event);
379        assert_eq!(delta.ts_init, ts_init);
380    }
381
382    #[rstest]
383    fn test_get_metadata() {
384        let instrument_id = InstrumentId::from("EURUSD.SIM");
385        let metadata = OrderBookDelta::get_metadata(&instrument_id, 5, 8);
386
387        assert_eq!(metadata.len(), 3);
388        assert_eq!(
389            metadata.get("instrument_id"),
390            Some(&"EURUSD.SIM".to_string())
391        );
392        assert_eq!(metadata.get("price_precision"), Some(&"5".to_string()));
393        assert_eq!(metadata.get("size_precision"), Some(&"8".to_string()));
394    }
395
396    #[rstest]
397    fn test_get_fields() {
398        let fields = OrderBookDelta::get_fields();
399
400        assert_eq!(fields.len(), 9);
401        assert_eq!(fields.get("action"), Some(&"UInt8".to_string()));
402        assert_eq!(fields.get("side"), Some(&"UInt8".to_string()));
403
404        #[cfg(feature = "high-precision")]
405        {
406            assert_eq!(
407                fields.get("price"),
408                Some(&"FixedSizeBinary(16)".to_string())
409            );
410            assert_eq!(fields.get("size"), Some(&"FixedSizeBinary(16)".to_string()));
411        }
412        #[cfg(not(feature = "high-precision"))]
413        {
414            assert_eq!(fields.get("price"), Some(&"FixedSizeBinary(8)".to_string()));
415            assert_eq!(fields.get("size"), Some(&"FixedSizeBinary(8)".to_string()));
416        }
417
418        assert_eq!(fields.get("order_id"), Some(&"UInt64".to_string()));
419        assert_eq!(fields.get("flags"), Some(&"UInt8".to_string()));
420        assert_eq!(fields.get("sequence"), Some(&"UInt64".to_string()));
421        assert_eq!(fields.get("ts_event"), Some(&"UInt64".to_string()));
422        assert_eq!(fields.get("ts_init"), Some(&"UInt64".to_string()));
423    }
424
425    #[rstest]
426    #[case(BookAction::Add)]
427    #[case(BookAction::Update)]
428    #[case(BookAction::Delete)]
429    #[case(BookAction::Clear)]
430    fn test_order_book_delta_with_different_actions(#[case] action: BookAction) {
431        let order = BookOrder::new(
432            OrderSide::Buy,
433            Price::from("100.00"),
434            if matches!(action, BookAction::Delete | BookAction::Clear) {
435                Quantity::from(0)
436            } else {
437                Quantity::from("1000")
438            },
439            123_456,
440        );
441
442        let result = if matches!(action, BookAction::Clear) {
443            Ok(OrderBookDelta::clear(
444                InstrumentId::from("TEST.SIM"),
445                1,
446                UnixNanos::from(1_000_000_000),
447                UnixNanos::from(2_000_000_000),
448            ))
449        } else {
450            OrderBookDelta::new_checked(
451                InstrumentId::from("TEST.SIM"),
452                action,
453                order,
454                0,
455                1,
456                UnixNanos::from(1_000_000_000),
457                UnixNanos::from(2_000_000_000),
458            )
459        };
460
461        assert!(result.is_ok());
462        let delta = result.unwrap();
463        assert_eq!(delta.action, action);
464    }
465
466    #[rstest]
467    #[case(OrderSide::Buy)]
468    #[case(OrderSide::Sell)]
469    fn test_order_book_delta_with_different_sides(#[case] side: OrderSide) {
470        let order = BookOrder::new(side, Price::from("100.00"), Quantity::from("1000"), 123_456);
471
472        let delta = OrderBookDelta::new(
473            InstrumentId::from("TEST.SIM"),
474            BookAction::Add,
475            order,
476            0,
477            1,
478            UnixNanos::from(1_000_000_000),
479            UnixNanos::from(2_000_000_000),
480        );
481
482        assert_eq!(delta.order.side, side);
483    }
484
485    #[rstest]
486    fn test_order_book_delta_has_ts_init() {
487        let delta = create_test_delta();
488        assert_eq!(delta.ts_init(), UnixNanos::from(2_000_000_000));
489    }
490
491    #[rstest]
492    fn test_order_book_delta_display() {
493        let delta = create_test_delta();
494        let display_str = format!("{delta}");
495
496        assert!(display_str.contains("EURUSD.SIM"));
497        assert!(display_str.contains("ADD"));
498        assert!(display_str.contains("BUY"));
499        assert!(display_str.contains("1.0500"));
500        assert!(display_str.contains("100000"));
501        assert!(display_str.contains("12345"));
502        assert!(display_str.contains("123"));
503    }
504
505    #[rstest]
506    fn test_order_book_delta_with_zero_timestamps() {
507        let order = BookOrder::new(
508            OrderSide::Buy,
509            Price::from("100.00"),
510            Quantity::from("1000"),
511            123_456,
512        );
513        let delta = OrderBookDelta::new(
514            InstrumentId::from("TEST.SIM"),
515            BookAction::Add,
516            order,
517            0,
518            0,
519            UnixNanos::from(0),
520            UnixNanos::from(0),
521        );
522
523        assert_eq!(delta.sequence, 0);
524        assert_eq!(delta.ts_event, UnixNanos::from(0));
525        assert_eq!(delta.ts_init, UnixNanos::from(0));
526    }
527
528    #[rstest]
529    fn test_order_book_delta_with_max_values() {
530        let order = BookOrder::new(
531            OrderSide::Sell,
532            Price::from("999999.9999"),
533            Quantity::from("999999999.9999"),
534            u64::MAX,
535        );
536        let delta = OrderBookDelta::new(
537            InstrumentId::from("TEST.SIM"),
538            BookAction::Update,
539            order,
540            u8::MAX,
541            u64::MAX,
542            UnixNanos::from(u64::MAX),
543            UnixNanos::from(u64::MAX),
544        );
545
546        assert_eq!(delta.flags, u8::MAX);
547        assert_eq!(delta.sequence, u64::MAX);
548        assert_eq!(delta.order.order_id, u64::MAX);
549        assert_eq!(delta.ts_event, UnixNanos::from(u64::MAX));
550        assert_eq!(delta.ts_init, UnixNanos::from(u64::MAX));
551    }
552
553    #[rstest]
554    fn test_new() {
555        let instrument_id = InstrumentId::from("AAPL.XNAS");
556        let action = BookAction::Add;
557        let price = Price::from("100.00");
558        let size = Quantity::from("10");
559        let side = OrderSide::Buy;
560        let order_id = 123_456;
561        let flags = 0;
562        let sequence = 1;
563        let ts_event = 1;
564        let ts_init = 2;
565
566        let order = BookOrder::new(side, price, size, order_id);
567
568        let delta = OrderBookDelta::new(
569            instrument_id,
570            action,
571            order,
572            flags,
573            sequence,
574            ts_event.into(),
575            ts_init.into(),
576        );
577
578        assert_eq!(delta.instrument_id, instrument_id);
579        assert_eq!(delta.action, action);
580        assert_eq!(delta.order.price, price);
581        assert_eq!(delta.order.size, size);
582        assert_eq!(delta.order.side, side);
583        assert_eq!(delta.order.order_id, order_id);
584        assert_eq!(delta.flags, flags);
585        assert_eq!(delta.sequence, sequence);
586        assert_eq!(delta.ts_event, ts_event);
587        assert_eq!(delta.ts_init, ts_init);
588    }
589
590    #[rstest]
591    fn test_clear() {
592        let instrument_id = InstrumentId::from("AAPL.XNAS");
593        let sequence = 1;
594        let ts_event = 2;
595        let ts_init = 3;
596
597        let delta = OrderBookDelta::clear(instrument_id, sequence, ts_event.into(), ts_init.into());
598
599        assert_eq!(delta.instrument_id, instrument_id);
600        assert_eq!(delta.action, BookAction::Clear);
601        assert!(delta.order.price.is_zero());
602        assert!(delta.order.size.is_zero());
603        assert_eq!(delta.order.side, OrderSide::NoOrderSide);
604        assert_eq!(delta.order.order_id, 0);
605        assert_eq!(delta.flags, 32);
606        assert_eq!(delta.sequence, sequence);
607        assert_eq!(delta.ts_event, ts_event);
608        assert_eq!(delta.ts_init, ts_init);
609    }
610
611    #[rstest]
612    fn test_order_book_delta_hash() {
613        let delta1 = create_test_delta();
614        let delta2 = create_test_delta();
615
616        let mut hasher1 = DefaultHasher::new();
617        let mut hasher2 = DefaultHasher::new();
618
619        delta1.hash(&mut hasher1);
620        delta2.hash(&mut hasher2);
621
622        assert_eq!(hasher1.finish(), hasher2.finish());
623    }
624
625    #[rstest]
626    fn test_order_book_delta_hash_different_deltas() {
627        let delta1 = create_test_delta();
628        let order2 = BookOrder::new(
629            OrderSide::Sell,
630            Price::from("1.0505"),
631            Quantity::from("50000"),
632            67890,
633        );
634        let delta2 = OrderBookDelta::new(
635            InstrumentId::from("EURUSD.SIM"),
636            BookAction::Add,
637            order2,
638            0,
639            123,
640            UnixNanos::from(1_000_000_000),
641            UnixNanos::from(2_000_000_000),
642        );
643
644        let mut hasher1 = DefaultHasher::new();
645        let mut hasher2 = DefaultHasher::new();
646
647        delta1.hash(&mut hasher1);
648        delta2.hash(&mut hasher2);
649
650        assert_ne!(hasher1.finish(), hasher2.finish());
651    }
652
653    #[rstest]
654    fn test_order_book_delta_partial_eq() {
655        let delta1 = create_test_delta();
656        let delta2 = create_test_delta();
657
658        // Test equality
659        assert_eq!(delta1, delta2);
660
661        // Test inequality with different instrument
662        let order3 = BookOrder::new(
663            OrderSide::Buy,
664            Price::from("1.0500"),
665            Quantity::from("100000"),
666            12345,
667        );
668        let delta3 = OrderBookDelta::new(
669            InstrumentId::from("GBPUSD.SIM"),
670            BookAction::Add,
671            order3,
672            0,
673            123,
674            UnixNanos::from(1_000_000_000),
675            UnixNanos::from(2_000_000_000),
676        );
677
678        assert_ne!(delta1, delta3);
679    }
680
681    #[rstest]
682    fn test_order_book_delta_clone() {
683        let delta1 = create_test_delta();
684        let delta2 = delta1;
685
686        assert_eq!(delta1, delta2);
687        assert_eq!(delta1.instrument_id, delta2.instrument_id);
688        assert_eq!(delta1.action, delta2.action);
689        assert_eq!(delta1.order, delta2.order);
690        assert_eq!(delta1.flags, delta2.flags);
691        assert_eq!(delta1.sequence, delta2.sequence);
692        assert_eq!(delta1.ts_event, delta2.ts_event);
693        assert_eq!(delta1.ts_init, delta2.ts_init);
694    }
695
696    #[rstest]
697    fn test_order_book_delta_debug() {
698        let delta = create_test_delta();
699        let debug_str = format!("{delta:?}");
700
701        assert!(debug_str.contains("OrderBookDelta"));
702        assert!(debug_str.contains("EURUSD.SIM"));
703        assert!(debug_str.contains("Add"));
704        assert!(debug_str.contains("BUY"));
705        assert!(debug_str.contains("1.0500"));
706    }
707
708    #[rstest]
709    fn test_order_book_delta_serialization() {
710        let delta = create_test_delta();
711
712        let json = serde_json::to_string(&delta).unwrap();
713        let deserialized: OrderBookDelta = serde_json::from_str(&json).unwrap();
714
715        assert_eq!(delta, deserialized);
716    }
717
718    #[rstest]
719    fn test_json_serialization(stub_delta: OrderBookDelta) {
720        let delta = stub_delta;
721        let serialized = delta.to_json_bytes().unwrap();
722        let deserialized = OrderBookDelta::from_json_bytes(serialized.as_ref()).unwrap();
723        assert_eq!(deserialized, delta);
724    }
725
726    #[rstest]
727    fn test_msgpack_serialization(stub_delta: OrderBookDelta) {
728        let delta = stub_delta;
729        let serialized = delta.to_msgpack_bytes().unwrap();
730        let deserialized = OrderBookDelta::from_msgpack_bytes(serialized.as_ref()).unwrap();
731        assert_eq!(deserialized, delta);
732    }
733}