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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
//! Serializer implementations for messages.
use thiserror::Error;

use crate::host::api::message;

#[derive(Error, Debug)]
pub enum EncodeError {
    #[error("serialization to Bincode failed: {0}")]
    Bincode(#[from] bincode::Error),
    #[cfg(feature = "msgpack_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "msgpack_serializer")))]
    #[error("serialization to MessagePack failed: {0}")]
    MessagePack(#[from] rmp_serde::encode::Error),
    #[cfg(feature = "json_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "json_serializer")))]
    #[error("serialization to Json failed: {0}")]
    Json(#[from] serde_json::error::Error),
    #[cfg(feature = "protobuf_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "protobuf_serializer")))]
    #[error("serialization to Protocol Buffers failed: {0}")]
    ProtocolBuffers(#[from] protobuf::Error),
    #[error("serialization failed: {0}")]
    IO(#[from] std::io::Error),
    #[error("serialization failed: {0}")]
    Custom(String),
}

#[derive(Error, Debug)]
pub enum DecodeError {
    #[error("deserialization from Bincode failed: {0}")]
    Bincode(#[from] bincode::Error),
    #[cfg(feature = "msgpack_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "msgpack_serializer")))]
    #[error("deserialization from MessagePack failed: {0}")]
    MessagePack(#[from] rmp_serde::decode::Error),
    #[cfg(feature = "json_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "json_serializer")))]
    #[error("deserialization from Json failed: {0}")]
    Json(#[from] serde_json::error::Error),
    #[cfg(feature = "protobuf_serializer")]
    #[cfg_attr(docsrs, doc(cfg(feature = "protobuf_serializer")))]
    #[error("deserialization from Protocol Buffers failed: {0}")]
    ProtocolBuffers(#[from] protobuf::Error),
    #[error("serialization failed: {0}")]
    IO(#[from] std::io::Error),
    #[error("deserialization failed: {0}")]
    Custom(String),
}

/// The `CanSerialize` trait is implemented for serializers that can encode and
/// decode the type `M`.
///
/// This trait is used across the whole lunatic API to allow us to switch out
/// serializers when sending messages between processes. Lunatic already ships
/// with support for a few well known serialization formats like json, message
/// pack, protocol buffers and bincode, that can be enabled with feature flags.
/// You can add others by implementing this trait.
///
/// The generic parameter `M` can be used to express trait dependencies on
/// messages for each concrete serializer type. Let's say we want to use
/// `Bincode` to serialize messages, we still need to limit the message types to
/// a specific subset that implement the `serde::Serialize` and
/// `serde::Deserialize` traits. We can express this dependency in the following
/// way:
///
/// ```no_run
/// impl<M: serde::Serialize + serde::Deserialize> Serializer<M> for Bincode {
///     fn encode(message: M) -> Error {
///         // `message` is guaranteed to implement the `serde::Serialize`
///         // trait and can be encoded here using `Bincode`.
///     }
///     // ...
/// }
/// ```
///
/// Serializers that can work with the [`Read`](std::io::Read) &
/// [`Write`](std::io::Write) traits are generally better suited for lunatic's
/// FFI, that works on a streaming basis and can avoid unnecessary copies.
/// Serializer that require raw access to chunks of mutable memories (e.g.
/// `Prost`) require additional copies between guest and host memories.
pub trait CanSerialize<M> {
    fn encode(message: &M) -> Result<(), EncodeError>;
    fn decode() -> Result<M, DecodeError>;
}

/// A `Bincode` serializer.
///
/// It can serialize any message that satisfies the traits:
/// - `serde::Serialize`
/// - `serde::de::DeserializeOwned`
///
/// `serde::de::DeserializeOwned` is used here instead of
/// `serde::Deserialize<'de>` because the messages are extracted from a stream
/// that lives inside the VM, has an unknown lifetime and can't be referenced
/// from the guest. `serde::de::DeserializeOwned` is automatically implemented
/// for each type that also implements `serde::Deserialize<'de>`.
#[derive(Hash, Debug)]
pub struct Bincode {}

impl<M> CanSerialize<M> for Bincode
where
    M: serde::Serialize + serde::de::DeserializeOwned,
{
    fn encode(message: &M) -> Result<(), EncodeError> {
        Ok(bincode::serialize_into(MessageRw {}, message)?)
    }

    fn decode() -> Result<M, DecodeError> {
        Ok(bincode::deserialize_from(MessageRw {})?)
    }
}

/// A `MessagePack` serializer.
///
/// It can serialize any message that satisfies the traits:
/// - `serde::Serialize`
/// - `serde::de::DeserializeOwned`
///
/// Refer to the [`Bincode`] docs for the difference between
/// `serde::de::DeserializeOwned` and `serde::Deserialize<'de>`.
#[cfg(feature = "msgpack_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "msgpack_serializer")))]
#[derive(Debug, Hash)]
pub struct MessagePack {}

#[cfg(feature = "msgpack_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "msgpack_serializer")))]
impl<M> CanSerialize<M> for MessagePack
where
    M: serde::Serialize + serde::de::DeserializeOwned,
{
    fn encode(message: &M) -> Result<(), EncodeError> {
        use std::io::Write;
        let data = rmp_serde::to_vec(message)?;
        Ok(MessageRw {}.write_all(&data)?)
    }

    fn decode() -> Result<M, DecodeError> {
        Ok(rmp_serde::decode::from_read(MessageRw {})?)
    }
}

/// A `Json` serializer.
///
/// It can serialize any message that satisfies the traits:
/// - `serde::Serialize`
/// - `serde::de::DeserializeOwned`
///
/// Refer to the [`Bincode`] docs for the difference between
/// `serde::de::DeserializeOwned` and `serde::Deserialize<'de>`.
#[cfg(feature = "json_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "json_serializer")))]
#[derive(Debug, Hash)]
pub struct Json {}

#[cfg(feature = "json_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "json_serializer")))]
impl<M> CanSerialize<M> for Json
where
    M: serde::Serialize + serde::de::DeserializeOwned,
{
    fn encode(message: &M) -> Result<(), EncodeError> {
        use std::io::Write;
        let data = serde_json::to_vec(message)?;
        Ok(MessageRw {}.write_all(&data)?)
    }

    fn decode() -> Result<M, DecodeError> {
        Ok(serde_json::from_reader(MessageRw {})?)
    }
}

/// The `ProtocolBuffers` serializer can serialize any message that satisfies
/// the trait `protobuf::Message`.
#[cfg(feature = "protobuf_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf_serializer")))]
#[derive(Debug, Hash)]
pub struct ProtocolBuffers {}

#[cfg(feature = "protobuf_serializer")]
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf_serializer")))]
impl<M> CanSerialize<M> for ProtocolBuffers
where
    M: protobuf::Message,
{
    fn encode(message: &M) -> Result<(), EncodeError> {
        use std::io::Write;
        let mut data = Vec::new();
        message.write_to_vec(&mut data)?;
        Ok(MessageRw {}.write_all(&data)?)
    }

    fn decode() -> Result<M, DecodeError> {
        Ok(M::parse_from_reader(&mut MessageRw {})?)
    }
}

/// A helper struct to read from and write to the message scratch buffer.
///
/// It simplifies streaming serialization/deserialization directly from the host
/// and avoids copies. Most serde based serializers can work directly with
/// streaming serialization.
#[derive(Debug, Hash)]
pub struct MessageRw {}

impl std::io::Read for MessageRw {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        Ok(unsafe { message::read_data(buf.as_mut_ptr(), buf.len()) })
    }
}

impl std::io::Write for MessageRw {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        Ok(unsafe { message::write_data(buf.as_ptr(), buf.len()) })
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}