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