tl_proto/
traits.rs

1use std::sync::Arc;
2
3/// Serialized object representation.
4///
5/// - [`Boxed`] - object with explicit type id. Can be used for enums or dynamic dispatch.
6/// - [`Bare`] - object without explicit type id. Can only be used for structs, or write-only enums.
7pub trait Repr: private::Sealed {}
8
9/// Object representation with explicit type id.
10/// Can be used for enums or dynamic dispatch.
11pub enum Boxed {}
12impl private::Sealed for Boxed {}
13impl Repr for Boxed {}
14
15/// Object representation without explicit type id.
16/// Can only be used for structs, or write-only enums.
17pub enum Bare {}
18impl private::Sealed for Bare {}
19impl Repr for Bare {}
20
21/// Specifies how this type can read from the packet.
22pub trait TlRead<'a>: Sized {
23    /// Serialized object representation.
24    type Repr: Repr;
25
26    /// Tries to read itself from bytes at the specified offset, incrementing that offset.
27    fn read_from(packet: &mut &'a [u8]) -> TlResult<Self>;
28}
29
30impl<'a, T> TlRead<'a> for Arc<T>
31where
32    T: TlRead<'a>,
33{
34    type Repr = T::Repr;
35
36    #[inline(always)]
37    fn read_from(packet: &mut &'a [u8]) -> TlResult<Self> {
38        match T::read_from(packet) {
39            Ok(data) => Ok(Arc::new(data)),
40            Err(e) => Err(e),
41        }
42    }
43}
44
45impl<'a, T> TlRead<'a> for Box<T>
46where
47    T: TlRead<'a>,
48{
49    type Repr = T::Repr;
50
51    #[inline(always)]
52    fn read_from(packet: &mut &'a [u8]) -> TlResult<Self> {
53        match T::read_from(packet) {
54            Ok(data) => Ok(Box::new(data)),
55            Err(e) => Err(e),
56        }
57    }
58}
59
60/// Specifies how this type can be written to the packet.
61pub trait TlWrite {
62    /// Serialized object representation.
63    type Repr: Repr;
64
65    /// Max required number of bytes.
66    fn max_size_hint(&self) -> usize;
67
68    /// Writes itself to the specified [`TlPacket`].
69    fn write_to<P>(&self, packet: &mut P)
70    where
71        P: TlPacket;
72}
73
74impl<T> TlWrite for &T
75where
76    T: TlWrite,
77{
78    type Repr = T::Repr;
79
80    fn max_size_hint(&self) -> usize {
81        TlWrite::max_size_hint(*self)
82    }
83
84    #[inline(always)]
85    fn write_to<P>(&self, packet: &mut P)
86    where
87        P: TlPacket,
88    {
89        TlWrite::write_to(*self, packet)
90    }
91}
92
93impl<T> TlWrite for Box<T>
94where
95    T: TlWrite,
96{
97    type Repr = T::Repr;
98
99    #[inline(always)]
100    fn max_size_hint(&self) -> usize {
101        TlWrite::max_size_hint(&**self)
102    }
103
104    #[inline(always)]
105    fn write_to<P>(&self, packet: &mut P)
106    where
107        P: TlPacket,
108    {
109        TlWrite::write_to(&**self, packet)
110    }
111}
112
113impl<T> TlWrite for Arc<T>
114where
115    T: TlWrite,
116{
117    type Repr = T::Repr;
118
119    #[inline(always)]
120    fn max_size_hint(&self) -> usize {
121        TlWrite::max_size_hint(&**self)
122    }
123
124    #[inline(always)]
125    fn write_to<P>(&self, packet: &mut P)
126    where
127        P: TlPacket,
128    {
129        TlWrite::write_to(&**self, packet)
130    }
131}
132
133/// TL packet interface.
134pub trait TlPacket {
135    /// Whether this packet type excludes signatures.
136    fn ignore_signature(&self) -> bool;
137
138    /// Writes `u32` to the packet.
139    fn write_u32(&mut self, data: u32);
140    /// Writes `i32` to the packet.
141    fn write_i32(&mut self, data: i32);
142    /// Writes `u64` to the packet.
143    fn write_u64(&mut self, data: u64);
144    /// Writes `i64` to the packet.
145    fn write_i64(&mut self, data: i64);
146    /// Writes raw bytes to the packet.
147    fn write_raw_slice(&mut self, data: &[u8]);
148}
149
150impl TlPacket for Vec<u8> {
151    #[inline(always)]
152    fn ignore_signature(&self) -> bool {
153        false
154    }
155
156    #[inline(always)]
157    fn write_u32(&mut self, data: u32) {
158        self.extend_from_slice(&data.to_le_bytes());
159    }
160
161    #[inline(always)]
162    fn write_i32(&mut self, data: i32) {
163        self.extend_from_slice(&data.to_le_bytes());
164    }
165
166    #[inline(always)]
167    fn write_u64(&mut self, data: u64) {
168        self.extend_from_slice(&data.to_le_bytes());
169    }
170
171    #[inline(always)]
172    fn write_i64(&mut self, data: i64) {
173        self.extend_from_slice(&data.to_le_bytes());
174    }
175
176    #[inline(always)]
177    fn write_raw_slice(&mut self, data: &[u8]) {
178        self.extend_from_slice(data);
179    }
180}
181
182#[cfg(feature = "bytes")]
183impl TlPacket for bytes::BytesMut {
184    #[inline(always)]
185    fn ignore_signature(&self) -> bool {
186        false
187    }
188
189    #[inline(always)]
190    fn write_u32(&mut self, data: u32) {
191        self.extend_from_slice(&data.to_le_bytes());
192    }
193
194    #[inline(always)]
195    fn write_i32(&mut self, data: i32) {
196        self.extend_from_slice(&data.to_le_bytes());
197    }
198
199    #[inline(always)]
200    fn write_u64(&mut self, data: u64) {
201        self.extend_from_slice(&data.to_le_bytes());
202    }
203
204    #[inline(always)]
205    fn write_i64(&mut self, data: i64) {
206        self.extend_from_slice(&data.to_le_bytes());
207    }
208
209    #[inline(always)]
210    fn write_raw_slice(&mut self, data: &[u8]) {
211        self.extend_from_slice(data);
212    }
213}
214
215/// A wrapper type for writing to [`std::io::Write`] types.
216///
217/// Ignores all errors afther the first one.
218/// The status can be retrieved using [`IoWriter::into_parts`].
219pub struct IoWriter<W> {
220    writer: W,
221    status: std::io::Result<()>,
222}
223
224impl<W> IoWriter<W> {
225    /// Creates a new writer.
226    pub const fn new(writer: W) -> Self {
227        Self {
228            writer,
229            status: Ok(()),
230        }
231    }
232
233    /// Gets a mutable reference to the underlying writer.
234    pub fn get_mut(&mut self) -> &mut W {
235        &mut self.writer
236    }
237
238    /// Gets a reference to the underlying writer.
239    pub fn get_ref(&self) -> &W {
240        &self.writer
241    }
242
243    /// Disassembles the [`IoWriter<W>`], returning the underlying writer, and the status.
244    pub fn into_parts(self) -> (W, std::io::Result<()>) {
245        (self.writer, self.status)
246    }
247}
248
249impl<W: std::io::Write> TlPacket for IoWriter<W> {
250    #[inline(always)]
251    fn ignore_signature(&self) -> bool {
252        false
253    }
254
255    #[inline(always)]
256    fn write_u32(&mut self, data: u32) {
257        if self.status.is_ok() {
258            self.status = self.writer.write_all(&data.to_le_bytes());
259        }
260    }
261
262    fn write_i32(&mut self, data: i32) {
263        if self.status.is_ok() {
264            self.status = self.writer.write_all(&data.to_le_bytes());
265        }
266    }
267
268    fn write_u64(&mut self, data: u64) {
269        if self.status.is_ok() {
270            self.status = self.writer.write_all(&data.to_le_bytes());
271        }
272    }
273
274    fn write_i64(&mut self, data: i64) {
275        if self.status.is_ok() {
276            self.status = self.writer.write_all(&data.to_le_bytes());
277        }
278    }
279
280    fn write_raw_slice(&mut self, data: &[u8]) {
281        if self.status.is_ok() {
282            self.status = self.writer.write_all(data);
283        }
284    }
285}
286
287/// TL result wrapper.
288pub type TlResult<T> = Result<T, TlError>;
289
290/// Error type for parsing related errors.
291#[derive(thiserror::Error, Debug)]
292pub enum TlError {
293    /// An unexpected end of packet has been reached.
294    #[error("Unexpected packet EOF")]
295    UnexpectedEof,
296    /// Expected boxed type with different constructor.
297    #[error("Unknown constructor")]
298    UnknownConstructor,
299    /// Parsed data is not valid.
300    #[error("Invalid data")]
301    InvalidData,
302}
303
304mod private {
305    pub trait Sealed {}
306}