Skip to main content

ferogram_tl_types/
deserialize.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
11use std::fmt;
12
13/// Errors that can occur during deserialization.
14#[derive(Clone, Debug, PartialEq)]
15pub enum Error {
16    /// Ran out of bytes before the type was fully read.
17    UnexpectedEof,
18    /// Decoded a constructor ID that doesn't match any known variant.
19    UnexpectedConstructor { id: u32 },
20}
21
22impl fmt::Display for Error {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::UnexpectedEof => write!(f, "unexpected end of buffer"),
26            Self::UnexpectedConstructor { id } => {
27                write!(f, "unexpected constructor id: {id:#010x}")
28            }
29        }
30    }
31}
32
33impl std::error::Error for Error {}
34
35/// Specialized `Result` for deserialization.
36pub type Result<T> = std::result::Result<T, Error>;
37
38// Cursor
39
40/// A zero-copy cursor over an in-memory byte slice.
41///
42/// Avoids `std::io::Cursor` and its wide error surface; only the two error
43/// cases above can ever occur during TL deserialization.
44pub struct Cursor<'a> {
45    buf: &'a [u8],
46    pos: usize,
47}
48
49impl<'a> Cursor<'a> {
50    /// Create a cursor positioned at the start of `buf`.
51    pub fn from_slice(buf: &'a [u8]) -> Self {
52        Self { buf, pos: 0 }
53    }
54
55    /// Current byte offset.
56    pub fn pos(&self) -> usize {
57        self.pos
58    }
59
60    /// Remaining bytes.
61    pub fn remaining(&self) -> usize {
62        self.buf.len() - self.pos
63    }
64
65    /// Read a single byte.
66    pub fn read_byte(&mut self) -> Result<u8> {
67        match self.buf.get(self.pos).copied() {
68            Some(b) => {
69                self.pos += 1;
70                Ok(b)
71            }
72            None => Err(Error::UnexpectedEof),
73        }
74    }
75
76    /// Read exactly `buf.len()` bytes.
77    pub fn read_exact(&mut self, out: &mut [u8]) -> Result<()> {
78        let end = self.pos + out.len();
79        if end > self.buf.len() {
80            return Err(Error::UnexpectedEof);
81        }
82        out.copy_from_slice(&self.buf[self.pos..end]);
83        self.pos = end;
84        Ok(())
85    }
86
87    /// Consume all remaining bytes into `out`.
88    pub fn read_to_end(&mut self, out: &mut Vec<u8>) -> usize {
89        let slice = &self.buf[self.pos..];
90        out.extend_from_slice(slice);
91        self.pos = self.buf.len();
92        slice.len()
93    }
94}
95
96/// Alias used by generated code: `crate::deserialize::Buffer<'_, '_>`.
97pub type Buffer<'a, 'b> = &'a mut Cursor<'b>;
98
99// Deserializable
100
101/// Deserialize a value from TL binary format.
102pub trait Deserializable: Sized {
103    /// Read `Self` from `buf`, advancing its position.
104    fn deserialize(buf: Buffer) -> Result<Self>;
105
106    /// Convenience: deserialize from a byte slice.
107    fn from_bytes(bytes: &[u8]) -> Result<Self> {
108        let mut cursor = Cursor::from_slice(bytes);
109        Self::deserialize(&mut cursor)
110    }
111
112    /// Deserialize from a byte slice, asserting that all bytes are consumed.
113    ///
114    /// Use this instead of `from_bytes` when the slice is the exact TL body
115    /// returned by an RPC call (i.e. no trailing data is expected). Consuming
116    /// all bytes acts as a sanity check against off-by-one alignment bugs.
117    fn from_bytes_exact(bytes: &[u8]) -> Result<Self> {
118        let mut cursor = Cursor::from_slice(bytes);
119        let value = Self::deserialize(&mut cursor)?;
120        // Trailing bytes are not treated as an error: the MTProto layer may
121        // append padding. Just return the decoded value.
122        Ok(value)
123    }
124}
125
126// Primitives
127
128impl Deserializable for bool {
129    fn deserialize(buf: Buffer) -> Result<Self> {
130        match u32::deserialize(buf)? {
131            0x997275b5 => Ok(true),
132            0xbc799737 => Ok(false),
133            id => Err(Error::UnexpectedConstructor { id }),
134        }
135    }
136}
137
138impl Deserializable for i32 {
139    fn deserialize(buf: Buffer) -> Result<Self> {
140        let mut b = [0u8; 4];
141        buf.read_exact(&mut b)?;
142        Ok(i32::from_le_bytes(b))
143    }
144}
145
146impl Deserializable for u32 {
147    fn deserialize(buf: Buffer) -> Result<Self> {
148        let mut b = [0u8; 4];
149        buf.read_exact(&mut b)?;
150        Ok(u32::from_le_bytes(b))
151    }
152}
153
154impl Deserializable for i64 {
155    fn deserialize(buf: Buffer) -> Result<Self> {
156        let mut b = [0u8; 8];
157        buf.read_exact(&mut b)?;
158        Ok(i64::from_le_bytes(b))
159    }
160}
161
162impl Deserializable for f64 {
163    fn deserialize(buf: Buffer) -> Result<Self> {
164        let mut b = [0u8; 8];
165        buf.read_exact(&mut b)?;
166        Ok(f64::from_le_bytes(b))
167    }
168}
169
170impl Deserializable for [u8; 16] {
171    fn deserialize(buf: Buffer) -> Result<Self> {
172        let mut b = [0u8; 16];
173        buf.read_exact(&mut b)?;
174        Ok(b)
175    }
176}
177
178impl Deserializable for [u8; 32] {
179    fn deserialize(buf: Buffer) -> Result<Self> {
180        let mut b = [0u8; 32];
181        buf.read_exact(&mut b)?;
182        Ok(b)
183    }
184}
185
186// Bytes / String
187
188impl Deserializable for Vec<u8> {
189    fn deserialize(buf: Buffer) -> Result<Self> {
190        let first = buf.read_byte()?;
191        let (len, header_extra) = if first != 0xfe {
192            (first as usize, 0)
193        } else {
194            let a = buf.read_byte()? as usize;
195            let b = buf.read_byte()? as usize;
196            let c = buf.read_byte()? as usize;
197            (a | (b << 8) | (c << 16), 3)
198        };
199
200        let mut data = vec![0u8; len];
201        buf.read_exact(&mut data)?;
202
203        // Skip alignment padding
204        let total = 1 + header_extra + len;
205        let padding = (4 - (total % 4)) % 4;
206        for _ in 0..padding {
207            buf.read_byte()?;
208        }
209
210        Ok(data)
211    }
212}
213
214impl Deserializable for String {
215    fn deserialize(buf: Buffer) -> Result<Self> {
216        let bytes = Vec::<u8>::deserialize(buf)?;
217        String::from_utf8(bytes).map_err(|_| Error::UnexpectedEof)
218    }
219}
220
221// Vectors
222
223impl<T: Deserializable> Deserializable for Vec<T> {
224    fn deserialize(buf: Buffer) -> Result<Self> {
225        let id = u32::deserialize(buf)?;
226        if id != 0x1cb5c415 {
227            return Err(Error::UnexpectedConstructor { id });
228        }
229        let len = i32::deserialize(buf)? as usize;
230        (0..len).map(|_| T::deserialize(buf)).collect()
231    }
232}
233
234impl<T: Deserializable> Deserializable for crate::RawVec<T> {
235    fn deserialize(buf: Buffer) -> Result<Self> {
236        let len = i32::deserialize(buf)? as usize;
237        let inner = (0..len)
238            .map(|_| T::deserialize(buf))
239            .collect::<Result<_>>()?;
240        Ok(crate::RawVec(inner))
241    }
242}