luanti_protocol/wire/
ser.rs

1use anyhow::Result;
2use anyhow::bail;
3use std::num::TryFromIntError;
4
5use crate::types::CommandDirection;
6use crate::types::ProtocolContext;
7
8#[derive(Debug, Clone, thiserror::Error)]
9pub enum SerializeError {
10    #[error("Ran out of space while serializing: {0}")]
11    BufferLimit(String),
12    #[error("Invalid value: {0}")]
13    InvalidValue(String),
14    #[error("CompressionFailed: {0}")]
15    CompressionFailed(String),
16}
17
18impl From<TryFromIntError> for SerializeError {
19    fn from(other: TryFromIntError) -> SerializeError {
20        SerializeError::InvalidValue(format!("{other:?}"))
21    }
22}
23
24pub type SerializeResult = Result<()>;
25
26pub trait Serializer {
27    type Marker;
28
29    fn context(&self) -> ProtocolContext;
30
31    // Serializing a ToServer or ToClient command
32    fn direction(&self) -> CommandDirection;
33
34    // Request writing directly to a slice
35    // Needed for random access writes
36    // It is not guaranteed the 'f' is called.
37    fn write<F>(&mut self, length: usize, f: F) -> SerializeResult
38    where
39        F: FnOnce(&mut [u8]);
40
41    // Write bytes
42    fn write_bytes(&mut self, fragment: &[u8]) -> SerializeResult;
43
44    // Reserve some bytes for writing later.
45    fn write_marker(&mut self, length: usize) -> Result<Self::Marker, SerializeError>;
46
47    // Write to the marker
48    fn set_marker(&mut self, marker: Self::Marker, fragment: &[u8]) -> SerializeResult;
49
50    // Number of bytes written to the stream after the marker (not including the marker itself)
51    fn marker_distance(&self, marker: &Self::Marker) -> usize;
52}
53
54/// Serialize a Packet to a mutable slice
55pub struct SliceSerializer<'data> {
56    context: ProtocolContext,
57    offset: usize,
58    data: &'data mut [u8],
59    overflow: bool,
60}
61
62impl<'data> SliceSerializer<'data> {
63    pub fn new(context: ProtocolContext, data: &'data mut [u8]) -> Self {
64        Self {
65            context,
66            offset: 0,
67            data,
68            overflow: false,
69        }
70    }
71
72    /// Returns the finished serialized packet
73    /// This is a sub-slice of the original data slice provided
74    /// If the serializer ran out of space, returns None.
75    pub fn take(&self) -> Result<&[u8]> {
76        if self.overflow {
77            bail!(SerializeError::BufferLimit(
78                "SliceSerializer overflow".into()
79            ));
80        }
81        Ok(&self.data[..self.offset])
82    }
83}
84
85impl Serializer for SliceSerializer<'_> {
86    type Marker = (usize, usize);
87
88    fn context(&self) -> ProtocolContext {
89        self.context
90    }
91
92    fn direction(&self) -> CommandDirection {
93        self.context.dir
94    }
95
96    fn write_bytes(&mut self, fragment: &[u8]) -> SerializeResult {
97        if self.offset + fragment.len() > self.data.len() {
98            self.overflow = true;
99            bail!(SerializeError::BufferLimit(
100                "SliceSerializer out of space ".into(),
101            ));
102        }
103        self.data[self.offset..self.offset + fragment.len()].copy_from_slice(fragment);
104        self.offset += fragment.len();
105        Ok(())
106    }
107
108    fn write_marker(&mut self, length: usize) -> Result<Self::Marker, SerializeError> {
109        if self.offset + length > self.data.len() {
110            self.overflow = true;
111            Err(SerializeError::BufferLimit(
112                "SliceSerializer out of space ".into(),
113            ))
114        } else {
115            let marker = (self.offset, length);
116            self.offset += length;
117            Ok(marker)
118        }
119    }
120
121    fn set_marker(&mut self, marker: Self::Marker, fragment: &[u8]) -> SerializeResult {
122        let (offset, length) = marker;
123        if fragment.len() != length {
124            self.overflow = true;
125            bail!(SerializeError::InvalidValue("Marker has wrong size".into(),));
126        }
127        self.data[offset..offset + length].copy_from_slice(fragment);
128        Ok(())
129    }
130
131    fn marker_distance(&self, marker: &Self::Marker) -> usize {
132        let (offset, length) = marker;
133        self.offset - (offset + length)
134    }
135
136    fn write<F>(&mut self, length: usize, write_slice_fn: F) -> SerializeResult
137    where
138        F: FnOnce(&mut [u8]),
139    {
140        if self.offset + length > self.data.len() {
141            self.overflow = true;
142            bail!(SerializeError::BufferLimit(
143                "SliceSerializer out of space ".into(),
144            ))
145        }
146        write_slice_fn(&mut self.data[self.offset..self.offset + length]);
147        self.offset += length;
148        Ok(())
149    }
150}
151
152pub struct VecSerializer {
153    context: ProtocolContext,
154    data: Vec<u8>,
155}
156
157impl VecSerializer {
158    #[must_use]
159    pub fn new(context: ProtocolContext, initial_capacity: usize) -> Self {
160        Self {
161            context,
162            data: Vec::with_capacity(initial_capacity),
163        }
164    }
165
166    #[must_use]
167    pub fn take(self) -> Vec<u8> {
168        self.data
169    }
170}
171
172impl Serializer for VecSerializer {
173    type Marker = (usize, usize);
174
175    fn context(&self) -> ProtocolContext {
176        self.context
177    }
178
179    fn direction(&self) -> CommandDirection {
180        self.context.dir
181    }
182
183    fn write_bytes(&mut self, fragment: &[u8]) -> SerializeResult {
184        self.data.extend_from_slice(fragment);
185        Ok(())
186    }
187
188    fn write_marker(&mut self, length: usize) -> Result<Self::Marker, SerializeError> {
189        let marker = (self.data.len(), length);
190        self.data.resize(self.data.len() + length, 0_u8);
191        Ok(marker)
192    }
193
194    fn set_marker(&mut self, marker: Self::Marker, fragment: &[u8]) -> SerializeResult {
195        let (offset, length) = marker;
196        self.data[offset..offset + length].copy_from_slice(fragment);
197        Ok(())
198    }
199
200    fn marker_distance(&self, marker: &Self::Marker) -> usize {
201        let (offset, length) = marker;
202        self.data.len() - (offset + length)
203    }
204
205    fn write<F>(&mut self, length: usize, write_slice_fn: F) -> SerializeResult
206    where
207        F: FnOnce(&mut [u8]),
208    {
209        let offset = self.data.len();
210        self.data.resize(offset + length, 0_u8);
211        write_slice_fn(&mut self.data.as_mut_slice()[offset..offset + length]);
212        Ok(())
213    }
214}
215
216/// `MockSerializer`
217/// Computes the size of the serialized output without storing it
218pub struct MockSerializer {
219    context: ProtocolContext,
220    count: usize,
221}
222
223impl MockSerializer {
224    #[must_use]
225    pub fn new(context: ProtocolContext) -> Self {
226        Self { context, count: 0 }
227    }
228
229    /// How many bytes have been written so far
230    #[must_use]
231    #[expect(
232        clippy::len_without_is_empty,
233        reason = "seems to be unneeded in this context"
234    )]
235    pub fn len(&self) -> usize {
236        self.count
237    }
238}
239
240impl Serializer for MockSerializer {
241    type Marker = (usize, usize);
242
243    fn context(&self) -> ProtocolContext {
244        self.context
245    }
246
247    fn direction(&self) -> CommandDirection {
248        self.context.dir
249    }
250
251    fn write_bytes(&mut self, fragment: &[u8]) -> SerializeResult {
252        self.count += fragment.len();
253        Ok(())
254    }
255
256    fn write_marker(&mut self, length: usize) -> Result<Self::Marker, SerializeError> {
257        let marker = (self.count, length);
258        self.count += length;
259        Ok(marker)
260    }
261
262    fn set_marker(&mut self, _marker: Self::Marker, _fragment: &[u8]) -> SerializeResult {
263        Ok(())
264    }
265
266    fn marker_distance(&self, marker: &Self::Marker) -> usize {
267        let (offset, length) = marker;
268        self.count - (offset + length)
269    }
270
271    fn write<F>(&mut self, length: usize, _f: F) -> SerializeResult
272    where
273        F: FnOnce(&mut [u8]),
274    {
275        self.count += length;
276        Ok(())
277    }
278}
279
280pub trait Serialize {
281    type Input: ?Sized;
282    fn serialize<S: Serializer>(value: &Self::Input, serializer: &mut S) -> SerializeResult;
283}