1use std::io::{self, Write};
4use std::path::Path;
5use std::fs::File;
6
7use layer_tl_parser::tl::{Category, Definition, ParameterType};
8
9use crate::grouper;
10use crate::metadata::Metadata;
11use crate::namegen as n;
12
13pub struct Config {
17 pub gen_name_for_id: bool,
19 pub deserializable_functions: bool,
21 pub impl_debug: bool,
23 pub impl_from_type: bool,
25 pub impl_from_enum: bool,
27 pub impl_serde: bool,
29}
30
31impl Default for Config {
32 fn default() -> Self {
33 Self {
34 gen_name_for_id: false,
35 deserializable_functions: false,
36 impl_debug: true,
37 impl_from_type: true,
38 impl_from_enum: true,
39 impl_serde: false,
40 }
41 }
42}
43
44pub struct Outputs<W: Write> {
48 pub common: W,
50 pub types: W,
52 pub functions: W,
54 pub enums: W,
56}
57
58impl Outputs<File> {
59 pub fn from_dir(out_dir: &str) -> io::Result<Self> {
61 let p = Path::new(out_dir);
62 Ok(Self {
63 common: File::create(p.join("generated_common.rs"))?,
64 types: File::create(p.join("generated_types.rs"))?,
65 functions: File::create(p.join("generated_functions.rs"))?,
66 enums: File::create(p.join("generated_enums.rs"))?,
67 })
68 }
69}
70
71impl<W: Write> Outputs<W> {
72 pub fn flush(&mut self) -> io::Result<()> {
74 self.common.flush()?;
75 self.types.flush()?;
76 self.functions.flush()?;
77 self.enums.flush()
78 }
79}
80
81const BUILTIN_TYPES: &[&str] = &["Bool", "True"];
85
86fn is_builtin(ty_name: &str) -> bool {
87 BUILTIN_TYPES.contains(&ty_name)
88}
89
90pub fn generate<W: Write>(
96 defs: &[Definition],
97 config: &Config,
98 outputs: &mut Outputs<W>,
99) -> io::Result<()> {
100 let meta = Metadata::build(defs);
101
102 write_common(defs, config, &mut outputs.common)?;
103 write_types_mod(defs, config, &meta, &mut outputs.types)?;
104 write_functions_mod(defs, config, &meta, &mut outputs.functions)?;
105 write_enums_mod(defs, config, &meta, &mut outputs.enums)?;
106
107 Ok(())
108}
109
110fn write_common<W: Write>(defs: &[Definition], config: &Config, out: &mut W) -> io::Result<()> {
113 writeln!(out, "// @generated — do not edit by hand")?;
116 writeln!(out, "// Re-run the build script to regenerate.")?;
117 writeln!(out)?;
118 writeln!(out, "/// The API layer this code was generated from.")?;
119 writeln!(out, "pub const LAYER: i32 = 0; // update via build.rs")?;
120 writeln!(out)?;
121
122 if config.gen_name_for_id {
123 writeln!(out, "/// Returns the TL name for a known constructor ID.")?;
124 writeln!(out, "pub fn name_for_id(id: u32) -> Option<&'static str> {{")?;
125 writeln!(out, " match id {{")?;
126 for def in defs {
127 writeln!(
128 out,
129 " {:#010x} => Some(\"{}\"),",
130 def.id,
131 def.full_name()
132 )?;
133 }
134 writeln!(out, " _ => None,")?;
135 writeln!(out, " }}")?;
136 writeln!(out, "}}")?;
137 }
138
139 Ok(())
140}
141
142fn write_types_mod<W: Write>(
145 defs: &[Definition],
146 config: &Config,
147 meta: &Metadata,
148 out: &mut W,
149) -> io::Result<()> {
150 writeln!(out, "// @generated — do not edit by hand")?;
151 writeln!(out, "pub mod types {{")?;
152
153 let grouped = grouper::group_by_ns(defs, Category::Types);
154 let mut namespaces: Vec<&String> = grouped.keys().collect();
155 namespaces.sort();
156
157 for ns in namespaces {
158 let bucket = &grouped[ns];
159 let indent = if ns.is_empty() {
160 " ".to_owned()
161 } else {
162 writeln!(out, " pub mod {ns} {{")?;
163 " ".to_owned()
164 };
165
166 for def in bucket {
167 write_struct(out, &indent, def, meta, config)?;
168 write_identifiable(out, &indent, def)?;
169 write_struct_serializable(out, &indent, def, meta)?;
170 write_struct_deserializable(out, &indent, def)?;
171 }
172
173 if !ns.is_empty() {
174 writeln!(out, " }}")?;
175 }
176 }
177
178 writeln!(out, "}}")
179}
180
181fn write_functions_mod<W: Write>(
182 defs: &[Definition],
183 config: &Config,
184 meta: &Metadata,
185 out: &mut W,
186) -> io::Result<()> {
187 writeln!(out, "// @generated — do not edit by hand")?;
188 writeln!(out, "pub mod functions {{")?;
189
190 let grouped = grouper::group_by_ns(defs, Category::Functions);
191 let mut namespaces: Vec<&String> = grouped.keys().collect();
192 namespaces.sort();
193
194 for ns in namespaces {
195 let bucket = &grouped[ns];
196 let indent = if ns.is_empty() {
197 " ".to_owned()
198 } else {
199 writeln!(out, " pub mod {ns} {{")?;
200 " ".to_owned()
201 };
202
203 for def in bucket {
204 write_struct(out, &indent, def, meta, config)?;
205 write_identifiable(out, &indent, def)?;
206 write_struct_serializable(out, &indent, def, meta)?;
207 if config.deserializable_functions {
208 write_struct_deserializable(out, &indent, def)?;
209 }
210 write_remote_call(out, &indent, def)?;
211 }
212
213 if !ns.is_empty() {
214 writeln!(out, " }}")?;
215 }
216 }
217
218 writeln!(out, "}}")
219}
220
221fn generic_list(def: &Definition, bounds: &str) -> String {
224 let mut params: Vec<&str> = Vec::new();
225 for p in &def.params {
226 if let ParameterType::Normal { ty, .. } = &p.ty
227 && ty.generic_ref && !params.contains(&ty.name.as_str()) {
228 params.push(&ty.name);
229 }
230 }
231 if params.is_empty() {
232 String::new()
233 } else {
234 format!("<{}>", params.join(&format!("{bounds}, ")) + bounds)
235 }
236}
237
238fn write_struct<W: Write>(
239 out: &mut W,
240 indent: &str,
241 def: &Definition,
242 _meta: &Metadata,
243 config: &Config,
244) -> io::Result<()> {
245 let kind = match def.category {
246 Category::Types => "constructor",
247 Category::Functions => "method",
248 };
249 writeln!(
250 out,
251 "\n{indent}/// [`{name}`](https://core.telegram.org/{kind}/{name})\n\
252 {indent}///\n\
253 {indent}/// Generated from:\n\
254 {indent}/// ```tl\n\
255 {indent}/// {def}\n\
256 {indent}/// ```",
257 name = def.full_name(),
258 )?;
259
260 if config.impl_debug {
261 writeln!(out, "{indent}#[derive(Debug)]")?;
262 }
263 if config.impl_serde {
264 writeln!(out, "{indent}#[derive(serde::Serialize, serde::Deserialize)]")?;
265 }
266 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
267 writeln!(
268 out,
269 "{indent}pub struct {}{} {{",
270 n::def_type_name(def),
271 generic_list(def, ""),
272 )?;
273
274 for param in &def.params {
275 match ¶m.ty {
276 ParameterType::Flags => {} ParameterType::Normal { .. } => {
278 writeln!(
279 out,
280 "{indent} pub {}: {},",
281 n::param_attr_name(param),
282 n::param_qual_name(param),
283 )?;
284 }
285 }
286 }
287 writeln!(out, "{indent}}}")
288}
289
290fn write_identifiable<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
291 let gl = generic_list(def, "");
292 writeln!(
293 out,
294 "{indent}impl{gl} crate::Identifiable for {}{gl} {{\n\
295 {indent} const CONSTRUCTOR_ID: u32 = {:#010x};\n\
296 {indent}}}",
297 n::def_type_name(def),
298 def.id,
299 )
300}
301
302fn write_struct_serializable<W: Write>(
303 out: &mut W,
304 indent: &str,
305 def: &Definition,
306 meta: &Metadata,
307) -> io::Result<()> {
308 let gl_decl = generic_list(def, ": crate::Serializable");
309 let gl_use = generic_list(def, "");
310
311 writeln!(
312 out,
313 "{indent}impl{gl_decl} crate::Serializable for {}{gl_use} {{",
314 n::def_type_name(def)
315 )?;
316
317 let underscore = if def.category == Category::Types && def.params.is_empty() { "_" } else { "" };
318 writeln!(out, "{indent} fn serialize(&self, {underscore}buf: &mut impl Extend<u8>) {{")?;
319
320 if def.category == Category::Functions {
321 writeln!(out, "{indent} use crate::Identifiable;")?;
322 writeln!(out, "{indent} Self::CONSTRUCTOR_ID.serialize(buf);")?;
323 }
324
325 for param in &def.params {
326 write_param_serialization(out, indent, def, meta, param)?;
327 }
328
329 writeln!(out, "{indent} }}")?;
330 writeln!(out, "{indent}}}")
331}
332
333fn write_param_serialization<W: Write>(
334 out: &mut W,
335 indent: &str,
336 def: &Definition,
337 meta: &Metadata,
338 param: &layer_tl_parser::tl::Parameter,
339) -> io::Result<()> {
340 use ParameterType::*;
341
342 match ¶m.ty {
343 Flags => {
344 if meta.is_unused_flag(def, param) {
345 writeln!(out, "{indent} 0u32.serialize(buf);")?;
346 return Ok(());
347 }
348 write!(out, "{indent} (")?;
350 let mut first = true;
351 for other in &def.params {
352 if let Normal { flag: Some(fl), ty, .. } = &other.ty {
353 if fl.name != param.name { continue; }
354 if !first { write!(out, " | ")?; }
355 first = false;
356 if ty.name == "true" {
357 write!(out, "if self.{} {{ 1 << {} }} else {{ 0 }}", n::param_attr_name(other), fl.index)?;
358 } else {
359 write!(out, "if self.{}.is_some() {{ 1 << {} }} else {{ 0 }}", n::param_attr_name(other), fl.index)?;
360 }
361 }
362 }
363 if first { write!(out, "0u32")?; }
364 writeln!(out, ").serialize(buf);")?;
365 }
366 Normal { ty, flag } => {
367 let attr = n::param_attr_name(param);
368 if flag.is_some() {
369 if ty.name == "true" {
370 } else {
372 writeln!(out, "{indent} if let Some(v) = &self.{attr} {{ v.serialize(buf); }}")?;
373 }
374 } else {
375 writeln!(out, "{indent} self.{attr}.serialize(buf);")?;
376 }
377 }
378 }
379 Ok(())
380}
381
382fn write_struct_deserializable<W: Write>(
383 out: &mut W,
384 indent: &str,
385 def: &Definition,
386) -> io::Result<()> {
387 let gl_decl = generic_list(def, ": crate::Deserializable");
388 let gl_use = generic_list(def, "");
389
390 let buf_name = if def.params.is_empty() { "_buf" } else { "buf" };
393
394 writeln!(
395 out,
396 "{indent}impl{gl_decl} crate::Deserializable for {}{gl_use} {{",
397 n::def_type_name(def)
398 )?;
399 writeln!(
400 out,
401 "{indent} fn deserialize({buf_name}: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
402 )?;
403
404 let flag_params: Vec<_> = def.params.iter()
406 .filter(|p| p.ty == ParameterType::Flags)
407 .collect();
408
409 for fp in &flag_params {
410 writeln!(
411 out,
412 "{indent} let _{} = u32::deserialize(buf)?;",
413 n::param_attr_name(fp)
414 )?;
415 }
416
417 for param in &def.params {
419 if param.ty == ParameterType::Flags {
420 continue; }
422 if let ParameterType::Normal { ty, flag } = ¶m.ty {
423 let attr = n::param_attr_name(param);
424 if let Some(fl) = flag {
425 if ty.name == "true" {
426 writeln!(
427 out,
428 "{indent} let {attr} = (_{} & (1 << {})) != 0;",
429 fl.name, fl.index
430 )?;
431 } else {
432 writeln!(
433 out,
434 "{indent} let {attr} = if (_{} & (1 << {})) != 0 {{ Some({}::deserialize(buf)?) }} else {{ None }};",
435 fl.name, fl.index, n::type_item_path(ty)
436 )?;
437 }
438 } else {
439 writeln!(
440 out,
441 "{indent} let {attr} = {}::deserialize(buf)?;",
442 n::type_item_path(ty)
443 )?;
444 }
445 }
446 }
447
448 writeln!(out, "{indent} Ok(Self {{")?;
449 for param in &def.params {
450 if param.ty != ParameterType::Flags {
451 let attr = n::param_attr_name(param);
452 writeln!(out, "{indent} {attr},")?;
453 }
454 }
455 writeln!(out, "{indent} }})")?;
456 writeln!(out, "{indent} }}")?;
457 writeln!(out, "{indent}}}")
458}
459
460fn write_remote_call<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
461 let gl_decl = generic_list(def, ": crate::Serializable + crate::Deserializable");
464 let gl_use = generic_list(def, "");
465 writeln!(
466 out,
467 "{indent}impl{gl_decl} crate::RemoteCall for {}{gl_use} {{",
468 n::def_type_name(def)
469 )?;
470 writeln!(
471 out,
472 "{indent} type Return = {};",
473 n::type_qual_name(&def.ty)
474 )?;
475 writeln!(out, "{indent}}}")
476}
477
478fn write_enums_mod<W: Write>(
481 defs: &[Definition],
482 config: &Config,
483 meta: &Metadata,
484 out: &mut W,
485) -> io::Result<()> {
486 writeln!(out, "// @generated — do not edit by hand")?;
487 writeln!(out, "pub mod enums {{")?;
488
489 let grouped = grouper::group_types_by_ns(defs);
490 let mut keys: Vec<&Option<String>> = grouped.keys().collect();
491 keys.sort();
492
493 for key in keys {
494 let types = &grouped[key];
495 let indent = if let Some(ns) = key {
496 writeln!(out, " pub mod {ns} {{")?;
497 " ".to_owned()
498 } else {
499 " ".to_owned()
500 };
501
502 for ty in types.iter().filter(|t| !is_builtin(&t.name)) {
503 write_enum(out, &indent, ty, meta, config)?;
504 write_enum_serializable(out, &indent, ty, meta)?;
505 write_enum_deserializable(out, &indent, ty, meta)?;
506 if config.impl_from_type {
507 write_impl_from(out, &indent, ty, meta)?;
508 }
509 if config.impl_from_enum {
510 write_impl_try_from(out, &indent, ty, meta)?;
511 }
512 }
513
514 if key.is_some() {
515 writeln!(out, " }}")?;
516 }
517 }
518
519 writeln!(out, "}}")
520}
521
522fn write_enum<W: Write>(
523 out: &mut W,
524 indent: &str,
525 ty: &layer_tl_parser::tl::Type,
526 meta: &Metadata,
527 config: &Config,
528) -> io::Result<()> {
529 writeln!(
530 out,
531 "\n{indent}/// [`{name}`](https://core.telegram.org/type/{name})",
532 name = n::type_name(ty)
533 )?;
534 if config.impl_debug {
535 writeln!(out, "{indent}#[derive(Debug)]")?;
536 }
537 if config.impl_serde {
538 writeln!(out, "{indent}#[derive(serde::Serialize, serde::Deserialize)]")?;
539 }
540 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
541 writeln!(out, "{indent}pub enum {} {{", n::type_name(ty))?;
542
543 for def in meta.defs_for_type(ty) {
544 let variant = n::def_variant_name(def);
545 if def.params.is_empty() {
546 writeln!(out, "{indent} {variant},")?;
547 } else if meta.is_recursive(def) {
548 writeln!(out, "{indent} {variant}(Box<{}>),", n::def_qual_name(def))?;
549 } else {
550 writeln!(out, "{indent} {variant}({})," , n::def_qual_name(def))?;
551 }
552 }
553
554 writeln!(out, "{indent}}}")
555}
556
557fn write_enum_serializable<W: Write>(
558 out: &mut W,
559 indent: &str,
560 ty: &layer_tl_parser::tl::Type,
561 meta: &Metadata,
562) -> io::Result<()> {
563 writeln!(
564 out,
565 "{indent}impl crate::Serializable for {} {{",
566 n::type_name(ty)
567 )?;
568 writeln!(out, "{indent} fn serialize(&self, buf: &mut impl Extend<u8>) {{")?;
569 writeln!(out, "{indent} use crate::Identifiable;")?;
570 writeln!(out, "{indent} match self {{")?;
571
572 for def in meta.defs_for_type(ty) {
573 let variant = n::def_variant_name(def);
574 let bind = if def.params.is_empty() { "" } else { "(x)" };
575 writeln!(out, "{indent} Self::{variant}{bind} => {{")?;
576 writeln!(out, "{indent} {}::CONSTRUCTOR_ID.serialize(buf);", n::def_qual_name(def))?;
577 if !def.params.is_empty() {
578 writeln!(out, "{indent} x.serialize(buf);")?;
579 }
580 writeln!(out, "{indent} }}")?;
581 }
582
583 writeln!(out, "{indent} }}")?;
584 writeln!(out, "{indent} }}")?;
585 writeln!(out, "{indent}}}")
586}
587
588fn write_enum_deserializable<W: Write>(
589 out: &mut W,
590 indent: &str,
591 ty: &layer_tl_parser::tl::Type,
592 meta: &Metadata,
593) -> io::Result<()> {
594 writeln!(
595 out,
596 "{indent}impl crate::Deserializable for {} {{",
597 n::type_name(ty)
598 )?;
599 writeln!(
600 out,
601 "{indent} fn deserialize(buf: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
602 )?;
603 writeln!(out, "{indent} use crate::Identifiable;")?;
604 writeln!(out, "{indent} let id = u32::deserialize(buf)?;")?;
605 writeln!(out, "{indent} Ok(match id {{")?;
606
607 for def in meta.defs_for_type(ty) {
608 let variant = n::def_variant_name(def);
609 let qual = n::def_qual_name(def);
610 if def.params.is_empty() {
611 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant},")?;
612 } else if meta.is_recursive(def) {
613 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}(Box::new({qual}::deserialize(buf)?)),")?;
614 } else {
615 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}({qual}::deserialize(buf)?),")?;
616 }
617 }
618
619 writeln!(
620 out,
621 "{indent} _ => return Err(crate::deserialize::Error::UnexpectedConstructor {{ id }}),"
622 )?;
623 writeln!(out, "{indent} }})")?;
624 writeln!(out, "{indent} }}")?;
625 writeln!(out, "{indent}}}")
626}
627
628fn write_impl_from<W: Write>(
629 out: &mut W,
630 indent: &str,
631 ty: &layer_tl_parser::tl::Type,
632 meta: &Metadata,
633) -> io::Result<()> {
634 for def in meta.defs_for_type(ty) {
635 let enum_name = n::type_name(ty);
636 let qual = n::def_qual_name(def);
637 let variant = n::def_variant_name(def);
638
639 writeln!(out, "{indent}impl From<{qual}> for {enum_name} {{")?;
640 let underscore = if def.params.is_empty() { "_" } else { "" };
641 writeln!(out, "{indent} fn from({underscore}x: {qual}) -> Self {{")?;
642 if def.params.is_empty() {
643 writeln!(out, "{indent} Self::{variant}")?;
644 } else if meta.is_recursive(def) {
645 writeln!(out, "{indent} Self::{variant}(Box::new(x))")?;
646 } else {
647 writeln!(out, "{indent} Self::{variant}(x)")?;
648 }
649 writeln!(out, "{indent} }}")?;
650 writeln!(out, "{indent}}}")?;
651 }
652 Ok(())
653}
654
655fn write_impl_try_from<W: Write>(
656 out: &mut W,
657 indent: &str,
658 ty: &layer_tl_parser::tl::Type,
659 meta: &Metadata,
660) -> io::Result<()> {
661 let enum_name = n::type_name(ty);
662 for def in meta.defs_for_type(ty) {
663 if def.params.is_empty() { continue; }
664 let qual = n::def_qual_name(def);
665 let variant = n::def_variant_name(def);
666
667 writeln!(out, "{indent}impl TryFrom<{enum_name}> for {qual} {{")?;
668 writeln!(out, "{indent} type Error = {enum_name};")?;
669 writeln!(out, "{indent} #[allow(unreachable_patterns)]")?;
670 writeln!(out, "{indent} fn try_from(v: {enum_name}) -> Result<Self, Self::Error> {{")?;
671 writeln!(out, "{indent} match v {{")?;
672 if meta.is_recursive(def) {
673 writeln!(out, "{indent} {enum_name}::{variant}(x) => Ok(*x),")?;
674 } else {
675 writeln!(out, "{indent} {enum_name}::{variant}(x) => Ok(x),")?;
676 }
677 writeln!(out, "{indent} other => Err(other),")?;
678 writeln!(out, "{indent} }}")?;
679 writeln!(out, "{indent} }}")?;
680 writeln!(out, "{indent}}}")?;
681 }
682 Ok(())
683}