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