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