Skip to main content

ferogram_tl_types/
serialize.rs

1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3//
4// ferogram: async Telegram MTProto client in Rust
5// https://github.com/ankit-chaubey/ferogram
6//
7// Based on layer: https://github.com/ankit-chaubey/layer
8// Follows official Telegram client behaviour (tdesktop, TDLib).
9//
10// If you use or modify this code, keep this notice at the top of your file
11// and include the LICENSE-MIT or LICENSE-APACHE file from this repository:
12// https://github.com/ankit-chaubey/ferogram
13
14//! The [`Serializable`] trait and its implementations for primitive TL types.
15//!
16//! Encoding follows the [MTProto Binary Serialization] spec.
17//!
18//! [MTProto Binary Serialization]: https://core.telegram.org/mtproto/serialize
19
20/// Serialize `self` into TL binary format.
21pub trait Serializable {
22    /// Appends the serialized form of `self` to `buf`.
23    fn serialize(&self, buf: &mut impl Extend<u8>);
24
25    /// Convenience: allocate a fresh `Vec<u8>` and serialize into it.
26    fn to_bytes(&self) -> Vec<u8> {
27        let mut v = Vec::new();
28        self.serialize(&mut v);
29        v
30    }
31}
32
33// bool
34
35/// `true`  → `boolTrue#997275b5`
36/// `false` → `boolFalse#bc799737`
37impl Serializable for bool {
38    fn serialize(&self, buf: &mut impl Extend<u8>) {
39        let id: u32 = if *self { 0x997275b5 } else { 0xbc799737 };
40        id.serialize(buf);
41    }
42}
43
44// integers
45
46impl Serializable for i32 {
47    fn serialize(&self, buf: &mut impl Extend<u8>) {
48        buf.extend(self.to_le_bytes());
49    }
50}
51
52impl Serializable for u32 {
53    fn serialize(&self, buf: &mut impl Extend<u8>) {
54        buf.extend(self.to_le_bytes());
55    }
56}
57
58impl Serializable for i64 {
59    fn serialize(&self, buf: &mut impl Extend<u8>) {
60        buf.extend(self.to_le_bytes());
61    }
62}
63
64impl Serializable for f64 {
65    fn serialize(&self, buf: &mut impl Extend<u8>) {
66        buf.extend(self.to_le_bytes());
67    }
68}
69
70impl Serializable for [u8; 16] {
71    fn serialize(&self, buf: &mut impl Extend<u8>) {
72        buf.extend(self.iter().copied());
73    }
74}
75
76impl Serializable for [u8; 32] {
77    fn serialize(&self, buf: &mut impl Extend<u8>) {
78        buf.extend(self.iter().copied());
79    }
80}
81
82// strings / bytes
83
84/// TL string encoding: a length-prefixed, 4-byte aligned byte string.
85///
86/// * If `len ≤ 253`: `[len as u8][data][0-padding to align to 4 bytes]`
87/// * If `len ≥ 254`: `[0xfe][len as 3 LE bytes][data][0-padding]`
88impl Serializable for &[u8] {
89    fn serialize(&self, buf: &mut impl Extend<u8>) {
90        let len = self.len();
91        let (header_len, header): (usize, Vec<u8>) = if len <= 253 {
92            (1, vec![len as u8])
93        } else {
94            (
95                4,
96                vec![
97                    0xfe,
98                    (len & 0xff) as u8,
99                    ((len >> 8) & 0xff) as u8,
100                    ((len >> 16) & 0xff) as u8,
101                ],
102            )
103        };
104
105        let total = header_len + len;
106        let padding = (4 - (total % 4)) % 4;
107
108        buf.extend(header);
109        buf.extend(self.iter().copied());
110        buf.extend(std::iter::repeat_n(0u8, padding));
111    }
112}
113
114impl Serializable for Vec<u8> {
115    fn serialize(&self, buf: &mut impl Extend<u8>) {
116        self.as_slice().serialize(buf);
117    }
118}
119
120impl Serializable for String {
121    fn serialize(&self, buf: &mut impl Extend<u8>) {
122        self.as_bytes().serialize(buf);
123    }
124}
125
126// vectors
127
128/// Boxed `Vector<T>`: prefixed with constructor ID `0x1cb5c415`.
129impl<T: Serializable> Serializable for Vec<T> {
130    fn serialize(&self, buf: &mut impl Extend<u8>) {
131        0x1cb5c415u32.serialize(buf);
132        (self.len() as i32).serialize(buf);
133        for item in self {
134            item.serialize(buf);
135        }
136    }
137}
138
139/// Bare `vector<T>`: just a count followed by items, no constructor ID.
140impl<T: Serializable> Serializable for crate::RawVec<T> {
141    fn serialize(&self, buf: &mut impl Extend<u8>) {
142        (self.0.len() as i32).serialize(buf);
143        for item in &self.0 {
144            item.serialize(buf);
145        }
146    }
147}
148
149// Option
150
151/// Optional parameters are handled by flags; when `Some`, serialize the value.
152/// When `None`, nothing is written (the flags word already encodes absence).
153impl<T: Serializable> Serializable for Option<T> {
154    fn serialize(&self, buf: &mut impl Extend<u8>) {
155        if let Some(v) = self {
156            v.serialize(buf);
157        }
158    }
159}