dbn/record/traits.rs
1//! Core traits for working with DBN records.
2//!
3//! - [`Record`]: read-only access to any record's header, size, timestamps, and raw bytes.
4//! - [`RecordMut`]: mutable access to the record header.
5//! - [`HasRType`]: implemented by concrete record types (e.g. [`MboMsg`](crate::MboMsg)),
6//! associates a static `rtype` used for downcasting via [`RecordRef`](crate::RecordRef).
7
8use super::ts_to_dt;
9use crate::{Publisher, RType, RecordHeader};
10
11/// Used for polymorphism around types all beginning with a [`RecordHeader`] where
12/// `rtype` is the discriminant used for indicating the type of record.
13///
14/// All record types are plain old data held in sequential memory, and therefore
15/// implement `AsRef<[u8]>` for simple serialization to bytes.
16///
17/// [`RecordRef`](crate::RecordRef) acts similar to a `&dyn Record`.
18pub trait Record: AsRef<[u8]> {
19 /// Returns a reference to the `RecordHeader` that comes at the beginning of all
20 /// record types.
21 fn header(&self) -> &RecordHeader;
22
23 /// Returns the size of the record in bytes.
24 fn record_size(&self) -> usize {
25 self.header().record_size()
26 }
27
28 /// Tries to convert the raw record type into an enum which is useful for exhaustive
29 /// pattern matching.
30 ///
31 /// # Errors
32 /// This function returns an error if the `rtype` field does not
33 /// contain a valid, known [`RType`].
34 fn rtype(&self) -> crate::Result<RType> {
35 self.header().rtype()
36 }
37
38 /// Tries to convert the raw `publisher_id` into an enum which is useful for
39 /// exhaustive pattern matching.
40 ///
41 /// # Errors
42 /// This function returns an error if the `publisher_id` does not correspond with
43 /// any known [`Publisher`].
44 fn publisher(&self) -> crate::Result<Publisher> {
45 self.header().publisher()
46 }
47
48 /// Returns the raw primary timestamp for the record.
49 ///
50 /// This timestamp should be used for sorting records as well as indexing into any
51 /// symbology data structure.
52 fn raw_index_ts(&self) -> u64 {
53 self.header().ts_event
54 }
55
56 /// Returns the primary timestamp for the record. Returns `None` if the primary
57 /// timestamp contains the sentinel value for a null timestamp.
58 ///
59 /// This timestamp should be used for sorting records as well as indexing into any
60 /// symbology data structure.
61 fn index_ts(&self) -> Option<time::OffsetDateTime> {
62 ts_to_dt(self.raw_index_ts())
63 }
64
65 /// Returns the primary date for the record; the date component of the primary
66 /// timestamp (`index_ts()`). Returns `None` if the primary timestamp contains the
67 /// sentinel value for a null timestamp.
68 fn index_date(&self) -> Option<time::Date> {
69 self.index_ts().map(|dt| dt.date())
70 }
71}
72
73/// Used for polymorphism around mutable types beginning with a [`RecordHeader`].
74pub trait RecordMut {
75 /// Returns a mutable reference to the `RecordHeader` that comes at the beginning of
76 /// all record types.
77 fn header_mut(&mut self) -> &mut RecordHeader;
78}
79
80/// An extension of the [`Record`] trait for types with a static [`RType`]. Used for
81/// determining if a rtype matches a type.
82///
83/// Because of the static function requirement, this trait is implemented by all concrete record
84/// types like [`MboMsg`](crate::MboMsg), but not by [`RecordRef`](crate::RecordRef), which can reference a record of
85/// dynamic type.
86///
87/// While not _dyn compatible_, [`RecordRef`](crate::RecordRef) acts like a `&dyn HasRType`.
88pub trait HasRType: Record + RecordMut {
89 /// Returns `true` if `rtype` matches the value associated with the implementing type.
90 fn has_rtype(rtype: u8) -> bool;
91}