Skip to main content

layer_tl_types/
serialize.rs

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