Skip to main content

ferogram_tl_types/
serialize.rs

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