tdlib_rs_gen/
types.rs

1// Copyright 2020 - developers of the `grammers` project.
2// Copyright 2021 - developers of the `tdlib-rs` project.
3// Copyright 2024 - developers of the `tgt` and `tdlib-rs` projects.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Code to generate Rust's `struct`'s from TL definitions.
12
13use crate::ignore_type;
14use crate::metadata::Metadata;
15use crate::rustifier;
16use std::io::{self, Write};
17use tdlib_rs_parser::tl::{Category, Definition};
18
19/// Defines the `struct` corresponding to the definition:
20///
21/// ```ignore
22/// pub struct Name {
23///     pub field: Type,
24/// }
25/// ```
26fn write_struct<W: Write>(
27    file: &mut W,
28    def: &Definition,
29    metadata: &Metadata,
30    gen_bots_only_api: bool,
31) -> io::Result<()> {
32    if rustifier::definitions::is_for_bots_only(def) && !gen_bots_only_api {
33        return Ok(());
34    }
35
36    writeln!(file, "{}", rustifier::definitions::description(def, "    "))?;
37
38    let serde_as = def
39        .params
40        .iter()
41        .any(|p| rustifier::parameters::serde_as(p).is_some());
42
43    if serde_as {
44        writeln!(file, "    #[serde_as]",)?;
45    }
46
47    write!(file, "    #[derive(Clone, Debug, ",)?;
48    if metadata.can_def_implement_default(def) {
49        write!(file, "Default, ",)?;
50    }
51    writeln!(file, "PartialEq, Deserialize, Serialize)]",)?;
52
53    writeln!(
54        file,
55        "    pub struct {} {{",
56        rustifier::definitions::type_name(def),
57    )?;
58
59    for param in def.params.iter() {
60        if rustifier::parameters::is_for_bots_only(param) && !gen_bots_only_api {
61            continue;
62        }
63
64        writeln!(
65            file,
66            "{}",
67            rustifier::parameters::description(param, "        ")
68        )?;
69
70        if let Some(serde_as) = rustifier::parameters::serde_as(param) {
71            writeln!(file, "        #[serde_as(as = \"{}\")]", serde_as)?;
72        }
73        write!(
74            file,
75            "        pub {}: ",
76            rustifier::parameters::attr_name(param),
77        )?;
78
79        let is_optional = rustifier::parameters::is_optional(param);
80        if is_optional {
81            write!(file, "Option<")?;
82        }
83        write!(file, "{}", rustifier::parameters::qual_name(param))?;
84        if is_optional {
85            write!(file, ">")?;
86        }
87
88        writeln!(file, ",")?;
89    }
90
91    writeln!(file, "    }}")?;
92    Ok(())
93}
94
95/// Writes an entire definition as Rust code (`struct`).
96fn write_definition<W: Write>(
97    file: &mut W,
98    def: &Definition,
99    metadata: &Metadata,
100    gen_bots_only_api: bool,
101) -> io::Result<()> {
102    write_struct(file, def, metadata, gen_bots_only_api)?;
103    Ok(())
104}
105
106/// Write the entire module dedicated to types.
107pub(crate) fn write_types_mod<W: Write>(
108    mut file: &mut W,
109    definitions: &[Definition],
110    metadata: &Metadata,
111    gen_bots_only_api: bool,
112) -> io::Result<()> {
113    // Begin outermost mod
114    writeln!(file, "#[allow(clippy::all)]")?;
115    writeln!(file, "pub mod types {{")?;
116    writeln!(file, "    use serde::{{Deserialize, Serialize}};")?;
117    writeln!(file, "    use serde_with::{{serde_as, DisplayFromStr}};")?;
118
119    let types = definitions
120        .iter()
121        .filter(|d| d.category == Category::Types && !ignore_type(&d.ty) && !d.params.is_empty());
122
123    for definition in types {
124        write_definition(&mut file, definition, metadata, gen_bots_only_api)?;
125    }
126
127    // End outermost mod
128    writeln!(file, "}}")
129}