1use nautilus_core::{Params, UUID4, UnixNanos};
19use nautilus_model::identifiers::{ClientId, InstrumentId, StrategyId, TraderId};
20use nautilus_serialization::{
21 base_capnp,
22 capnp::{ToCapnp, order_side_to_capnp},
23 trading_capnp,
24};
25
26use crate::messages::execution::{
27 BatchCancelOrders, CancelAllOrders, CancelOrder, ModifyOrder, QueryAccount, QueryOrder,
28 SubmitOrder, SubmitOrderList, TradingCommand,
29};
30
31fn populate_string_map<'a>(builder: base_capnp::string_map::Builder<'a>, params: &Params) {
33 let mut entries_builder = builder.init_entries(params.len() as u32);
34 for (i, (key, value)) in params.iter().enumerate() {
35 let mut entry_builder = entries_builder.reborrow().get(i as u32);
36 entry_builder.set_key(key.as_str());
37 let value_str = serde_json::to_string(value).unwrap_or_else(|_| value.to_string());
38 entry_builder.set_value(value_str.as_str());
39 }
40}
41
42fn populate_trading_command_header<'a>(
44 mut builder: trading_capnp::trading_command_header::Builder<'a>,
45 trader_id: &TraderId,
46 client_id: Option<&ClientId>,
47 strategy_id: &StrategyId,
48 instrument_id: &InstrumentId,
49 command_id: &UUID4,
50 ts_init: UnixNanos,
51) {
52 let trader_id_builder = builder.reborrow().init_trader_id();
53 trader_id.to_capnp(trader_id_builder);
54
55 if let Some(client_id) = client_id {
56 let client_id_builder = builder.reborrow().init_client_id();
57 client_id.to_capnp(client_id_builder);
58 }
59
60 let strategy_id_builder = builder.reborrow().init_strategy_id();
61 strategy_id.to_capnp(strategy_id_builder);
62
63 let instrument_id_builder = builder.reborrow().init_instrument_id();
64 instrument_id.to_capnp(instrument_id_builder);
65
66 let command_id_builder = builder.reborrow().init_command_id();
67 command_id.to_capnp(command_id_builder);
68
69 let mut ts_init_builder = builder.reborrow().init_ts_init();
70 ts_init_builder.set_value(*ts_init);
71}
72
73impl<'a> ToCapnp<'a> for CancelOrder {
74 type Builder = trading_capnp::cancel_order::Builder<'a>;
75
76 fn to_capnp(&self, mut builder: Self::Builder) {
77 let header_builder = builder.reborrow().init_header();
78 populate_trading_command_header(
79 header_builder,
80 &self.trader_id,
81 self.client_id.as_ref(),
82 &self.strategy_id,
83 &self.instrument_id,
84 &self.command_id,
85 self.ts_init,
86 );
87
88 let client_order_id_builder = builder.reborrow().init_client_order_id();
89 self.client_order_id.to_capnp(client_order_id_builder);
90
91 if let Some(ref venue_order_id) = self.venue_order_id {
92 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
93 venue_order_id.to_capnp(venue_order_id_builder);
94 }
95
96 if let Some(ref params) = self.params {
97 let params_builder = builder.reborrow().init_params();
98 populate_string_map(params_builder, params);
99 }
100 }
101}
102
103impl<'a> ToCapnp<'a> for CancelAllOrders {
104 type Builder = trading_capnp::cancel_all_orders::Builder<'a>;
105
106 fn to_capnp(&self, mut builder: Self::Builder) {
107 let header_builder = builder.reborrow().init_header();
108 populate_trading_command_header(
109 header_builder,
110 &self.trader_id,
111 self.client_id.as_ref(),
112 &self.strategy_id,
113 &self.instrument_id,
114 &self.command_id,
115 self.ts_init,
116 );
117
118 builder.set_order_side(order_side_to_capnp(self.order_side));
119
120 if let Some(ref params) = self.params {
121 let params_builder = builder.reborrow().init_params();
122 populate_string_map(params_builder, params);
123 }
124 }
125}
126
127impl<'a> ToCapnp<'a> for BatchCancelOrders {
128 type Builder = trading_capnp::batch_cancel_orders::Builder<'a>;
129
130 fn to_capnp(&self, mut builder: Self::Builder) {
131 let header_builder = builder.reborrow().init_header();
132 populate_trading_command_header(
133 header_builder,
134 &self.trader_id,
135 self.client_id.as_ref(),
136 &self.strategy_id,
137 &self.instrument_id,
138 &self.command_id,
139 self.ts_init,
140 );
141
142 let mut cancellations_builder = builder
143 .reborrow()
144 .init_cancellations(self.cancels.len() as u32);
145 for (i, cancel) in self.cancels.iter().enumerate() {
146 let cancel_builder = cancellations_builder.reborrow().get(i as u32);
147 cancel.to_capnp(cancel_builder);
148 }
149
150 if let Some(ref params) = self.params {
151 let params_builder = builder.reborrow().init_params();
152 populate_string_map(params_builder, params);
153 }
154 }
155}
156
157impl<'a> ToCapnp<'a> for ModifyOrder {
158 type Builder = trading_capnp::modify_order::Builder<'a>;
159
160 fn to_capnp(&self, mut builder: Self::Builder) {
161 let header_builder = builder.reborrow().init_header();
162 populate_trading_command_header(
163 header_builder,
164 &self.trader_id,
165 self.client_id.as_ref(),
166 &self.strategy_id,
167 &self.instrument_id,
168 &self.command_id,
169 self.ts_init,
170 );
171
172 let client_order_id_builder = builder.reborrow().init_client_order_id();
173 self.client_order_id.to_capnp(client_order_id_builder);
174
175 if let Some(ref venue_order_id) = self.venue_order_id {
176 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
177 venue_order_id.to_capnp(venue_order_id_builder);
178 }
179
180 if let Some(ref quantity) = self.quantity {
181 let quantity_builder = builder.reborrow().init_quantity();
182 quantity.to_capnp(quantity_builder);
183 }
184
185 if let Some(ref price) = self.price {
186 let price_builder = builder.reborrow().init_price();
187 price.to_capnp(price_builder);
188 }
189
190 if let Some(ref trigger_price) = self.trigger_price {
191 let trigger_price_builder = builder.reborrow().init_trigger_price();
192 trigger_price.to_capnp(trigger_price_builder);
193 }
194
195 if let Some(ref params) = self.params {
196 let params_builder = builder.reborrow().init_params();
197 populate_string_map(params_builder, params);
198 }
199 }
200}
201
202impl<'a> ToCapnp<'a> for QueryOrder {
203 type Builder = trading_capnp::query_order::Builder<'a>;
204
205 fn to_capnp(&self, mut builder: Self::Builder) {
206 let header_builder = builder.reborrow().init_header();
207 populate_trading_command_header(
208 header_builder,
209 &self.trader_id,
210 self.client_id.as_ref(),
211 &self.strategy_id,
212 &self.instrument_id,
213 &self.command_id,
214 self.ts_init,
215 );
216
217 let client_order_id_builder = builder.reborrow().init_client_order_id();
218 self.client_order_id.to_capnp(client_order_id_builder);
219
220 if let Some(ref venue_order_id) = self.venue_order_id {
221 let venue_order_id_builder = builder.reborrow().init_venue_order_id();
222 venue_order_id.to_capnp(venue_order_id_builder);
223 }
224 }
225}
226
227impl<'a> ToCapnp<'a> for QueryAccount {
228 type Builder = trading_capnp::query_account::Builder<'a>;
229
230 fn to_capnp(&self, mut builder: Self::Builder) {
231 let trader_id_builder = builder.reborrow().init_trader_id();
232 self.trader_id.to_capnp(trader_id_builder);
233
234 let account_id_builder = builder.reborrow().init_account_id();
235 self.account_id.to_capnp(account_id_builder);
236
237 let command_id_builder = builder.reborrow().init_command_id();
238 self.command_id.to_capnp(command_id_builder);
239
240 let mut ts_init_builder = builder.reborrow().init_ts_init();
241 ts_init_builder.set_value(*self.ts_init);
242 }
243}
244
245impl<'a> ToCapnp<'a> for SubmitOrder {
246 type Builder = trading_capnp::submit_order::Builder<'a>;
247
248 fn to_capnp(&self, mut builder: Self::Builder) {
249 let header_builder = builder.reborrow().init_header();
250 populate_trading_command_header(
251 header_builder,
252 &self.trader_id,
253 self.client_id.as_ref(),
254 &self.strategy_id,
255 &self.instrument_id,
256 &self.command_id,
257 self.ts_init,
258 );
259
260 let order_init_builder = builder.reborrow().init_order_init();
261 self.order_init.to_capnp(order_init_builder);
262
263 if let Some(ref position_id) = self.position_id {
264 let position_id_builder = builder.reborrow().init_position_id();
265 position_id.to_capnp(position_id_builder);
266 }
267
268 if let Some(ref params) = self.params {
269 let params_builder = builder.reborrow().init_params();
270 populate_string_map(params_builder, params);
271 }
272 }
273}
274
275impl<'a> ToCapnp<'a> for SubmitOrderList {
276 type Builder = trading_capnp::submit_order_list::Builder<'a>;
277
278 fn to_capnp(&self, mut builder: Self::Builder) {
279 let header_builder = builder.reborrow().init_header();
280 populate_trading_command_header(
281 header_builder,
282 &self.trader_id,
283 self.client_id.as_ref(),
284 &self.strategy_id,
285 &self.instrument_id,
286 &self.command_id,
287 self.ts_init,
288 );
289
290 let mut order_inits_builder = builder
291 .reborrow()
292 .init_order_inits(self.order_inits.len() as u32);
293 for (i, order_init) in self.order_inits.iter().enumerate() {
294 let order_init_builder = order_inits_builder.reborrow().get(i as u32);
295 order_init.to_capnp(order_init_builder);
296 }
297
298 if let Some(ref position_id) = self.position_id {
299 let position_id_builder = builder.reborrow().init_position_id();
300 position_id.to_capnp(position_id_builder);
301 }
302
303 if let Some(ref params) = self.params {
304 let params_builder = builder.reborrow().init_params();
305 populate_string_map(params_builder, params);
306 }
307 }
308}
309
310impl<'a> ToCapnp<'a> for TradingCommand {
311 type Builder = trading_capnp::trading_command::Builder<'a>;
312
313 fn to_capnp(&self, builder: Self::Builder) {
314 match self {
315 Self::SubmitOrder(command) => {
316 let submit_builder = builder.init_submit_order();
317 command.to_capnp(submit_builder);
318 }
319 Self::SubmitOrderList(command) => {
320 let submit_list_builder = builder.init_submit_order_list();
321 command.to_capnp(submit_list_builder);
322 }
323 Self::ModifyOrder(command) => {
324 let modify_builder = builder.init_modify_order();
325 command.to_capnp(modify_builder);
326 }
327 Self::CancelOrder(command) => {
328 let cancel_builder = builder.init_cancel_order();
329 command.to_capnp(cancel_builder);
330 }
331 Self::CancelAllOrders(command) => {
332 let cancel_all_builder = builder.init_cancel_all_orders();
333 command.to_capnp(cancel_all_builder);
334 }
335 Self::BatchCancelOrders(command) => {
336 let batch_cancel_builder = builder.init_batch_cancel_orders();
337 command.to_capnp(batch_cancel_builder);
338 }
339 Self::QueryOrder(command) => {
340 let query_builder = builder.init_query_order();
341 command.to_capnp(query_builder);
342 }
343 Self::QueryAccount(command) => {
344 let query_builder = builder.init_query_account();
345 command.to_capnp(query_builder);
346 }
347 }
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use capnp::message::Builder;
354 use nautilus_core::UnixNanos;
355 use nautilus_model::{
356 enums::{OrderSide, OrderType},
357 identifiers::{
358 AccountId, ClientId, ClientOrderId, InstrumentId, OrderListId, StrategyId, TraderId,
359 },
360 orders::{Order, OrderList, OrderTestBuilder},
361 stubs::TestDefault,
362 types::{Price, Quantity},
363 };
364 use rstest::*;
365
366 use super::*;
367 use crate::messages::execution::{
368 cancel::{BatchCancelOrdersBuilder, CancelAllOrdersBuilder, CancelOrderBuilder},
369 modify::ModifyOrderBuilder,
370 query::{QueryAccountBuilder, QueryOrderBuilder},
371 };
372
373 #[fixture]
374 fn trader_id() -> TraderId {
375 TraderId::test_default()
376 }
377
378 #[fixture]
379 fn strategy_id() -> StrategyId {
380 StrategyId::test_default()
381 }
382
383 #[fixture]
384 fn instrument_id() -> InstrumentId {
385 InstrumentId::test_default()
386 }
387
388 #[fixture]
389 fn client_order_id() -> ClientOrderId {
390 ClientOrderId::test_default()
391 }
392
393 #[fixture]
394 fn command_id() -> UUID4 {
395 UUID4::new()
396 }
397
398 #[fixture]
399 fn ts_init() -> UnixNanos {
400 UnixNanos::default()
401 }
402
403 #[fixture]
404 fn client_id() -> ClientId {
405 ClientId::new("TEST")
406 }
407
408 #[rstest]
409 fn test_cancel_order_serialization(
410 trader_id: TraderId,
411 client_id: ClientId,
412 strategy_id: StrategyId,
413 instrument_id: InstrumentId,
414 client_order_id: ClientOrderId,
415 command_id: UUID4,
416 ts_init: UnixNanos,
417 ) {
418 let command = CancelOrderBuilder::default()
419 .trader_id(trader_id)
420 .client_id(Some(client_id))
421 .strategy_id(strategy_id)
422 .instrument_id(instrument_id)
423 .client_order_id(client_order_id)
424 .venue_order_id(None)
425 .command_id(command_id)
426 .ts_init(ts_init)
427 .params(None)
428 .build()
429 .unwrap();
430
431 let mut message = Builder::new_default();
432 {
433 let builder = message.init_root::<trading_capnp::cancel_order::Builder>();
434 command.to_capnp(builder);
435 }
436
437 let reader = message
438 .get_root_as_reader::<trading_capnp::cancel_order::Reader>()
439 .expect("Valid capnp message");
440
441 assert!(reader.has_header());
443 let header = reader.get_header().unwrap();
444 assert!(header.has_trader_id());
445 assert!(header.has_client_id());
446 assert!(header.has_strategy_id());
447 assert!(header.has_instrument_id());
448 assert!(header.has_command_id());
449 assert!(header.has_ts_init());
450 }
451
452 #[rstest]
453 fn test_cancel_all_orders_serialization(
454 trader_id: TraderId,
455 strategy_id: StrategyId,
456 instrument_id: InstrumentId,
457 command_id: UUID4,
458 ts_init: UnixNanos,
459 ) {
460 let command = CancelAllOrdersBuilder::default()
461 .trader_id(trader_id)
462 .client_id(None)
463 .strategy_id(strategy_id)
464 .instrument_id(instrument_id)
465 .order_side(OrderSide::Buy)
466 .command_id(command_id)
467 .ts_init(ts_init)
468 .params(None)
469 .build()
470 .unwrap();
471
472 let mut message = Builder::new_default();
473 {
474 let builder = message.init_root::<trading_capnp::cancel_all_orders::Builder>();
475 command.to_capnp(builder);
476 }
477
478 let reader = message
479 .get_root_as_reader::<trading_capnp::cancel_all_orders::Reader>()
480 .expect("Valid capnp message");
481
482 assert!(reader.has_header());
483 }
484
485 #[rstest]
486 fn test_batch_cancel_orders_serialization(
487 trader_id: TraderId,
488 strategy_id: StrategyId,
489 instrument_id: InstrumentId,
490 command_id: UUID4,
491 ts_init: UnixNanos,
492 ) {
493 let cancel1 = CancelOrderBuilder::default()
494 .trader_id(trader_id)
495 .client_id(None)
496 .strategy_id(strategy_id)
497 .instrument_id(instrument_id)
498 .client_order_id(ClientOrderId::new("O-001"))
499 .venue_order_id(None)
500 .command_id(UUID4::new())
501 .ts_init(ts_init)
502 .params(None)
503 .build()
504 .unwrap();
505
506 let cancel2 = CancelOrderBuilder::default()
507 .trader_id(trader_id)
508 .client_id(None)
509 .strategy_id(strategy_id)
510 .instrument_id(instrument_id)
511 .client_order_id(ClientOrderId::new("O-002"))
512 .venue_order_id(None)
513 .command_id(UUID4::new())
514 .ts_init(ts_init)
515 .params(None)
516 .build()
517 .unwrap();
518
519 let command = BatchCancelOrdersBuilder::default()
520 .trader_id(trader_id)
521 .client_id(None)
522 .strategy_id(strategy_id)
523 .instrument_id(instrument_id)
524 .cancels(vec![cancel1, cancel2])
525 .command_id(command_id)
526 .ts_init(ts_init)
527 .params(None)
528 .build()
529 .unwrap();
530
531 let mut message = Builder::new_default();
532 {
533 let builder = message.init_root::<trading_capnp::batch_cancel_orders::Builder>();
534 command.to_capnp(builder);
535 }
536
537 let reader = message
538 .get_root_as_reader::<trading_capnp::batch_cancel_orders::Reader>()
539 .expect("Valid capnp message");
540
541 assert!(reader.has_header());
542 assert!(reader.has_cancellations());
543 assert_eq!(reader.get_cancellations().unwrap().len(), 2);
544 }
545
546 #[rstest]
547 fn test_modify_order_serialization(
548 trader_id: TraderId,
549 strategy_id: StrategyId,
550 instrument_id: InstrumentId,
551 client_order_id: ClientOrderId,
552 command_id: UUID4,
553 ts_init: UnixNanos,
554 ) {
555 let command = ModifyOrderBuilder::default()
556 .trader_id(trader_id)
557 .client_id(None)
558 .strategy_id(strategy_id)
559 .instrument_id(instrument_id)
560 .client_order_id(client_order_id)
561 .venue_order_id(None)
562 .quantity(Some(Quantity::new(100.0, 0)))
563 .price(Some(Price::new(50_000.0, 2)))
564 .trigger_price(Some(Price::new(49_000.0, 2)))
565 .command_id(command_id)
566 .ts_init(ts_init)
567 .params(None)
568 .build()
569 .unwrap();
570
571 let mut message = Builder::new_default();
572 {
573 let builder = message.init_root::<trading_capnp::modify_order::Builder>();
574 command.to_capnp(builder);
575 }
576
577 let reader = message
578 .get_root_as_reader::<trading_capnp::modify_order::Reader>()
579 .expect("Valid capnp message");
580
581 assert!(reader.has_header());
582 assert!(reader.has_quantity());
583 assert!(reader.has_price());
584 assert!(reader.has_trigger_price());
585 }
586
587 #[rstest]
588 fn test_query_order_serialization(
589 trader_id: TraderId,
590 strategy_id: StrategyId,
591 instrument_id: InstrumentId,
592 client_order_id: ClientOrderId,
593 command_id: UUID4,
594 ts_init: UnixNanos,
595 ) {
596 let command = QueryOrderBuilder::default()
597 .trader_id(trader_id)
598 .client_id(None)
599 .strategy_id(strategy_id)
600 .instrument_id(instrument_id)
601 .client_order_id(client_order_id)
602 .venue_order_id(None)
603 .command_id(command_id)
604 .ts_init(ts_init)
605 .build()
606 .unwrap();
607
608 let mut message = Builder::new_default();
609 {
610 let builder = message.init_root::<trading_capnp::query_order::Builder>();
611 command.to_capnp(builder);
612 }
613
614 let reader = message
615 .get_root_as_reader::<trading_capnp::query_order::Reader>()
616 .expect("Valid capnp message");
617
618 assert!(reader.has_header());
619 }
620
621 #[rstest]
622 fn test_query_account_serialization(
623 trader_id: TraderId,
624 command_id: UUID4,
625 ts_init: UnixNanos,
626 ) {
627 let command = QueryAccountBuilder::default()
628 .trader_id(trader_id)
629 .client_id(None)
630 .account_id(AccountId::new("ACC-001"))
631 .command_id(command_id)
632 .ts_init(ts_init)
633 .build()
634 .unwrap();
635
636 let mut message = Builder::new_default();
637 {
638 let builder = message.init_root::<trading_capnp::query_account::Builder>();
639 command.to_capnp(builder);
640 }
641
642 let reader = message
643 .get_root_as_reader::<trading_capnp::query_account::Reader>()
644 .expect("Valid capnp message");
645
646 assert!(reader.has_trader_id());
647 assert!(reader.has_account_id());
648 }
649
650 #[rstest]
651 fn test_submit_order_serialization(command_id: UUID4, ts_init: UnixNanos, client_id: ClientId) {
652 let order = OrderTestBuilder::new(OrderType::Limit)
653 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
654 .side(OrderSide::Buy)
655 .quantity(Quantity::new(1.0, 8))
656 .price(Price::new(50_000.0, 2))
657 .build();
658
659 let command = SubmitOrder::new(
660 order.trader_id(),
661 Some(client_id),
662 order.strategy_id(),
663 order.instrument_id(),
664 order.client_order_id(),
665 order.init_event().clone(),
666 None,
667 None,
668 None,
669 command_id,
670 ts_init,
671 );
672
673 let mut message = Builder::new_default();
674 {
675 let builder = message.init_root::<trading_capnp::submit_order::Builder>();
676 command.to_capnp(builder);
677 }
678
679 let reader = message
680 .get_root_as_reader::<trading_capnp::submit_order::Reader>()
681 .expect("Valid capnp message");
682
683 assert!(reader.has_header());
684 assert!(reader.has_order_init());
685 }
686
687 #[rstest]
688 fn test_submit_order_list_serialization(
689 command_id: UUID4,
690 ts_init: UnixNanos,
691 client_id: ClientId,
692 ) {
693 let order1 = OrderTestBuilder::new(OrderType::Limit)
694 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
695 .client_order_id(ClientOrderId::from("O-001"))
696 .side(OrderSide::Buy)
697 .quantity(Quantity::new(1.0, 8))
698 .price(Price::new(50_000.0, 2))
699 .build();
700
701 let order2 = OrderTestBuilder::new(OrderType::Limit)
702 .instrument_id(InstrumentId::from("BTCUSDT.BINANCE"))
703 .client_order_id(ClientOrderId::from("O-002"))
704 .side(OrderSide::Sell)
705 .quantity(Quantity::new(1.0, 8))
706 .price(Price::new(51_000.0, 2))
707 .build();
708
709 let orders = [order1.clone(), order2];
710 let order_inits: Vec<_> = orders.iter().map(|o| o.init_event().clone()).collect();
711 let order_list = OrderList::new(
712 OrderListId::new("OL-001"),
713 InstrumentId::from("BTCUSDT.BINANCE"),
714 order1.strategy_id(),
715 vec![order1.client_order_id(), orders[1].client_order_id()],
716 ts_init,
717 );
718
719 let command = SubmitOrderList::new(
720 order1.trader_id(),
721 Some(client_id),
722 order1.strategy_id(),
723 order_list,
724 order_inits,
725 None,
726 None,
727 None,
728 command_id,
729 ts_init,
730 );
731
732 let mut message = Builder::new_default();
733 {
734 let builder = message.init_root::<trading_capnp::submit_order_list::Builder>();
735 command.to_capnp(builder);
736 }
737
738 let reader = message
739 .get_root_as_reader::<trading_capnp::submit_order_list::Reader>()
740 .expect("Valid capnp message");
741
742 assert!(reader.has_header());
743 assert!(reader.has_order_inits());
744 assert_eq!(reader.get_order_inits().unwrap().len(), 2);
745 }
746
747 #[rstest]
748 fn test_trading_command_enum_serialization(
749 trader_id: TraderId,
750 strategy_id: StrategyId,
751 instrument_id: InstrumentId,
752 client_order_id: ClientOrderId,
753 command_id: UUID4,
754 ts_init: UnixNanos,
755 ) {
756 let cancel = CancelOrderBuilder::default()
757 .trader_id(trader_id)
758 .client_id(None)
759 .strategy_id(strategy_id)
760 .instrument_id(instrument_id)
761 .client_order_id(client_order_id)
762 .venue_order_id(None)
763 .command_id(command_id)
764 .ts_init(ts_init)
765 .params(None)
766 .build()
767 .unwrap();
768
769 let command = TradingCommand::CancelOrder(cancel);
770
771 let mut message = Builder::new_default();
772 {
773 let builder = message.init_root::<trading_capnp::trading_command::Builder>();
774 command.to_capnp(builder);
775 }
776
777 let reader = message
778 .get_root_as_reader::<trading_capnp::trading_command::Reader>()
779 .expect("Valid capnp message");
780
781 assert!(reader.has_cancel_order());
783 }
784}