1use std::fs::File;
4use std::io::{self, Write};
5use std::path::Path;
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!(
125 out,
126 "pub fn name_for_id(id: u32) -> Option<&'static str> {{"
127 )?;
128 writeln!(out, " match id {{")?;
129 for def in defs {
130 writeln!(
131 out,
132 " {:#010x} => Some(\"{}\"),",
133 def.id,
134 def.full_name()
135 )?;
136 }
137 writeln!(out, " _ => None,")?;
138 writeln!(out, " }}")?;
139 writeln!(out, "}}")?;
140 }
141
142 Ok(())
143}
144
145fn write_types_mod<W: Write>(
148 defs: &[Definition],
149 config: &Config,
150 meta: &Metadata,
151 out: &mut W,
152) -> io::Result<()> {
153 writeln!(out, "// @generated: do not edit by hand")?;
154 writeln!(out, "pub mod types {{")?;
155
156 let grouped = grouper::group_by_ns(defs, Category::Types);
157 let mut namespaces: Vec<&String> = grouped.keys().collect();
158 namespaces.sort();
159
160 for ns in namespaces {
161 let bucket = &grouped[ns];
162 let indent = if ns.is_empty() {
163 " ".to_owned()
164 } else {
165 writeln!(out, " pub mod {ns} {{")?;
166 " ".to_owned()
167 };
168
169 for def in bucket {
170 write_struct(out, &indent, def, meta, config)?;
171 write_identifiable(out, &indent, def)?;
172 write_struct_serializable(out, &indent, def, meta)?;
173 write_struct_deserializable(out, &indent, def)?;
174 }
175
176 if !ns.is_empty() {
177 writeln!(out, " }}")?;
178 }
179 }
180
181 writeln!(out, "}}")
182}
183
184fn write_functions_mod<W: Write>(
185 defs: &[Definition],
186 config: &Config,
187 meta: &Metadata,
188 out: &mut W,
189) -> io::Result<()> {
190 writeln!(out, "// @generated: do not edit by hand")?;
191 writeln!(out, "pub mod functions {{")?;
192
193 let grouped = grouper::group_by_ns(defs, Category::Functions);
194 let mut namespaces: Vec<&String> = grouped.keys().collect();
195 namespaces.sort();
196
197 for ns in namespaces {
198 let bucket = &grouped[ns];
199 let indent = if ns.is_empty() {
200 " ".to_owned()
201 } else {
202 writeln!(out, " pub mod {ns} {{")?;
203 " ".to_owned()
204 };
205
206 for def in bucket {
207 write_struct(out, &indent, def, meta, config)?;
208 write_identifiable(out, &indent, def)?;
209 write_struct_serializable(out, &indent, def, meta)?;
210 if config.deserializable_functions {
211 write_struct_deserializable(out, &indent, def)?;
212 }
213 write_remote_call(out, &indent, def)?;
214 }
215
216 if !ns.is_empty() {
217 writeln!(out, " }}")?;
218 }
219 }
220
221 writeln!(out, "}}")
222}
223
224fn generic_list(def: &Definition, bounds: &str) -> String {
227 let mut params: Vec<&str> = Vec::new();
228 for p in &def.params {
229 if let ParameterType::Normal { ty, .. } = &p.ty
230 && ty.generic_ref
231 && !params.contains(&ty.name.as_str())
232 {
233 params.push(&ty.name);
234 }
235 }
236 if params.is_empty() {
237 String::new()
238 } else {
239 format!("<{}>", params.join(&format!("{bounds}, ")) + bounds)
240 }
241}
242
243fn write_struct<W: Write>(
244 out: &mut W,
245 indent: &str,
246 def: &Definition,
247 _meta: &Metadata,
248 config: &Config,
249) -> io::Result<()> {
250 let kind = match def.category {
251 Category::Types => "constructor",
252 Category::Functions => "method",
253 };
254 writeln!(
255 out,
256 "\n{indent}/// [`{name}`](https://core.telegram.org/{kind}/{name})\n\
257 {indent}///\n\
258 {indent}/// Generated from:\n\
259 {indent}/// ```tl\n\
260 {indent}/// {def}\n\
261 {indent}/// ```",
262 name = def.full_name(),
263 )?;
264
265 if config.impl_debug {
266 writeln!(out, "{indent}#[derive(Debug)]")?;
267 }
268 if config.impl_serde {
269 writeln!(
270 out,
271 "{indent}#[derive(serde::Serialize, serde::Deserialize)]"
272 )?;
273 }
274 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
275 writeln!(
276 out,
277 "{indent}pub struct {}{} {{",
278 n::def_type_name(def),
279 generic_list(def, ""),
280 )?;
281
282 for param in &def.params {
283 match ¶m.ty {
284 ParameterType::Flags => {} ParameterType::Normal { .. } => {
286 writeln!(
287 out,
288 "{indent} pub {}: {},",
289 n::param_attr_name(param),
290 n::param_qual_name(param),
291 )?;
292 }
293 }
294 }
295 writeln!(out, "{indent}}}")
296}
297
298fn write_identifiable<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
299 let gl = generic_list(def, "");
300 writeln!(
301 out,
302 "{indent}impl{gl} crate::Identifiable for {}{gl} {{\n\
303 {indent} const CONSTRUCTOR_ID: u32 = {:#010x};\n\
304 {indent}}}",
305 n::def_type_name(def),
306 def.id,
307 )
308}
309
310fn write_struct_serializable<W: Write>(
311 out: &mut W,
312 indent: &str,
313 def: &Definition,
314 meta: &Metadata,
315) -> io::Result<()> {
316 let gl_decl = generic_list(def, ": crate::Serializable");
317 let gl_use = generic_list(def, "");
318
319 writeln!(
320 out,
321 "{indent}impl{gl_decl} crate::Serializable for {}{gl_use} {{",
322 n::def_type_name(def)
323 )?;
324
325 let underscore = if def.category == Category::Types && def.params.is_empty() {
326 "_"
327 } else {
328 ""
329 };
330 writeln!(
331 out,
332 "{indent} fn serialize(&self, {underscore}buf: &mut impl Extend<u8>) {{"
333 )?;
334
335 if def.category == Category::Functions {
336 writeln!(out, "{indent} use crate::Identifiable;")?;
337 writeln!(out, "{indent} Self::CONSTRUCTOR_ID.serialize(buf);")?;
338 }
339
340 for param in &def.params {
341 write_param_serialization(out, indent, def, meta, param)?;
342 }
343
344 writeln!(out, "{indent} }}")?;
345 writeln!(out, "{indent}}}")
346}
347
348fn write_param_serialization<W: Write>(
349 out: &mut W,
350 indent: &str,
351 def: &Definition,
352 meta: &Metadata,
353 param: &layer_tl_parser::tl::Parameter,
354) -> io::Result<()> {
355 use ParameterType::*;
356
357 match ¶m.ty {
358 Flags => {
359 if meta.is_unused_flag(def, param) {
360 writeln!(out, "{indent} 0u32.serialize(buf);")?;
361 return Ok(());
362 }
363 write!(out, "{indent} (")?;
365 let mut first = true;
366 for other in &def.params {
367 if let Normal {
368 flag: Some(fl), ty, ..
369 } = &other.ty
370 {
371 if fl.name != param.name {
372 continue;
373 }
374 if !first {
375 write!(out, " | ")?;
376 }
377 first = false;
378 if ty.name == "true" {
379 write!(
380 out,
381 "if self.{} {{ 1 << {} }} else {{ 0 }}",
382 n::param_attr_name(other),
383 fl.index
384 )?;
385 } else {
386 write!(
387 out,
388 "if self.{}.is_some() {{ 1 << {} }} else {{ 0 }}",
389 n::param_attr_name(other),
390 fl.index
391 )?;
392 }
393 }
394 }
395 if first {
396 write!(out, "0u32")?;
397 }
398 writeln!(out, ").serialize(buf);")?;
399 }
400 Normal { ty, flag } => {
401 let attr = n::param_attr_name(param);
402 if flag.is_some() {
403 if ty.name == "true" {
404 } else {
406 writeln!(
407 out,
408 "{indent} if let Some(v) = &self.{attr} {{ v.serialize(buf); }}"
409 )?;
410 }
411 } else {
412 writeln!(out, "{indent} self.{attr}.serialize(buf);")?;
413 }
414 }
415 }
416 Ok(())
417}
418
419fn write_struct_deserializable<W: Write>(
420 out: &mut W,
421 indent: &str,
422 def: &Definition,
423) -> io::Result<()> {
424 let gl_decl = generic_list(def, ": crate::Deserializable");
425 let gl_use = generic_list(def, "");
426
427 let buf_name = if def.params.is_empty() { "_buf" } else { "buf" };
430
431 writeln!(
432 out,
433 "{indent}impl{gl_decl} crate::Deserializable for {}{gl_use} {{",
434 n::def_type_name(def)
435 )?;
436 writeln!(
437 out,
438 "{indent} fn deserialize({buf_name}: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
439 )?;
440
441 let flag_params: Vec<_> = def
443 .params
444 .iter()
445 .filter(|p| p.ty == ParameterType::Flags)
446 .collect();
447
448 for fp in &flag_params {
449 writeln!(
450 out,
451 "{indent} let _{} = u32::deserialize(buf)?;",
452 n::param_attr_name(fp)
453 )?;
454 }
455
456 for param in &def.params {
458 if param.ty == ParameterType::Flags {
459 continue; }
461 if let ParameterType::Normal { ty, flag } = ¶m.ty {
462 let attr = n::param_attr_name(param);
463 if let Some(fl) = flag {
464 if ty.name == "true" {
465 writeln!(
466 out,
467 "{indent} let {attr} = (_{} & (1 << {})) != 0;",
468 fl.name, fl.index
469 )?;
470 } else {
471 writeln!(
472 out,
473 "{indent} let {attr} = if (_{} & (1 << {})) != 0 {{ Some({}::deserialize(buf)?) }} else {{ None }};",
474 fl.name,
475 fl.index,
476 n::type_item_path(ty)
477 )?;
478 }
479 } else {
480 writeln!(
481 out,
482 "{indent} let {attr} = {}::deserialize(buf)?;",
483 n::type_item_path(ty)
484 )?;
485 }
486 }
487 }
488
489 writeln!(out, "{indent} Ok(Self {{")?;
490 for param in &def.params {
491 if param.ty != ParameterType::Flags {
492 let attr = n::param_attr_name(param);
493 writeln!(out, "{indent} {attr},")?;
494 }
495 }
496 writeln!(out, "{indent} }})")?;
497 writeln!(out, "{indent} }}")?;
498 writeln!(out, "{indent}}}")
499}
500
501fn write_remote_call<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
502 let gl_decl = generic_list(def, ": crate::Serializable + crate::Deserializable");
505 let gl_use = generic_list(def, "");
506 writeln!(
507 out,
508 "{indent}impl{gl_decl} crate::RemoteCall for {}{gl_use} {{",
509 n::def_type_name(def)
510 )?;
511 writeln!(
512 out,
513 "{indent} type Return = {};",
514 n::type_qual_name(&def.ty)
515 )?;
516 writeln!(out, "{indent}}}")
517}
518
519fn write_enums_mod<W: Write>(
522 defs: &[Definition],
523 config: &Config,
524 meta: &Metadata,
525 out: &mut W,
526) -> io::Result<()> {
527 writeln!(out, "// @generated: do not edit by hand")?;
528 writeln!(out, "pub mod enums {{")?;
529
530 let grouped = grouper::group_types_by_ns(defs);
531 let mut keys: Vec<&Option<String>> = grouped.keys().collect();
532 keys.sort();
533
534 for key in keys {
535 let types = &grouped[key];
536 let indent = if let Some(ns) = key {
537 writeln!(out, " pub mod {ns} {{")?;
538 " ".to_owned()
539 } else {
540 " ".to_owned()
541 };
542
543 for ty in types.iter().filter(|t| !is_builtin(&t.name)) {
544 write_enum(out, &indent, ty, meta, config)?;
545 write_enum_serializable(out, &indent, ty, meta)?;
546 write_enum_deserializable(out, &indent, ty, meta)?;
547 if config.impl_from_type {
548 write_impl_from(out, &indent, ty, meta)?;
549 }
550 if config.impl_from_enum {
551 write_impl_try_from(out, &indent, ty, meta)?;
552 }
553 }
554
555 if key.is_some() {
556 writeln!(out, " }}")?;
557 }
558 }
559
560 writeln!(out, "}}")
561}
562
563fn write_enum<W: Write>(
564 out: &mut W,
565 indent: &str,
566 ty: &layer_tl_parser::tl::Type,
567 meta: &Metadata,
568 config: &Config,
569) -> io::Result<()> {
570 writeln!(
571 out,
572 "\n{indent}/// [`{name}`](https://core.telegram.org/type/{name})",
573 name = n::type_name(ty)
574 )?;
575 if config.impl_debug {
576 writeln!(out, "{indent}#[derive(Debug)]")?;
577 }
578 if config.impl_serde {
579 writeln!(
580 out,
581 "{indent}#[derive(serde::Serialize, serde::Deserialize)]"
582 )?;
583 }
584 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
585 writeln!(out, "{indent}pub enum {} {{", n::type_name(ty))?;
586
587 for def in meta.defs_for_type(ty) {
588 let variant = n::def_variant_name(def);
589 if def.params.is_empty() {
590 writeln!(out, "{indent} {variant},")?;
591 } else if meta.is_recursive(def) {
592 writeln!(
593 out,
594 "{indent} {variant}(Box<{}>),",
595 n::def_qual_name(def)
596 )?;
597 } else {
598 writeln!(out, "{indent} {variant}({}),", n::def_qual_name(def))?;
599 }
600 }
601
602 writeln!(out, "{indent}}}")
603}
604
605fn write_enum_serializable<W: Write>(
606 out: &mut W,
607 indent: &str,
608 ty: &layer_tl_parser::tl::Type,
609 meta: &Metadata,
610) -> io::Result<()> {
611 writeln!(
612 out,
613 "{indent}impl crate::Serializable for {} {{",
614 n::type_name(ty)
615 )?;
616 writeln!(
617 out,
618 "{indent} fn serialize(&self, buf: &mut impl Extend<u8>) {{"
619 )?;
620 writeln!(out, "{indent} use crate::Identifiable;")?;
621 writeln!(out, "{indent} match self {{")?;
622
623 for def in meta.defs_for_type(ty) {
624 let variant = n::def_variant_name(def);
625 let bind = if def.params.is_empty() { "" } else { "(x)" };
626 writeln!(out, "{indent} Self::{variant}{bind} => {{")?;
627 writeln!(
628 out,
629 "{indent} {}::CONSTRUCTOR_ID.serialize(buf);",
630 n::def_qual_name(def)
631 )?;
632 if !def.params.is_empty() {
633 writeln!(out, "{indent} x.serialize(buf);")?;
634 }
635 writeln!(out, "{indent} }}")?;
636 }
637
638 writeln!(out, "{indent} }}")?;
639 writeln!(out, "{indent} }}")?;
640 writeln!(out, "{indent}}}")
641}
642
643fn write_enum_deserializable<W: Write>(
644 out: &mut W,
645 indent: &str,
646 ty: &layer_tl_parser::tl::Type,
647 meta: &Metadata,
648) -> io::Result<()> {
649 writeln!(
650 out,
651 "{indent}impl crate::Deserializable for {} {{",
652 n::type_name(ty)
653 )?;
654 writeln!(
655 out,
656 "{indent} fn deserialize(buf: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
657 )?;
658 writeln!(out, "{indent} use crate::Identifiable;")?;
659 writeln!(out, "{indent} let id = u32::deserialize(buf)?;")?;
660 writeln!(out, "{indent} Ok(match id {{")?;
661
662 for def in meta.defs_for_type(ty) {
663 let variant = n::def_variant_name(def);
664 let qual = n::def_qual_name(def);
665 if def.params.is_empty() {
666 writeln!(
667 out,
668 "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant},"
669 )?;
670 } else if meta.is_recursive(def) {
671 writeln!(
672 out,
673 "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}(Box::new({qual}::deserialize(buf)?)),"
674 )?;
675 } else {
676 writeln!(
677 out,
678 "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}({qual}::deserialize(buf)?),"
679 )?;
680 }
681 }
682
683 writeln!(
684 out,
685 "{indent} _ => return Err(crate::deserialize::Error::UnexpectedConstructor {{ id }}),"
686 )?;
687 writeln!(out, "{indent} }})")?;
688 writeln!(out, "{indent} }}")?;
689 writeln!(out, "{indent}}}")
690}
691
692fn write_impl_from<W: Write>(
693 out: &mut W,
694 indent: &str,
695 ty: &layer_tl_parser::tl::Type,
696 meta: &Metadata,
697) -> io::Result<()> {
698 for def in meta.defs_for_type(ty) {
699 let enum_name = n::type_name(ty);
700 let qual = n::def_qual_name(def);
701 let variant = n::def_variant_name(def);
702
703 writeln!(out, "{indent}impl From<{qual}> for {enum_name} {{")?;
704 let underscore = if def.params.is_empty() { "_" } else { "" };
705 writeln!(out, "{indent} fn from({underscore}x: {qual}) -> Self {{")?;
706 if def.params.is_empty() {
707 writeln!(out, "{indent} Self::{variant}")?;
708 } else if meta.is_recursive(def) {
709 writeln!(out, "{indent} Self::{variant}(Box::new(x))")?;
710 } else {
711 writeln!(out, "{indent} Self::{variant}(x)")?;
712 }
713 writeln!(out, "{indent} }}")?;
714 writeln!(out, "{indent}}}")?;
715 }
716 Ok(())
717}
718
719fn write_impl_try_from<W: Write>(
720 out: &mut W,
721 indent: &str,
722 ty: &layer_tl_parser::tl::Type,
723 meta: &Metadata,
724) -> io::Result<()> {
725 let enum_name = n::type_name(ty);
726 for def in meta.defs_for_type(ty) {
727 if def.params.is_empty() {
728 continue;
729 }
730 let qual = n::def_qual_name(def);
731 let variant = n::def_variant_name(def);
732
733 writeln!(out, "{indent}impl TryFrom<{enum_name}> for {qual} {{")?;
734 writeln!(out, "{indent} type Error = {enum_name};")?;
735 writeln!(out, "{indent} #[allow(unreachable_patterns)]")?;
736 writeln!(
737 out,
738 "{indent} fn try_from(v: {enum_name}) -> Result<Self, Self::Error> {{"
739 )?;
740 writeln!(out, "{indent} match v {{")?;
741 if meta.is_recursive(def) {
742 writeln!(
743 out,
744 "{indent} {enum_name}::{variant}(x) => Ok(*x),"
745 )?;
746 } else {
747 writeln!(
748 out,
749 "{indent} {enum_name}::{variant}(x) => Ok(x),"
750 )?;
751 }
752 writeln!(out, "{indent} other => Err(other),")?;
753 writeln!(out, "{indent} }}")?;
754 writeln!(out, "{indent} }}")?;
755 writeln!(out, "{indent}}}")?;
756 }
757 Ok(())
758}