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