Skip to main content

grammers_tl_parser/tl/
definition.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt;
10use std::str::FromStr;
11
12use crate::errors::{ParamParseError, ParseError};
13use crate::tl::{Category, Flag, Parameter, ParameterType, Type};
14use crate::utils::infer_id;
15
16/// A [Type Language] definition.
17///
18/// [Type Language]: https://core.telegram.org/mtproto/TL
19#[derive(Debug, PartialEq)]
20pub struct Definition {
21    /// The namespace components of the definition. This list will be empty
22    /// if the name of the definition belongs to the global namespace.
23    pub namespace: Vec<String>,
24
25    /// The name of this definition. Also known as "predicate" or "method".
26    pub name: String,
27
28    /// The numeric identifier of this definition.
29    ///
30    /// If a definition has an identifier, it overrides this value.
31    /// Otherwise, the identifier is inferred from the definition.
32    pub id: u32,
33
34    /// A possibly-empty list of parameters this definition has.
35    pub params: Vec<Parameter>,
36
37    /// The type to which this definition belongs to.
38    pub ty: Type,
39
40    /// The category to which this definition belongs to.
41    pub category: Category,
42}
43
44impl fmt::Display for Definition {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        for ns in self.namespace.iter() {
47            write!(f, "{ns}.")?;
48        }
49        write!(f, "{}#{:x}", self.name, self.id)?;
50
51        // If any parameter references a generic, make sure to define it early
52        let mut type_defs = vec![];
53        for param in self.params.iter() {
54            if let ParameterType::Normal { ty, .. } = &param.ty {
55                ty.find_generic_refs(&mut type_defs);
56            }
57        }
58        type_defs.sort_unstable();
59        type_defs.dedup();
60        for type_def in type_defs {
61            write!(f, " {{{type_def}:Type}}")?;
62        }
63
64        for param in self.params.iter() {
65            write!(f, " {param}")?;
66        }
67        write!(f, " = {}", self.ty)?;
68        Ok(())
69    }
70}
71
72impl FromStr for Definition {
73    type Err = ParseError;
74
75    /// Parses a [Type Language] definition.
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// use grammers_tl_parser::tl::Definition;
81    ///
82    /// assert!("sendMessage chat_id:int message:string = Message".parse::<Definition>().is_ok());
83    /// ```
84    ///
85    /// [Type Language]: https://core.telegram.org/mtproto/TL
86    fn from_str(definition: &str) -> Result<Self, Self::Err> {
87        if definition.trim().is_empty() {
88            return Err(ParseError::Empty);
89        }
90
91        // Parse `(left = ty)`
92        let (left, ty) = match definition.split_once('=') {
93            Some((ls, t)) => (ls.trim(), t.trim()),
94            None => return Err(ParseError::MissingType),
95        };
96
97        let mut ty = Type::from_str(ty).map_err(|_| ParseError::MissingType)?;
98
99        // Parse `name middle`
100        let (name, middle) = match left.split_once(|c: char| c.is_whitespace()) {
101            Some((name, middle)) => (name.trim_end(), middle.trim_start()),
102            None => (left, ""),
103        };
104
105        // Parse `name#id`
106        let (name, id) = match name.split_once('#') {
107            Some((name, id)) => (name.trim_end(), Some(id.trim_start())),
108            None => (name, None),
109        };
110
111        // Parse `ns1.ns2.name`
112        let (namespace, name) = match name.rsplit_once('.') {
113            Some((namespace, name)) => (
114                namespace
115                    .split('.')
116                    .map(|part| part.to_owned())
117                    .collect::<Vec<_>>(),
118                name,
119            ),
120            None => (Vec::new(), name),
121        };
122        if namespace.iter().any(|part| part.is_empty()) || name.is_empty() {
123            return Err(ParseError::MissingName);
124        }
125
126        // Parse `id`
127        let id = match id {
128            Some(id) => u32::from_str_radix(id, 16).map_err(ParseError::InvalidId)?,
129            None => infer_id(definition),
130        };
131
132        // Parse `middle`
133        let mut type_defs = vec![];
134        let mut flag_defs = vec![];
135
136        let params = middle
137            .split_whitespace()
138            .map(Parameter::from_str)
139            .filter_map(|p| match p {
140                // If the parameter is a type definition save it
141                // and ignore this parameter.
142                Err(ParamParseError::TypeDef { name }) => {
143                    type_defs.push(name);
144                    None
145                }
146
147                Ok(p) => match p {
148                    // If the parameter is a flag definition save both
149                    // the definition and the parameter.
150                    Parameter {
151                        ref name,
152                        ty: ParameterType::Flags,
153                    } => {
154                        flag_defs.push(name.clone());
155                        Some(Ok(p))
156                    }
157
158                    // If the parameter type is a generic ref ensure it's valid.
159                    Parameter {
160                        ty:
161                            ParameterType::Normal {
162                                ty:
163                                    Type {
164                                        ref name,
165                                        generic_ref: true,
166                                        ..
167                                    },
168                                ..
169                            },
170                        ..
171                    } if !type_defs.contains(name) => {
172                        Some(Err(ParseError::InvalidParam(ParamParseError::MissingDef)))
173                    }
174
175                    // If the parameter type references a flag ensure it's valid
176                    Parameter {
177                        ty:
178                            ParameterType::Normal {
179                                flag: Some(Flag { ref name, .. }),
180                                ..
181                            },
182                        ..
183                    } if !flag_defs.contains(name) => {
184                        Some(Err(ParseError::InvalidParam(ParamParseError::MissingDef)))
185                    }
186
187                    // Any other parameter that's okay should just be passed as-is.
188                    p => Some(Ok(p)),
189                },
190
191                // Unimplenented parameters are unimplemented definitions.
192                Err(ParamParseError::NotImplemented) => Some(Err(ParseError::NotImplemented)),
193
194                // Any error should just become a `ParseError`
195                Err(x) => Some(Err(ParseError::InvalidParam(x))),
196            })
197            .collect::<Result<_, ParseError>>()?;
198
199        // The type lacks `!` so we determine if it's a generic one based
200        // on whether its name is known in a previous parameter type def.
201        if type_defs.contains(&ty.name) {
202            ty.generic_ref = true;
203        }
204
205        Ok(Definition {
206            namespace,
207            name: name.to_owned(),
208            id,
209            params,
210            ty,
211            category: Category::Types,
212        })
213    }
214}
215
216impl Definition {
217    /// Convenience function to format both the namespace and name back into a single string.
218    pub fn full_name(&self) -> String {
219        let mut result = String::with_capacity(
220            self.namespace.iter().map(|ns| ns.len() + 1).sum::<usize>() + self.name.len(),
221        );
222        for ns in self.namespace.iter() {
223            result.push_str(ns);
224            result.push('.');
225        }
226        result.push_str(&self.name);
227        result
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234    use crate::tl::Flag;
235
236    #[test]
237    fn parse_empty_def() {
238        assert_eq!(Definition::from_str(""), Err(ParseError::Empty));
239    }
240
241    #[test]
242    fn parse_bad_id() {
243        let bad = u32::from_str_radix("bar", 16).unwrap_err();
244        let bad_q = u32::from_str_radix("?", 16).unwrap_err();
245        let bad_empty = u32::from_str_radix("", 16).unwrap_err();
246        assert_eq!(
247            Definition::from_str("foo#bar = baz"),
248            Err(ParseError::InvalidId(bad))
249        );
250        assert_eq!(
251            Definition::from_str("foo#? = baz"),
252            Err(ParseError::InvalidId(bad_q))
253        );
254        assert_eq!(
255            Definition::from_str("foo# = baz"),
256            Err(ParseError::InvalidId(bad_empty))
257        );
258    }
259
260    #[test]
261    fn parse_no_name() {
262        assert_eq!(Definition::from_str(" = foo"), Err(ParseError::MissingName));
263    }
264
265    #[test]
266    fn parse_no_type() {
267        assert_eq!(Definition::from_str("foo"), Err(ParseError::MissingType));
268        assert_eq!(Definition::from_str("foo = "), Err(ParseError::MissingType));
269    }
270
271    #[test]
272    fn parse_unimplemented() {
273        assert_eq!(
274            Definition::from_str("int ? = Int"),
275            Err(ParseError::NotImplemented)
276        );
277    }
278
279    #[test]
280    fn parse_override_id() {
281        let def = "rpc_answer_dropped msg_id:long seq_no:int bytes:int = RpcDropAnswer";
282        assert_eq!(Definition::from_str(def).unwrap().id, 0xa43ad8b7);
283
284        let def = "rpc_answer_dropped#123456 msg_id:long seq_no:int bytes:int = RpcDropAnswer";
285        assert_eq!(Definition::from_str(def).unwrap().id, 0x123456);
286    }
287
288    #[test]
289    fn parse_valid_definition() {
290        let def = Definition::from_str("a#1=d").unwrap();
291        assert_eq!(def.name, "a");
292        assert_eq!(def.id, 1);
293        assert_eq!(def.params.len(), 0);
294        assert_eq!(
295            def.ty,
296            Type {
297                namespace: vec![],
298                name: "d".into(),
299                bare: true,
300                generic_ref: false,
301                generic_arg: None,
302            }
303        );
304
305        let def = Definition::from_str("a=d<e>").unwrap();
306        assert_eq!(def.name, "a");
307        assert_ne!(def.id, 0);
308        assert_eq!(def.params.len(), 0);
309        assert_eq!(
310            def.ty,
311            Type {
312                namespace: vec![],
313                name: "d".into(),
314                bare: true,
315                generic_ref: false,
316                generic_arg: Some(Box::new("e".parse().unwrap())),
317            }
318        );
319
320        let def = Definition::from_str("a b:c = d").unwrap();
321        assert_eq!(def.name, "a");
322        assert_ne!(def.id, 0);
323        assert_eq!(def.params.len(), 1);
324        assert_eq!(
325            def.ty,
326            Type {
327                namespace: vec![],
328                name: "d".into(),
329                bare: true,
330                generic_ref: false,
331                generic_arg: None,
332            }
333        );
334
335        let def = Definition::from_str("a#1 {b:Type} c:!b = d").unwrap();
336        assert_eq!(def.name, "a");
337        assert_eq!(def.id, 1);
338        assert_eq!(def.params.len(), 1);
339        assert!(matches!(
340            def.params[0].ty,
341            ParameterType::Normal {
342                ty: Type { generic_ref, .. },
343                ..
344            } if generic_ref
345        ));
346        assert_eq!(
347            def.ty,
348            Type {
349                namespace: vec![],
350                name: "d".into(),
351                bare: true,
352                generic_ref: false,
353                generic_arg: None,
354            }
355        );
356    }
357
358    #[test]
359    fn parse_multiline_definition() {
360        let def = "
361            first#1 lol:param
362              = t;
363            ";
364
365        assert_eq!(Definition::from_str(def).unwrap().id, 1);
366
367        let def = "
368            second#2
369              lol:String
370            = t;
371            ";
372
373        assert_eq!(Definition::from_str(def).unwrap().id, 2);
374
375        let def = "
376            third#3
377
378              lol:String
379
380            =
381                     t;
382            ";
383
384        assert_eq!(Definition::from_str(def).unwrap().id, 3);
385    }
386
387    #[test]
388    fn parse_complete() {
389        let def = "ns1.name#123 {X:Type} flags:# pname:flags.10?ns2.Vector<!X> = ns3.Type";
390        assert_eq!(
391            Definition::from_str(def),
392            Ok(Definition {
393                namespace: vec!["ns1".into()],
394                name: "name".into(),
395                id: 0x123,
396                params: vec![
397                    Parameter {
398                        name: "flags".into(),
399                        ty: ParameterType::Flags,
400                    },
401                    Parameter {
402                        name: "pname".into(),
403                        ty: ParameterType::Normal {
404                            ty: Type {
405                                namespace: vec!["ns2".into()],
406                                name: "Vector".into(),
407                                bare: false,
408                                generic_ref: false,
409                                generic_arg: Some(Box::new(Type {
410                                    namespace: vec![],
411                                    name: "X".into(),
412                                    bare: false,
413                                    generic_ref: true,
414                                    generic_arg: None,
415                                })),
416                            },
417                            flag: Some(Flag {
418                                name: "flags".into(),
419                                index: 10
420                            })
421                        },
422                    },
423                ],
424                ty: Type {
425                    namespace: vec!["ns3".into()],
426                    name: "Type".into(),
427                    bare: false,
428                    generic_ref: false,
429                    generic_arg: None,
430                },
431                category: Category::Types,
432            })
433        );
434    }
435
436    #[test]
437    fn parse_missing_generic() {
438        let def = "name param:!X = Type";
439        assert_eq!(
440            Definition::from_str(def),
441            Err(ParseError::InvalidParam(ParamParseError::MissingDef))
442        );
443
444        let def = "name {X:Type} param:!Y = Type";
445        assert_eq!(
446            Definition::from_str(def),
447            Err(ParseError::InvalidParam(ParamParseError::MissingDef))
448        );
449    }
450
451    #[test]
452    fn parse_unknown_flags() {
453        let def = "name param:flags.0?true = Type";
454        assert_eq!(
455            Definition::from_str(def),
456            Err(ParseError::InvalidParam(ParamParseError::MissingDef))
457        );
458
459        let def = "name foo:# param:flags.0?true = Type";
460        assert_eq!(
461            Definition::from_str(def),
462            Err(ParseError::InvalidParam(ParamParseError::MissingDef))
463        );
464    }
465
466    #[test]
467    fn test_to_string() {
468        let def = "ns1.name#123 {X:Type} flags:# pname:flags.10?ns2.Vector<!X> = ns3.Type";
469        assert_eq!(Definition::from_str(def).unwrap().to_string(), def);
470    }
471}