aversion/
group.rs

1//! Define message groups for automatic dispatching.
2//!
3//! A message group is a collection of messages that may be used together.
4//! For example, a file format or a network protocol may form a group.
5//!
6
7use crate::{MessageId, Versioned};
8use serde::de::DeserializeOwned;
9use serde::Serialize;
10use std::any::type_name;
11
12/// A data structure that contains a message-id and version fields.
13
14pub trait GroupHeader {
15    /// Retrieve the message id.
16    fn msg_id(&self) -> u16;
17    /// Retrieve the message version.
18    fn msg_ver(&self) -> u16;
19}
20
21/// A trait for deserializing any version of a [`Versioned`] data structure.
22///
23/// This trait will normally be derived using `#[derive(Versioned)]`.
24///
25// How will the macro know which versions exist?
26// a) Macro will assume that every version [1..latest] exists
27//    - and maybe there's a macro to generate stubs for missing versions?
28// b) User needs to specify a range or list of versions
29pub trait UpgradeLatest: DeserializeOwned + Versioned {
30    /// Deserialize version `ver` of the target struct, then upgrade it to the latest version.
31    fn upgrade_latest<Src>(src: &mut Src, header: Src::Header) -> Result<Self, Src::Error>
32    where
33        Src: DataSource;
34}
35
36/// `DataSource` allows user-defined IO, deserialization, and
37/// error handling.
38///
39pub trait DataSource {
40    /// A user-defined error type.
41    ///
42    /// This error type will be returned from [`read_header`][Self::read_header]
43    /// and [`read_message`][Self::read_message].
44    /// It's probably a good idea for it to be able to represent IO errors,
45    /// deserialization errors, and "unknown message" errors.
46    type Error;
47    /// A user-defined header struct.
48    ///
49    /// The `Header` is a way of communicating what kind of message is being
50    /// sent, along with the message version.
51    type Header: GroupHeader;
52
53    /// Read a header from the data source.
54    ///
55    /// This is a user-defined function that will read the next header.
56    /// The data in the header will be used to determine what kind of
57    /// message comes next.
58    ///
59    fn read_header(&mut self) -> Result<Self::Header, Self::Error>;
60
61    /// Read a message from the data source.
62    ///
63    /// This is a user-defined function that will deserialize a message
64    /// of type `T`.
65    fn read_message<T>(&mut self, header: &Self::Header) -> Result<T, Self::Error>
66    where
67        T: DeserializeOwned;
68
69    /// An unknown message id was received.
70    ///
71    /// This is a user-defined function that constructs an error value.
72    /// This function will be called by [`GroupDeserialize::read_message`]
73    /// when an unknown message is received (a message with an unknown
74    /// message id).
75    ///
76    fn unknown_message(&self, msg_id: u16) -> Self::Error {
77        panic!("unknown message id {}", msg_id);
78    }
79
80    /// An unknown version of a known message was received.
81    ///
82    /// This is a user-defined function that constructs an error value.
83    /// This function will be called by [`GroupDeserialize::read_message`]
84    /// when a known message id is received, but with a message version that
85    /// is unknown.
86    ///
87    fn unknown_version<T>(&self, ver: u16) -> Self::Error {
88        panic!("unknown version {} for {}", ver, type_name::<T>());
89    }
90
91    /// Expected a specific message type, but got a different message id.
92    ///
93    /// This is a user-defined function that constructs an error value.
94    /// This function will be called by [`GroupDeserialize::expect_message`]
95    /// when a different message id is received from the message that was
96    /// specified.
97    ///
98    fn unexpected_message<T>(&self, msg_id: u16) -> Self::Error {
99        panic!(
100            "unexpected message id {} (expected {})",
101            msg_id,
102            type_name::<T>()
103        );
104    }
105}
106
107/// Useful functions for `DataSource`.
108///
109/// There is a blanket implementation of this trait, so that any
110/// [`DataSource`] type can use these functions.
111pub trait DataSourceExt: DataSource {
112    /// Read a specific message type from the `DataSource`.
113    ///
114    /// This will read the message header, and if the message id matches
115    /// the type `T` that was requested, read the message.
116    /// The message will be upgraded to the latest version, and then
117    /// returned.
118    fn expect_message<T>(&mut self) -> Result<T, Self::Error>
119    where
120        T: MessageId + UpgradeLatest;
121}
122
123impl<Src> DataSourceExt for Src
124where
125    Src: DataSource,
126{
127    fn expect_message<T>(&mut self) -> Result<T, Src::Error>
128    where
129        Src: DataSource,
130        T: MessageId + UpgradeLatest,
131    {
132        let header: Src::Header = self.read_header()?;
133        if header.msg_id() == T::MSG_ID {
134            T::upgrade_latest(self, header)
135        } else {
136            // Call the user-supplied error fn
137            Err(self.unexpected_message::<T>(header.msg_id()))
138        }
139    }
140}
141
142/// A derived trait that can deserialize any message from a group.
143pub trait GroupDeserialize: Sized {
144    /// Read the next message from the `DataSource`.
145    ///
146    /// This will read the message header, and if the message id and
147    /// message version are known, also read the message.
148    /// The message will be upgraded to the latest version, and then
149    /// returned as an enum variant (in the `Self` enum).
150    fn read_message<Src>(src: &mut Src) -> Result<Self, Src::Error>
151    where
152        Src: DataSource;
153}
154
155/// `DataSink` allows user-defined IO, deserialization, and
156/// error handling.
157///
158pub trait DataSink {
159    /// A user-defined error type.
160    ///
161    /// This error type will be returned from all trait member functions.
162    /// It's probably a good idea for it to be able to represent IO errors,
163    /// deserialization errors, and "unknown message" errors.
164    type Error;
165
166    /// Write a header and message to the data sink.
167    ///
168    fn write_message<T>(&mut self, msg: &T) -> Result<(), Self::Error>
169    where
170        T: Serialize + Versioned,
171        T::Base: MessageId;
172}