Skip to main content

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}