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
//! SERializers & DEserializers (traits & implementations) for our [SocketServer]


use std::fmt::Debug;
use serde::{Serialize, Deserialize};
use once_cell::sync::Lazy;


/// Trait that should be implemented by enums that model the "local messages" to be sent to the remote peer --
/// "local messages" may either be messages generated by the server or by the client, depending on if you're building a server or client.\
/// This trait, therefore, specifies how to:
///   * `serialize()` enum variants into a String (like RON, for textual protocols) to be sent to the remote peer
///   * inform the peer if any wrong input was sent -- the network processor will handle that special case.
pub trait ReactiveMessagingSerializer<LocalPeerMessages: ReactiveMessagingSerializer<LocalPeerMessages> + Send + PartialEq + Debug> {

    /// Local messages serializer: transforms a strong typed `message` into a sequence of bytes, put in `buffer`\
    /// -- not appending any '\n'.
    /// IMPLEMENTORS: #[inline(always)]
    fn serialize(remote_message: &LocalPeerMessages, buffer: &mut Vec<u8>);

    /// Called whenever the local processor found an error -- the returned message should be as descriptive as possible.\
    /// IMPLEMENTORS: #[inline(always)]
    fn processor_error_message(err: String) -> LocalPeerMessages;
}

/// Trait that should be implemented by enums that model the "remote messages" to be consumed by a "Responsive Processor" --
/// "remote messages" may either be messages produced by the remote server or by the remote client (when we are implementing the opposite peer).\
/// This trait, therefore, specifies how to `deserialize()` enum variants received by the remote peer (like RON, for textual protocols)
pub trait ReactiveMessagingDeserializer<T> {

    /// Local messages deserializer: transform a textual `message` into a string typed value.\
    /// IMPLEMENTORS: #[inline(always)]
    fn deserialize(remote_message: &[u8]) -> Result<T, Box<dyn std::error::Error + Sync + Send>>;
}


// RON SERDE
////////////

static RON_DESERIALIZER_CONFIG: Lazy<ron::Options> = Lazy::new(ron::Options::default);

/// RON serializer
#[inline(always)]
pub fn ron_serializer<T: ?Sized + Serialize>(message: &T, buffer: &mut Vec<u8>) -> Result<(), ron::Error> {
    buffer.clear();
    let mut serializer = ron::Serializer::with_options(buffer, None, ron::Options::default())?;
    message.serialize(&mut serializer)?;
    Ok(())
}

/// RON deserializer
#[inline(always)]
pub fn ron_deserializer<T: for<'r> Deserialize<'r>>(message: &[u8]) -> Result<T, Box<dyn std::error::Error + Sync + Send>> {
    RON_DESERIALIZER_CONFIG.from_bytes(message)
        .map_err(|err| Box::from(format!("RON deserialization error for message '{:?}': {}", std::str::from_utf8(message), err)))
}


/// Unit tests for our socket server [serde](self) module
#[cfg(any(test,doc))]
mod tests {
    use super::*;


    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    pub enum Messages {
        Echo(String),
        Recursive(Option<Box<Messages>>)
    }


    /// assures RON serialization / deserialization works for all client / server messages
    #[cfg_attr(not(doc),test)]
    fn ron_serde_for_server_only() {
        let mut buffer = Vec::<u8>::with_capacity(16);
        let message = Messages::Echo(String::from("This is an error message"));
        let expected = "Echo(\"This is an error message\")";
        ron_serializer(&message, &mut buffer).expect("calling `ron_serializer()`");
        let observed = String::from_utf8(buffer).expect("Ron should be utf-8");
        assert_eq!(observed, expected, "RON serialization is not good");

        let message = "Recursive(Some(Recursive(Some(Echo(\"here it is\")))))".as_bytes();
        let expected = Messages::Recursive(Some(Box::new(Messages::Recursive(Some(Box::new(Messages::Echo(String::from("here it is"))))))));
        let observed = ron_deserializer::<Messages>(message)
            .expect("RON deserialization failed");
        assert_eq!(observed, expected, "RON deserialization is not good");
    }
}