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