Skip to main content

dbn/
macros.rs

1//! Helper macros for working with multiple RTypes, Schemas, and types of records.
2
3// Re-export
4pub use dbn_macros::{
5    dbn_record, CsvSerialize, DbnAttr, JsonSerialize, PyFieldDesc, RecordDebug, WritePyRepr,
6};
7
8/// Base macro for type dispatch based on rtype.
9///
10/// # Errors
11/// This macro returns an error if the rtype is not recognized.
12#[doc(hidden)]
13#[macro_export]
14macro_rules! rtype_dispatch_base {
15    ($rec_ref:expr, $handler:ident) => {{
16        // Introduced new scope so new `use`s are ok
17        use $crate::enums::RType;
18        use $crate::record::*;
19        match $rec_ref.rtype() {
20            Ok(RType::Mbp0) => Ok($handler!(TradeMsg)),
21            Ok(RType::Mbp1) => Ok($handler!(Mbp1Msg)),
22            Ok(RType::Mbp10) => Ok($handler!(Mbp10Msg)),
23            #[allow(deprecated)]
24            Ok(RType::OhlcvDeprecated)
25            | Ok(RType::Ohlcv1S)
26            | Ok(RType::Ohlcv1M)
27            | Ok(RType::Ohlcv1H)
28            | Ok(RType::Ohlcv1D)
29            | Ok(RType::OhlcvEod) => Ok($handler!(OhlcvMsg)),
30            Ok(RType::Imbalance) => Ok($handler!(ImbalanceMsg)),
31            Ok(RType::Status) => Ok($handler!(StatusMsg)),
32            Ok(RType::InstrumentDef)
33                if $rec_ref.record_size() < std::mem::size_of::<$crate::v2::InstrumentDefMsg>() =>
34            {
35                Ok($handler!($crate::v1::InstrumentDefMsg))
36            }
37            Ok(RType::InstrumentDef)
38                if $rec_ref.record_size() < std::mem::size_of::<$crate::v3::InstrumentDefMsg>() =>
39            {
40                Ok($handler!($crate::v2::InstrumentDefMsg))
41            }
42            Ok(RType::InstrumentDef) => Ok($handler!($crate::v3::InstrumentDefMsg)),
43            Ok(RType::SymbolMapping)
44                if $rec_ref.record_size() < std::mem::size_of::<SymbolMappingMsg>() =>
45            {
46                Ok($handler!($crate::v1::SymbolMappingMsg))
47            }
48            Ok(RType::SymbolMapping) => Ok($handler!(SymbolMappingMsg)),
49            Ok(RType::Error) if $rec_ref.record_size() < std::mem::size_of::<ErrorMsg>() => {
50                Ok($handler!($crate::v1::ErrorMsg))
51            }
52            Ok(RType::Error) => Ok($handler!(ErrorMsg)),
53            Ok(RType::System) if $rec_ref.record_size() < std::mem::size_of::<SystemMsg>() => {
54                Ok($handler!($crate::v1::SystemMsg))
55            }
56            Ok(RType::System) => Ok($handler!(SystemMsg)),
57            Ok(RType::Statistics)
58                if $rec_ref.record_size() < std::mem::size_of::<$crate::v3::StatMsg>() =>
59            {
60                Ok($handler!($crate::v1::StatMsg))
61            }
62            Ok(RType::Statistics) => Ok($handler!($crate::v3::StatMsg)),
63            Ok(RType::Mbo) => Ok($handler!(MboMsg)),
64            Ok(RType::Cmbp1) | Ok(RType::Tcbbo) => Ok($handler!(Cmbp1Msg)),
65            Ok(RType::Bbo1S) | Ok(RType::Bbo1M) => Ok($handler!(BboMsg)),
66            Ok(RType::Cbbo1S) | Ok(RType::Cbbo1M) => Ok($handler!(CbboMsg)),
67            Err(e) => Err(e),
68        }
69    }};
70}
71
72/// Dispatches to a generic function or method based on `$rtype` and optionally `$ts_out`.
73///
74/// # Panics
75/// This function will panic if the encoded length of the given record is shorter
76/// than expected for its `rtype`.
77///
78/// # Errors
79/// This macro returns an error if the rtype is not recognized.
80#[macro_export]
81macro_rules! rtype_dispatch {
82    // generic async method
83    ($rec_ref:expr, $this:ident.$generic_method:ident($($arg:expr),*).await$(,)?) => {{
84        macro_rules! handler {
85            ($r:ty) => {{
86                $this.$generic_method($rec_ref.get::<$r>().unwrap() $(, $arg)*).await
87            }}
88        }
89        $crate::rtype_dispatch_base!($rec_ref, handler)
90    }};
91    // generic method
92    ($rec_ref:expr, $this:ident.$generic_method:ident($($arg:expr),*)$(,)?) => {{
93        macro_rules! handler {
94            ($r:ty) => {{
95                $this.$generic_method($rec_ref.get::<$r>().unwrap() $(, $arg)*)
96            }}
97        }
98        $crate::rtype_dispatch_base!($rec_ref, handler)
99    }};
100    // generic async function
101    ($rec_ref:expr, $generic_fn:ident($($arg:expr),*).await$(,)?) => {{
102        macro_rules! handler {
103            ($r:ty) => {{
104                $generic_fn($rec_ref.get::<$r>().unwrap() $(, $arg)*).await
105            }}
106        }
107        $crate::rtype_dispatch_base!($rec_ref, handler)
108    }};
109    // generic function
110    ($rec_ref:expr, $generic_fn:ident($($arg:expr),*)$(,)?) => {{
111        macro_rules! handler {
112            ($r:ty) => {{
113                $generic_fn($rec_ref.get::<$r>().unwrap() $(, $arg)*)
114            }}
115        }
116        $crate::rtype_dispatch_base!($rec_ref, handler)
117    }};
118    // generic always ts_out async method
119    ($rec_ref:expr, ts_out: true, $this:ident.$generic_method:ident($($arg:expr),*).await$(,)?) => {{
120        macro_rules! handler {
121            ($r:ty) => {{
122                $this.$generic_method($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*).await
123            }}
124        }
125        $crate::rtype_dispatch_base!($rec_ref, handler)
126    }};
127    // generic always ts_out method
128    ($rec_ref:expr, ts_out: true, $this:ident.$generic_method:ident($($arg:expr),*)$(,)?) => {{
129        macro_rules! handler {
130            ($r:ty) => {{
131                $this.$generic_method($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap(), $(, $arg)*)
132            }}
133        }
134        $crate::rtype_dispatch_base!($rec_ref, handler)
135    }};
136    // generic always ts_out async function
137    ($rec_ref:expr, ts_out: true, $generic_fn:ident($($arg:expr),*).await$(,)?) => {{
138        macro_rules! handler {
139            ($r:ty) => {{
140                $generic_fn($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*).await
141            }}
142        }
143        $crate::rtype_dispatch_base!($rec_ref, handler)
144    }};
145    // generic always ts_out function
146    ($rec_ref:expr, ts_out: true, $generic_fn:ident($($arg:expr),*)$(,)?) => {{
147        macro_rules! handler {
148            ($r:ty) => {{
149                $generic_fn($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*)
150            }}
151        }
152        $crate::rtype_dispatch_base!($rec_ref, handler)
153    }};
154    // ts_out generic async method
155    ($rec_ref:expr, ts_out: $ts_out:expr, $this:ident.$generic_method:ident($($arg:expr),*).await$(,)?) => {{
156        macro_rules! handler {
157            ($r:ty) => {{
158                if $ts_out {
159                    $this.$generic_method($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*).await
160                } else {
161                    $this.$generic_method($rec_ref.get::<$r>().unwrap() $(, $arg)*).await
162                }
163            }}
164        }
165        $crate::rtype_dispatch_base!($rec_ref, handler)
166    }};
167    // ts_out generic method
168    ($rec_ref:expr, ts_out: $ts_out:expr, $this:ident.$generic_method:ident($($arg:expr),*)$(,)?) => {{
169        macro_rules! handler {
170            ($r:ty) => {{
171                if $ts_out {
172                    $this.$generic_method($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*)
173                } else {
174                    $this.$generic_method($rec_ref.get::<$r>().unwrap() $(, $arg)*)
175                }
176            }}
177        }
178        $crate::rtype_dispatch_base!($rec_ref, handler)
179    }};
180    // ts_out generic async function
181    ($rec_ref:expr, ts_out: $ts_out:expr, $generic_fn:ident($($arg:expr),*).await$(,)?) => {{
182        macro_rules! handler {
183            ($r:ty) => {{
184                if $ts_out {
185                    $generic_fn($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*).await
186                } else {
187                    $generic_fn($rec_ref.get::<$r>().unwrap() $(, $arg)*).await
188                }
189            }}
190        }
191        $crate::rtype_dispatch_base!($rec_ref, handler)
192    }};
193    // ts_out generic function
194    ($rec_ref:expr, ts_out: $ts_out:expr, $generic_fn:ident($($arg:expr),*)$(,)?) => {{
195        macro_rules! handler {
196            ($r:ty) => {{
197                if $ts_out {
198                    $generic_fn($rec_ref.get::<$crate::WithTsOut<$r>>().unwrap() $(, $arg)*)
199                } else {
200                    $generic_fn($rec_ref.get::<$r>().unwrap() $(, $arg)*)
201                }
202            }}
203        }
204        $crate::rtype_dispatch_base!($rec_ref, handler)
205    }};
206}
207
208#[doc(hidden)]
209#[macro_export]
210macro_rules! schema_dispatch_base {
211    ($schema:expr, $handler:ident) => {{
212        use $crate::enums::Schema;
213        use $crate::record::*;
214        match $schema {
215            Schema::Mbo => $handler!(MboMsg),
216            Schema::Mbp1 | Schema::Tbbo => $handler!(Mbp1Msg),
217            Schema::Bbo1S | Schema::Bbo1M => $handler!(BboMsg),
218            Schema::Mbp10 => $handler!(Mbp10Msg),
219            Schema::Trades => $handler!(TradeMsg),
220            Schema::Ohlcv1D
221            | Schema::Ohlcv1H
222            | Schema::Ohlcv1M
223            | Schema::Ohlcv1S
224            | Schema::OhlcvEod => {
225                $handler!(OhlcvMsg)
226            }
227            Schema::Definition => $handler!(InstrumentDefMsg),
228            Schema::Statistics => $handler!(StatMsg),
229            Schema::Status => $handler!(StatusMsg),
230            Schema::Imbalance => $handler!(ImbalanceMsg),
231            Schema::Cmbp1 | Schema::Tcbbo => {
232                $handler!(Cmbp1Msg)
233            }
234            Schema::Cbbo1S | Schema::Cbbo1M => {
235                $handler!(CbboMsg)
236            }
237        }
238    }};
239}
240
241/// Dispatches to a generic function or method based on `$schema` and optionally `$ts_out`.
242///
243/// # Errors
244/// This macro returns an error when the generic function or method returns an error.
245#[macro_export]
246macro_rules! schema_dispatch {
247    // generic async method
248    ($schema:expr, $this:ident.$generic_method:ident($($arg:expr),*).await$(,)?) => {{
249        macro_rules! handler {
250            ($r:ty) => {{
251                $this.$generic_method::<$r>($($arg),*).await
252            }}
253        }
254        $crate::schema_dispatch_base!($schema, handler)
255    }};
256    // generic method
257    ($schema:expr, $this:ident.$generic_method:ident($($arg:expr),*)$(,)?) => {{
258        macro_rules! handler {
259            ($r:ty) => {{
260                $this.$generic_method::<$r>($($arg),*)
261            }}
262        }
263        $crate::schema_dispatch_base!($schema, handler)
264    }};
265    // generic async function
266    ($schema:expr, $generic_fn:ident($($arg:expr),*).await$(,)?) => {{
267        macro_rules! handler {
268            ($r:ty) => {{
269                $generic_fn::<$r>($($arg),*).await
270            }}
271        }
272        $crate::schema_dispatch_base!($schema, handler)
273    }};
274    // generic function
275    ($schema:expr, $generic_fn:ident($($arg:expr),*)$(,)?) => {{
276        macro_rules! handler {
277            ($r:ty) => {{
278                $generic_fn::<$r>($($arg),*)
279            }}
280        }
281        $crate::schema_dispatch_base!($schema, handler)
282    }};
283    // generic async method
284    ($schema:expr, ts_out: $ts_out:expr, $this:ident.$generic_method:ident($($arg:expr),*).await$(,)?) => {{
285        macro_rules! handler {
286            ($r:ty) => {{
287                if $ts_out {
288                    $this.$generic_method::<$crate::WithTsOut<$r>>($($arg),*).await
289                } else {
290                    $this.$generic_method::<$r>($($arg),*).await
291                }
292            }}
293        }
294        $crate::schema_dispatch_base!($schema, handler)
295   }};
296    // generic method
297    ($schema:expr, ts_out: $ts_out:expr, $this:ident.$generic_method:ident($($arg:expr),*)$(,)?) => {{
298        macro_rules! handler {
299            ($r:ty) => {{
300                if $ts_out {
301                    $this.$generic_method::<$crate::WithTsOut<$r>>($($arg),*)
302                } else {
303                    $this.$generic_method::<$r>($($arg),*)
304                }
305            }}
306        }
307        $crate::schema_dispatch_base!($schema, handler)
308    }};
309    // generic async function
310    ($schema:expr, ts_out: $ts_out:expr, $generic_fn:ident($($arg:expr),*).await$(,)?) => {{
311        macro_rules! handler {
312            ($r:ty) => {{
313                if $ts_out {
314                    $generic_fn::<$crate::WithTsOut<$r>>($($arg),*).await
315                } else {
316                    $generic_fn::<$r>($($arg),*).await
317                }
318            }}
319        }
320        $crate::schema_dispatch_base!($schema, handler)
321    }};
322    // generic function
323    ($schema:expr, ts_out: $ts_out:expr, $generic_fn:ident($($arg:expr),*)$(,)?) => {{
324        macro_rules! handler {
325            ($r:ty) => {{
326                if $ts_out {
327                    $generic_fn::<$crate::WithTsOut<$r>>($($arg),*)
328                } else {
329                    $generic_fn::<$r>($($arg),*)
330                }
331            }}
332        }
333        $crate::schema_dispatch_base!($schema, handler)
334    }};
335}
336
337// DEPRECATED macros
338
339/// Specializes a generic function to all record types and dispatches based on the
340/// `rtype` and `ts_out`.
341///
342/// # Safety
343/// Assumes `$rec_ref` contains a record with `ts_out` appended. If this is not the
344/// case, the reading the record will read beyond the end of the record.
345///
346/// # Errors
347/// This macro returns an error if the rtype is not recognized.
348#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
349#[macro_export]
350macro_rules! rtype_ts_out_dispatch {
351    ($rec_ref:expr, $ts_out:expr, $generic_fn:expr $(,$arg:expr)*) => {{
352        macro_rules! maybe_ts_out {
353            ($r:ty) => {{
354                if $ts_out {
355                    $generic_fn($rec_ref.get_unchecked::<WithTsOut<$r>>() $(, $arg)*)
356                } else {
357                    $generic_fn(unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*)
358                }
359            }};
360        }
361        $crate::rtype_dispatch_base!($rec_ref, maybe_ts_out)
362    }};
363}
364/// Specializes a generic method to all record types and dispatches based on the
365/// `rtype` and `ts_out`.
366///
367/// # Safety
368/// Assumes `$rec_ref` contains a record with `ts_out` appended. If this is not the
369/// case, the reading the record will read beyond the end of the record.
370///
371/// # Errors
372/// This macro returns an error if the rtype is not recognized.
373#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
374#[macro_export]
375macro_rules! rtype_ts_out_method_dispatch {
376    ($rec_ref:expr, $ts_out:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
377        macro_rules! maybe_ts_out {
378            ($r:ty) => {{
379                if $ts_out {
380                    $this.$generic_method($rec_ref.get_unchecked::<WithTsOut<$r>>() $(, $arg)*)
381                } else {
382                    $this.$generic_method(unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*)
383                }
384            }};
385        }
386        $crate::rtype_dispatch_base!($rec_ref, maybe_ts_out)
387    }};
388}
389/// Specializes a generic async function to all record types and dispatches based
390/// `rtype` and `ts_out`.
391///
392/// # Errors
393/// This macro returns an error if the rtype is not recognized.
394#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
395#[macro_export]
396macro_rules! rtype_ts_out_async_dispatch {
397    ($rec_ref:expr, $ts_out:expr, $generic_fn:expr $(,$arg:expr)*) => {{
398        macro_rules! maybe_ts_out {
399            ($r:ty) => {{
400                if $ts_out {
401                    $generic_fn($rec_ref.get_unchecked::<WithTsOut<$r>>() $(, $arg)*).await
402                } else {
403                    $generic_fn(unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*).await
404                }
405            }};
406        }
407        $crate::rtype_dispatch_base!($rec_ref, maybe_ts_out)
408    }};
409}
410/// Specializes a generic async method to all record types and dispatches based
411/// `rtype` and `ts_out`.
412///
413/// # Errors
414/// This macro returns an error if the rtype is not recognized.
415#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
416#[macro_export]
417macro_rules! rtype_ts_out_async_method_dispatch {
418    ($rec_ref:expr, $ts_out:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
419        macro_rules! maybe_ts_out {
420            ($r:ty) => {{
421                if $ts_out {
422                    $this.$generic_method($rec_ref.get_unchecked::<WithTsOut<$r>>() $(, $arg)*).await
423                } else {
424                    $this.$generic_method(unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*).await
425                }
426            }};
427        }
428        $crate::rtype_dispatch_base!($rec_ref, maybe_ts_out)
429    }};
430}
431/// Specializes a generic method to all record types and dispatches based `rtype`.
432///
433/// # Errors
434/// This macro returns an error if the rtype is not recognized.
435#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
436#[macro_export]
437macro_rules! rtype_method_dispatch {
438    ($rec_ref:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
439        macro_rules! handler {
440            ($r:ty) => {{
441                // Safety: checks rtype before converting.
442                $this.$generic_method( unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*)
443            }}
444        }
445        $crate::rtype_dispatch_base!($rec_ref, handler)
446    }};
447}
448/// Specializes a generic async function to all record types and dispatches based
449/// `rtype`.
450///
451/// # Errors
452/// This macro returns an error if the rtype is not recognized.
453#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
454#[macro_export]
455macro_rules! rtype_async_dispatch {
456    ($rec_ref:expr, $generic_fn:expr $(,$arg:expr)*) => {{
457        macro_rules! handler {
458            ($r:ty) => {{
459                // Safety: checks rtype before converting.
460                $generic_fn( unsafe { $rec_ref.get_unchecked::<$r>() } $(, $arg)*).await
461            }}
462        }
463        $crate::rtype_dispatch_base!($rec_ref, handler)
464    }};
465}
466/// Specializes a generic function to all record types wrapped in
467/// [`WithTsOut`](crate::record::WithTsOut) and dispatches based on the `rtype`.
468///
469/// # Safety
470/// Assumes `$rec_ref` contains a record with `ts_out` appended. If this is not the
471/// case, the reading the record will read beyond the end of the record.
472///
473/// # Errors
474/// This macro returns an error if the rtype is not recognized.
475#[deprecated(since = "0.32.0", note = "Use the updated rtype_dispatch macro")]
476#[macro_export]
477macro_rules! rtype_dispatch_with_ts_out {
478    ($rec_ref:expr, $generic_fn:expr $(,$arg:expr)*) => {{
479        macro_rules! handler {
480            ($r:ty) => {{
481                $generic_fn( $rec_ref.get_unchecked::<WithTsOut<$r>>() $(, $arg)*)
482            }}
483        }
484        $crate::rtype_dispatch_base!($rec_ref, handler)
485    };
486}}
487
488/// Specializes a generic method to all record types with an associated schema.
489#[deprecated(since = "0.32.0", note = "Use the updated schema_dispatch macro")]
490#[macro_export]
491macro_rules! schema_method_dispatch {
492    ($schema:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
493        macro_rules! handler {
494            ($r:ty) => {{
495                $this.$generic_method::<$r>($($arg),*)
496            }}
497        }
498        $crate::schema_dispatch_base!($schema, handler)
499    }};
500}
501/// Specializes a generic method to all record types based on the associated type for
502/// `schema` and `ts_out`.
503#[deprecated(since = "0.32.0", note = "Use the updated schema_dispatch macro")]
504#[macro_export]
505macro_rules! schema_ts_out_method_dispatch {
506    ($schema:expr, $ts_out:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
507        macro_rules! handler {
508            ($r:ty) => {{
509                if $ts_out {
510                    $this.$generic_method::<WithTsOut<$r>>($($arg),*)
511                } else {
512                    $this.$generic_method::<$r>($($arg),*)
513                }
514            }}
515        }
516        $crate::schema_dispatch_base!($schema, handler)
517    }};
518}
519/// Specializes a generic async method to all record types with an associated
520/// schema.
521#[deprecated(since = "0.32.0", note = "Use the updated schema_dispatch macro")]
522#[macro_export]
523macro_rules! schema_async_method_dispatch {
524    ($schema:expr, $this:expr, $generic_method:ident $(,$arg:expr)*) => {{
525        macro_rules! handler {
526            ($r:ty) => {{
527                $this.$generic_method::<$r>($($arg),*).await
528            }}
529        }
530        $crate::schema_dispatch_base!($schema, handler)
531    }};
532}
533
534#[cfg(test)]
535mod tests {
536    use crate::{record::HasRType, rtype};
537
538    struct Dummy {}
539
540    #[allow(dead_code)]
541    impl Dummy {
542        fn on_rtype<T: HasRType>(&self) -> bool {
543            T::has_rtype(0xFF)
544        }
545
546        #[allow(clippy::extra_unused_type_parameters)]
547        fn on_rtype_2<T: HasRType>(&self, x: u64, y: u64) -> u64 {
548            x + y
549        }
550
551        async fn do_something<T: HasRType>(&self, arg: u8) -> bool {
552            T::has_rtype(arg)
553        }
554    }
555
556    fn has_rtype<T: HasRType>(arg: u8) -> bool {
557        T::has_rtype(arg)
558    }
559
560    #[test]
561    fn test_two_args() {
562        assert!(schema_dispatch!(
563            Schema::Imbalance,
564            has_rtype(rtype::IMBALANCE)
565        ))
566    }
567
568    #[test]
569    fn test_method_two_args() {
570        let dummy = Dummy {};
571        let ret = schema_dispatch!(Schema::Definition, dummy.on_rtype_2(5, 6));
572        assert_eq!(ret, 11);
573    }
574
575    #[test]
576    fn test_method_no_args() {
577        let dummy = Dummy {};
578        let ret = schema_dispatch!(Schema::Definition, dummy.on_rtype());
579        assert!(!ret);
580    }
581
582    #[cfg(feature = "async")]
583    mod r#async {
584        use super::*;
585
586        #[tokio::test]
587        async fn test_self() {
588            let target = Dummy {};
589            let ret_true = schema_dispatch!(
590                Schema::Trades,
591                target.do_something(crate::enums::rtype::MBP_0).await,
592            );
593            let ret_false = schema_dispatch!(Schema::Trades, target.do_something(0xff).await);
594            assert!(ret_true);
595            assert!(!ret_false);
596        }
597    }
598}