Skip to main content

acktor_ipc/
codec.rs

1//! Codec traits for encoding and decoding remote messages over IPC channels.
2//!
3//! This module provides the [`Encode`] and [`Decode`] traits along with implementations for
4//! primitive types, standard library containers, and acktor types.
5//!
6
7use bytes::{Bytes, BytesMut};
8
9use acktor::{Actor, Address, Message, Recipient, SenderId};
10
11use crate::remote_actor::RemoteActorRegistry;
12use crate::remote_address::RemoteAddress;
13use crate::remote_message::ToRemoteMessageRecipient;
14use crate::session::Session;
15
16mod errors;
17pub use errors::{DecodeError, EncodeError};
18
19mod control_message;
20mod ipc_message;
21
22mod protobuf_helper;
23
24mod common_codec;
25#[cfg(not(feature = "prost-codec"))]
26mod default_codec;
27#[cfg(feature = "prost-codec")]
28mod prost_codec;
29
30/// Context passed through every [`Encode::encode`] call.
31///
32/// Carries the remote actor registry so that when the address of an actor which can be reached
33/// over IPC is serialized for the first time, it can self-register in the registry.
34#[derive(Debug, Clone)]
35pub struct EncodeContext {
36    /// The actor registry associated with this context.
37    registry: RemoteActorRegistry,
38}
39
40impl EncodeContext {
41    /// Constructs a new [`EncodeContext`] from the given actor registry.
42    #[inline]
43    pub fn new(registry: RemoteActorRegistry) -> Self {
44        Self { registry }
45    }
46
47    /// Creates a new [`DecodeContext`] from this context and the given remote session.
48    #[inline]
49    pub fn create_decode_context(&self, session: Address<Session>) -> DecodeContext {
50        DecodeContext {
51            session,
52            registry: self.registry.clone(),
53        }
54    }
55
56    /// Registers the given address/recipient in the actor registry.
57    pub fn register<A>(&self, address: &A) -> Result<(), EncodeError>
58    where
59        A: SenderId + ToRemoteMessageRecipient,
60    {
61        let index = address.index();
62
63        if self.registry.contains_index(index) {
64            return Ok(());
65        }
66
67        if index.is_remote() {
68            Err(EncodeError::EncodeRemoteAddress)
69        } else {
70            self.registry.insert(address.to_remote_message_recipient()?);
71
72            Ok(())
73        }
74    }
75}
76
77/// Context passed through every [`Decode::decode`] call.
78///
79/// Carries the IPC session actor address and the remote actor registry which are needed to
80/// reconstruct [`RemoteAddress`]s during decoding.
81#[derive(Debug, Clone)]
82pub struct DecodeContext {
83    /// The remote session associated with this context.
84    session: Address<Session>,
85    /// The actor registry associated with this context.
86    registry: RemoteActorRegistry,
87}
88
89impl DecodeContext {
90    /// Constructs a new [`DecodeContext`] from the given remote session and the actor registry.
91    #[inline]
92    pub fn new(session: Address<Session>, registry: RemoteActorRegistry) -> Self {
93        Self { session, registry }
94    }
95
96    /// Creates a new [`EncodeContext`] from this context.
97    #[inline]
98    pub fn create_encode_context(&self) -> EncodeContext {
99        EncodeContext {
100            registry: self.registry.clone(),
101        }
102    }
103
104    /// Creates a new [`RemoteAddress`] from the given actor ID.
105    #[inline]
106    pub fn create_remote_address(&self, actor_id: u64) -> Result<RemoteAddress, DecodeError> {
107        if actor_id.is_remote() {
108            Err(DecodeError::DecodeRemoteAddress)
109        } else {
110            Ok(RemoteAddress::new(
111                actor_id,
112                self.session.clone(),
113                self.registry.clone(),
114            ))
115        }
116    }
117}
118
119/// Describes how to encode a remote message.
120pub trait Encode {
121    /// Message identifier. A remote message should have an unique identifier so the
122    /// `Handler<RemoteMessage>` can dispatch the message to the proper handler.
123    ///
124    /// Here `unique` means that for one particular actor type, the messages that can be handled
125    /// by it must have unique identifiers, but two different actor can have messages share the
126    /// same identifier.
127    ///
128    /// The identifier in [`Encode`] and [`Decode`] must be the same for the same message type.
129    ///
130    /// The derived implementation of `Handler<RemoteMessage>` relies on this identifier to work
131    /// properly. If you do not use the derived implementation of `Handler<RemoteMessage>`, you
132    /// can ignore this requirement and just use the default value.
133    ///
134    /// (u64::MAX - 255) ~ u64::MAX is reserved for internal use.
135    const ID: u64 = 0;
136
137    /// Returns the number of bytes this value will encode to.
138    fn encoded_len(&self) -> usize;
139
140    /// Encodes the value into the provided buffer.
141    fn encode(&self, buf: &mut BytesMut, ctx: Option<&EncodeContext>) -> Result<(), EncodeError>;
142
143    /// Encodes the value into a freshly allocated [`Bytes`].
144    fn encode_to_bytes(&self, ctx: Option<&EncodeContext>) -> Result<Bytes, EncodeError> {
145        let mut buf = BytesMut::with_capacity(self.encoded_len());
146        self.encode(&mut buf, ctx)?;
147
148        Ok(buf.freeze())
149    }
150}
151
152/// Describes how to decode a remote message.
153pub trait Decode {
154    /// Message identifier. A remote message should have an unique identifier so the
155    /// `Handler<RemoteMessage>` can dispatch the message to the proper handler.
156    ///
157    /// Here `unique` means that for one particular actor type, the messages that can be handled
158    /// by it must have unique identifiers, but two different actor can have messages share the
159    /// same identifier.
160    ///
161    /// The identifier in [`Encode`] and [`Decode`] must be the same for the same message type.
162    ///
163    /// The derived implementation of `Handler<RemoteMessage>` relies on this identifier to work
164    /// properly. If you do not use the derived implementation of `Handler<RemoteMessage>`, you
165    /// can ignore this requirement and just use the default value.
166    ///
167    /// (u64::MAX - 255) ~ u64::MAX is reserved for internal use.
168    const ID: u64 = 0;
169
170    /// Decodes the remote message from the provided buffer.
171    fn decode(buf: Bytes, ctx: Option<&DecodeContext>) -> Result<Self, DecodeError>
172    where
173        Self: Sized;
174}
175
176impl<A> Encode for Address<A>
177where
178    A: Actor,
179{
180    #[inline]
181    fn encoded_len(&self) -> usize {
182        prost::Message::encoded_len(&self.index())
183    }
184
185    #[inline]
186    fn encode(&self, buf: &mut BytesMut, ctx: Option<&EncodeContext>) -> Result<(), EncodeError> {
187        // auto-register the address if it is an local address
188        ctx.ok_or(EncodeError::MissingEncodeContext)?
189            .register(self)?;
190        prost::Message::encode(&self.index(), buf).map_err(Into::into)
191    }
192}
193
194impl<M> Encode for Recipient<M>
195where
196    M: Message,
197{
198    #[inline]
199    fn encoded_len(&self) -> usize {
200        prost::Message::encoded_len(&self.index())
201    }
202
203    #[inline]
204    fn encode(&self, buf: &mut BytesMut, ctx: Option<&EncodeContext>) -> Result<(), EncodeError> {
205        // auto-register the address if it is an local address
206        ctx.ok_or(EncodeError::MissingEncodeContext)?
207            .register(self)?;
208        prost::Message::encode(&self.index(), buf).map_err(Into::into)
209    }
210}
211
212impl Decode for RemoteAddress {
213    #[inline]
214    fn decode(buf: Bytes, ctx: Option<&DecodeContext>) -> Result<Self, DecodeError> {
215        let actor_id = <u64 as prost::Message>::decode(buf)?;
216        ctx.ok_or(DecodeError::MissingDecodeContext)?
217            .create_remote_address(actor_id)
218    }
219}
220
221#[cfg(test)]
222mod test {
223    use super::*;
224
225    macro_rules! create_test {
226        ($name:ident, $type:ty, $value:expr) => {
227            #[test]
228            fn $name() {
229                let value = $value;
230                let buf = Encode::encode_to_bytes(&value, None).unwrap();
231                let decoded = <$type as Decode>::decode(buf, None).unwrap();
232                assert_eq!(value, decoded);
233            }
234        };
235    }
236
237    create_test!(test_unit, (), ());
238    create_test!(test_bool, bool, true);
239    create_test!(test_u8, u8, 42_u8);
240    create_test!(test_u16, u16, 4242_u16);
241    create_test!(test_u32, u32, 424242_u32);
242    create_test!(test_u64, u64, 42424242_u64);
243    create_test!(test_usize, usize, 4242424242_usize);
244    create_test!(test_i8, i8, -42_i8);
245    create_test!(test_i16, i16, -4242_i16);
246    create_test!(test_i32, i32, -424242_i32);
247    create_test!(test_i64, i64, -42424242_i64);
248    create_test!(test_isize, isize, -4242424242_isize);
249    create_test!(test_f32, f32, 42.42_f32);
250    create_test!(test_f64, f64, 42.42_f64);
251    create_test!(test_string, String, "hello".to_string());
252
253    create_test!(test_vec_bool, Vec<bool>, vec![true, false, true]);
254    create_test!(test_vec_u8, Vec<u8>, vec![42_u8, 42_u8, 42_u8]);
255    create_test!(test_vec_u16, Vec<u16>, vec![4242_u16, 4242_u16, 4242_u16]);
256    create_test!(
257        test_vec_u32,
258        Vec<u32>,
259        vec![424242_u32, 424242_u32, 424242_u32]
260    );
261    create_test!(
262        test_vec_u64,
263        Vec<u64>,
264        vec![42424242_u64, 42424242_u64, 42424242_u64]
265    );
266    create_test!(
267        test_vec_usize,
268        Vec<usize>,
269        vec![4242424242_usize, 4242424242_usize, 4242424242_usize]
270    );
271    create_test!(test_vec_i8, Vec<i8>, vec![-42_i8, -42_i8, -42_i8]);
272    create_test!(
273        test_vec_i16,
274        Vec<i16>,
275        vec![-4242_i16, -4242_i16, -4242_i16]
276    );
277    create_test!(
278        test_vec_i32,
279        Vec<i32>,
280        vec![-424242_i32, -424242_i32, -424242_i32]
281    );
282    create_test!(
283        test_vec_i64,
284        Vec<i64>,
285        vec![-42424242_i64, -42424242_i64, -42424242_i64]
286    );
287    create_test!(
288        test_vec_isize,
289        Vec<isize>,
290        vec![-4242424242_isize, -4242424242_isize, -4242424242_isize]
291    );
292    create_test!(
293        test_vec_f32,
294        Vec<f32>,
295        vec![42.42_f32, 42.42_f32, 42.42_f32]
296    );
297    create_test!(
298        test_vec_f64,
299        Vec<f64>,
300        vec![42.42_f64, 42.42_f64, 42.42_f64]
301    );
302
303    create_test!(test_option_none, Option<u16>, None::<u16>);
304    create_test!(test_option_some, Option<u16>, Some(4242_u16));
305
306    create_test!(test_result_ok, Result<u32, String>, Ok::<u32, String>(424242_u32));
307    create_test!(test_result_err, Result<u32, String>, Err::<u32, String>("hello".into()));
308    create_test!(
309        test_result_nested_option,
310        Result<Option<u32>, String>,
311        Ok::<Option<u32>, String>(Some(424242_u32))
312    );
313
314    create_test!(
315        test_box_vec,
316        Box<Vec<u16>>,
317        Box::new(vec![4242_u16, 4242_u16, 4242_u16])
318    );
319    create_test!(
320        test_arc_string,
321        std::sync::Arc<String>,
322        std::sync::Arc::new("hello".to_string())
323    );
324
325    create_test!(test_tuple2, (u32, String), (42_u32, "hello".to_string()));
326    create_test!(
327        test_tuple4,
328        (i64, bool, String, Option<u16>),
329        (-42424242_i64, true, "hello".to_string(), Some(4242_u16))
330    );
331    create_test!(
332        test_nested_tuple,
333        (u8, (i32, String)),
334        (42_u8, (-424242_i32, "hello".to_string()))
335    );
336
337    #[test]
338    fn test_result_string() {
339        for value in [
340            Ok::<String, String>("hello".to_string()),
341            Err::<String, String>("boom".to_string()),
342        ] {
343            let expected_len = value.encoded_len();
344            let mut buf = BytesMut::with_capacity(expected_len);
345            value.encode(&mut buf, None).unwrap();
346            assert_eq!(
347                buf.len(),
348                expected_len,
349                "encoded_len mismatch for {value:?}"
350            );
351
352            let decoded = <Result<String, String> as Decode>::decode(buf.freeze(), None).unwrap();
353            assert_eq!(value, decoded);
354        }
355    }
356}