Skip to main content

grammers_tl_gen/
lib.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
9//! This library is intended to be a build-time dependency,
10//! used to generate source code from parsed TL definitions.
11
12#![deny(unsafe_code)]
13
14mod enums;
15mod grouper;
16mod metadata;
17mod rustifier;
18mod structs;
19
20use std::io::{self, Write};
21
22use grammers_tl_parser::tl::{Category, Definition, Type};
23
24/// Writers to use as output for each generated module.
25pub struct Outputs<W: Write> {
26    /// Writer to the file containing the generated layer constant and name mapping if enabled.
27    pub common: W,
28    /// Writer to the file containing all of the concrete [`Category::Types`] constructors.
29    pub types: W,
30    /// Writer to the file containing all of the [`Category::Functions`] constructors.
31    pub functions: W,
32    /// Writer to the file containing all of the boxed [`Category::Types`].
33    pub enums: W,
34}
35
36impl<W: Write> Outputs<W> {
37    /// Flush all writers sequentially.
38    pub fn flush(&mut self) -> std::io::Result<()> {
39        self.common.flush()?;
40        self.types.flush()?;
41        self.functions.flush()?;
42        self.enums.flush()
43    }
44}
45
46/// Configuration used by [`generate_rust_code`].
47pub struct Config {
48    /// Whether to generate a giant function that will map the constructor ID to its TL name. Useful for debugging.
49    pub gen_name_for_id: bool,
50    /// Whether to also `impl Deserializable` on the definitions under [`Category::Functions`].
51    pub deserializable_functions: bool,
52    /// Whether to derive `Debug` for all generated types.
53    pub impl_debug: bool,
54    /// Whether to `impl From<types::*> for enums::*` for all generated types.
55    pub impl_from_type: bool,
56    /// Whether to `impl TryFrom<enums::*> for types::*` for all generated types.
57    pub impl_from_enum: bool,
58    /// Whether to derive `serde::*` for all generated types.
59    pub impl_serde: bool,
60}
61
62impl Default for Config {
63    fn default() -> Self {
64        Self {
65            gen_name_for_id: false,
66            deserializable_functions: false,
67            impl_debug: true,
68            impl_from_type: true,
69            impl_from_enum: true,
70            impl_serde: false,
71        }
72    }
73}
74
75/// Don't generate types for definitions of this type,
76/// since they are "core" types and treated differently.
77const SPECIAL_CASED_TYPES: [&str; 1] = ["Bool"];
78
79fn ignore_type(ty: &Type) -> bool {
80    SPECIAL_CASED_TYPES.iter().any(|&x| x == ty.name)
81}
82
83/// Generate the Rust code into the provided outputs for the given parsed definitions.
84pub fn generate_rust_code<W: Write>(
85    outputs: &mut Outputs<W>,
86    definitions: &[Definition],
87    layer: i32,
88    config: &Config,
89) -> io::Result<()> {
90    writeln!(
91        &mut outputs.common,
92        r#"/// The schema layer from which the definitions were generated.
93pub const LAYER: i32 = {layer};
94"#
95    )?;
96
97    if config.gen_name_for_id {
98        writeln!(
99            outputs.common,
100            r#"
101/// Return the name from the `.tl` definition corresponding to the provided definition identifier.
102pub fn name_for_id(id: u32) -> &'static str {{
103    match id {{
104        0x1cb5c415 => "vector","#
105        )?;
106        for def in definitions {
107            writeln!(
108                &mut outputs.common,
109                r#"        0x{:x} => "{}","#,
110                def.id,
111                def.full_name()
112            )?;
113        }
114
115        writeln!(
116            outputs.common,
117            r#"
118        _ => "(unknown)",
119    }}
120}}
121    "#,
122        )?;
123    }
124
125    let metadata = metadata::Metadata::new(definitions);
126    structs::write_category_mod(
127        &mut outputs.types,
128        Category::Types,
129        definitions,
130        &metadata,
131        config,
132    )?;
133    structs::write_category_mod(
134        &mut outputs.functions,
135        Category::Functions,
136        definitions,
137        &metadata,
138        config,
139    )?;
140    enums::write_enums_mod(&mut outputs.enums, definitions, &metadata, config)?;
141
142    Ok(())
143}