protosocket/encoding.rs
1use crate::{DeserializeError, Serialize};
2
3/// A codec combines an encoder and decoder for a message type.
4///
5/// You can make a codec via a tuple of `(Encoder, Decoder)` or
6/// by implementing one yourself.
7///
8/// ## Buffer lifecycles
9/// The lifecycle of a message, with respect to encoding and decoding, is:
10///
11/// ### 1 decode
12/// `Decoder::decode()` produces a Message from inbound bytes.
13/// If you want to reuse allocations, you can pull from your own pool in here.
14///
15/// ### 2 your application process
16/// If you want to reuse the decoder memory later, you will either need to use
17/// a smart pointer on Drop, or you will need to carry the buffer into your
18/// logical response message type. This way, it can be delivered back to the
19/// Codec via `Encoder::encode()` later.
20///
21/// ### 3 encode
22/// `Encoder::encode()` produces outbound bytes from a logical Message. This is
23/// where you can return decoder buffers to your pool, if you carried them through.
24///
25/// ### 4 buffer return
26/// After the encoded bytes are sent, `Encoder::return_buffer()` is called with
27/// the serialized buffer. You can reuse or drop it as appropriate.
28///
29/// ## About pooling
30/// The Encoder's encode->return_buffer cycle is independent of the Decoder's lifecycle.
31/// Pooling for the Encoder is easy, and you should totally do it. `protosocket`
32/// provides a `PooledEncoder` wrapper and a `Serialize` trait you can use for the easiest
33/// way to pool your outbound buffer allocations.
34///
35/// Decoder pooling is more application-specific, and depends very much on your encoding and
36/// application types for its usefulness, so you will need to implement it yourself.
37pub trait Codec: Encoder + Decoder {}
38
39impl<E, D> Codec for (E, D)
40where
41 E: Encoder,
42 D: Decoder,
43{
44}
45impl<E, D> Encoder for (E, D)
46where
47 E: Encoder,
48 D: Decoder,
49{
50 type Message = E::Message;
51 type Serialized = E::Serialized;
52 fn encode(&mut self, message: Self::Message) -> Self::Serialized {
53 self.0.encode(message)
54 }
55
56 fn return_buffer(&mut self, buffer: Self::Serialized) {
57 self.0.return_buffer(buffer);
58 }
59}
60impl<E, D> Decoder for (E, D)
61where
62 E: Encoder,
63 D: Decoder,
64{
65 type Message = D::Message;
66 fn decode(
67 &mut self,
68 buffer: impl bytes::Buf,
69 ) -> std::result::Result<(usize, Self::Message), DeserializeError> {
70 self.1.decode(buffer)
71 }
72}
73
74/// An encoder takes messages and produces outbound bytes.
75pub trait Encoder {
76 /// The message type consumed by this serializer.
77 type Message;
78
79 /// The type this serializer produces.
80 ///
81 /// If you want to write to raw vectors, consider wrapping your serializer
82 /// with [PooledEncoder] and using that instead.
83 type Serialized: bytes::Buf;
84
85 /// Encode a message into a buffer.
86 fn encode(&mut self, message: Self::Message) -> Self::Serialized;
87
88 /// Buffers are sent back to the encoder once the message is sent.
89 /// Buffers are not guaranteed to be advanced to the end.
90 /// You can reset and reuse your buffer, if appropriate.
91 fn return_buffer(&mut self, _buffer: Self::Serialized) {
92 // drop by default
93 }
94}
95
96/// A decoder takes inbound bytes and produces messages.
97pub trait Decoder {
98 /// The message type produced by this deserializer.
99 type Message;
100
101 /// Decode a message from the buffer, or tell why you can't.
102 ///
103 /// You must not consume more bytes than the message you produce.
104 fn decode(
105 &mut self,
106 buffer: impl bytes::Buf,
107 ) -> std::result::Result<(usize, Self::Message), DeserializeError>;
108}
109
110impl<T> Encoder for T
111where
112 T: Serialize,
113{
114 type Message = T::Message;
115 type Serialized = OwnedBuffer;
116
117 #[cfg_attr(
118 feature = "tracing",
119 tracing::instrument(skip_all, name = "raw_serialize")
120 )]
121 fn encode(&mut self, message: Self::Message) -> Self::Serialized {
122 let mut buffer = Vec::new();
123 self.serialize_into_buffer(message, &mut buffer);
124 OwnedBuffer::new(buffer)
125 }
126}
127
128/// A basic Buf wrapper for a byte array. This works for simple apis, but if you
129/// have latency, memory, or cpu constraints, you should be using PooledEncoder
130/// or another more sophisticated memory reuse mechanism.
131pub struct OwnedBuffer {
132 buffer: Vec<u8>,
133 cursor: usize,
134}
135impl OwnedBuffer {
136 fn new(buffer: Vec<u8>) -> Self {
137 Self { buffer, cursor: 0 }
138 }
139}
140impl bytes::Buf for OwnedBuffer {
141 #[inline(always)]
142 fn remaining(&self) -> usize {
143 self.buffer.len() - self.cursor
144 }
145
146 #[inline(always)]
147 fn chunk(&self) -> &[u8] {
148 &self.buffer[self.cursor..]
149 }
150
151 #[inline(always)]
152 fn advance(&mut self, cnt: usize) {
153 assert!(
154 self.cursor + cnt <= self.buffer.len(),
155 "can't advance past the end of the buffer"
156 );
157 self.cursor += cnt;
158 }
159}