1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! Define message groups for automatic dispatching.
//!
//! A message group is a collection of messages that may be used together.
//! For example, a file format or a network protocol may form a group.
//!

use crate::{MessageId, Versioned};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::any::type_name;

/// A data structure that contains a message-id and version fields.

pub trait GroupHeader {
    /// Retrieve the message id.
    fn msg_id(&self) -> u16;
    /// Retrieve the message version.
    fn msg_ver(&self) -> u16;
}

/// A trait for deserializing any version of a [`Versioned`] data structure.
///
/// This trait will normally be derived using `#[derive(Versioned)]`.
///
// How will the macro know which versions exist?
// a) Macro will assume that every version [1..latest] exists
//    - and maybe there's a macro to generate stubs for missing versions?
// b) User needs to specify a range or list of versions
pub trait UpgradeLatest: DeserializeOwned + Versioned {
    /// Deserialize version `ver` of the target struct, then upgrade it to the latest version.
    fn upgrade_latest<Src>(src: &mut Src, header: Src::Header) -> Result<Self, Src::Error>
    where
        Src: DataSource;
}

/// `DataSource` allows user-defined IO, deserialization, and
/// error handling.
///
pub trait DataSource {
    /// A user-defined error type.
    ///
    /// This error type will be returned from [`read_header`][Self::read_header]
    /// and [`read_message`][Self::read_message].
    /// It's probably a good idea for it to be able to represent IO errors,
    /// deserialization errors, and "unknown message" errors.
    type Error;
    /// A user-defined header struct.
    ///
    /// The `Header` is a way of communicating what kind of message is being
    /// sent, along with the message version.
    type Header: GroupHeader;

    /// Read a header from the data source.
    ///
    /// This is a user-defined function that will read the next header.
    /// The data in the header will be used to determine what kind of
    /// message comes next.
    ///
    fn read_header(&mut self) -> Result<Self::Header, Self::Error>;

    /// Read a message from the data source.
    ///
    /// This is a user-defined function that will deserialize a message
    /// of type `T`.
    fn read_message<T>(&mut self, header: &Self::Header) -> Result<T, Self::Error>
    where
        T: DeserializeOwned;

    /// An unknown message id was received.
    ///
    /// This is a user-defined function that constructs an error value.
    /// This function will be called by [`GroupDeserialize::read_message`]
    /// when an unknown message is received (a message with an unknown
    /// message id).
    ///
    fn unknown_message(&self, msg_id: u16) -> Self::Error {
        panic!("unknown message id {}", msg_id);
    }

    /// An unknown version of a known message was received.
    ///
    /// This is a user-defined function that constructs an error value.
    /// This function will be called by [`GroupDeserialize::read_message`]
    /// when a known message id is received, but with a message version that
    /// is unknown.
    ///
    fn unknown_version<T>(&self, ver: u16) -> Self::Error {
        panic!("unknown version {} for {}", ver, type_name::<T>());
    }

    /// Expected a specific message type, but got a different message id.
    ///
    /// This is a user-defined function that constructs an error value.
    /// This function will be called by [`GroupDeserialize::expect_message`]
    /// when a different message id is received from the message that was
    /// specified.
    ///
    fn unexpected_message<T>(&self, msg_id: u16) -> Self::Error {
        panic!(
            "unexpected message id {} (expected {})",
            msg_id,
            type_name::<T>()
        );
    }
}

/// Useful functions for `DataSource`.
///
/// There is a blanket implementation of this trait, so that any
/// [`DataSource`] type can use these functions.
pub trait DataSourceExt: DataSource {
    /// Read a specific message type from the `DataSource`.
    ///
    /// This will read the message header, and if the message id matches
    /// the type `T` that was requested, read the message.
    /// The message will be upgraded to the latest version, and then
    /// returned.
    fn expect_message<T>(&mut self) -> Result<T, Self::Error>
    where
        T: MessageId + UpgradeLatest;
}

impl<Src> DataSourceExt for Src
where
    Src: DataSource,
{
    fn expect_message<T>(&mut self) -> Result<T, Src::Error>
    where
        Src: DataSource,
        T: MessageId + UpgradeLatest,
    {
        let header: Src::Header = self.read_header()?;
        if header.msg_id() == T::MSG_ID {
            T::upgrade_latest(self, header)
        } else {
            // Call the user-supplied error fn
            Err(self.unexpected_message::<T>(header.msg_id()))
        }
    }
}

/// A derived trait that can deserialize any message from a group.
pub trait GroupDeserialize: Sized {
    /// Read the next message from the `DataSource`.
    ///
    /// This will read the message header, and if the message id and
    /// message version are known, also read the message.
    /// The message will be upgraded to the latest version, and then
    /// returned as an enum variant (in the `Self` enum).
    fn read_message<Src>(src: &mut Src) -> Result<Self, Src::Error>
    where
        Src: DataSource;
}

/// `DataSink` allows user-defined IO, deserialization, and
/// error handling.
///
pub trait DataSink {
    /// A user-defined error type.
    ///
    /// This error type will be returned from all trait member functions.
    /// It's probably a good idea for it to be able to represent IO errors,
    /// deserialization errors, and "unknown message" errors.
    type Error;

    /// Write a header and message to the data sink.
    ///
    fn write_message<T>(&mut self, msg: &T) -> Result<(), Self::Error>
    where
        T: Serialize + Versioned,
        T::Base: MessageId;
}