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 if ty.generic_ref && !params.contains(&ty.name.as_str()) {
228 params.push(&ty.name);
229 }
230 }
231 }
232 if params.is_empty() {
233 String::new()
234 } else {
235 format!("<{}>", params.join(&format!("{bounds}, ")) + bounds)
236 }
237}
238
239fn write_struct<W: Write>(
240 out: &mut W,
241 indent: &str,
242 def: &Definition,
243 _meta: &Metadata,
244 config: &Config,
245) -> io::Result<()> {
246 let kind = match def.category {
247 Category::Types => "constructor",
248 Category::Functions => "method",
249 };
250 writeln!(
251 out,
252 "\n{indent}/// [`{name}`](https://core.telegram.org/{kind}/{name})\n\
253 {indent}///\n\
254 {indent}/// Generated from:\n\
255 {indent}/// ```tl\n\
256 {indent}/// {def}\n\
257 {indent}/// ```",
258 name = def.full_name(),
259 )?;
260
261 if config.impl_debug {
262 writeln!(out, "{indent}#[derive(Debug)]")?;
263 }
264 if config.impl_serde {
265 writeln!(out, "{indent}#[derive(serde::Serialize, serde::Deserialize)]")?;
266 }
267 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
268 writeln!(
269 out,
270 "{indent}pub struct {}{} {{",
271 n::def_type_name(def),
272 generic_list(def, ""),
273 )?;
274
275 for param in &def.params {
276 match ¶m.ty {
277 ParameterType::Flags => {} ParameterType::Normal { .. } => {
279 writeln!(
280 out,
281 "{indent} pub {}: {},",
282 n::param_attr_name(param),
283 n::param_qual_name(param),
284 )?;
285 }
286 }
287 }
288 writeln!(out, "{indent}}}")
289}
290
291fn write_identifiable<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
292 let gl = generic_list(def, "");
293 writeln!(
294 out,
295 "{indent}impl{gl} crate::Identifiable for {}{gl} {{\n\
296 {indent} const CONSTRUCTOR_ID: u32 = {:#010x};\n\
297 {indent}}}",
298 n::def_type_name(def),
299 def.id,
300 )
301}
302
303fn write_struct_serializable<W: Write>(
304 out: &mut W,
305 indent: &str,
306 def: &Definition,
307 meta: &Metadata,
308) -> io::Result<()> {
309 let gl_decl = generic_list(def, ": crate::Serializable");
310 let gl_use = generic_list(def, "");
311
312 writeln!(
313 out,
314 "{indent}impl{gl_decl} crate::Serializable for {}{gl_use} {{",
315 n::def_type_name(def)
316 )?;
317
318 let underscore = if def.category == Category::Types && def.params.is_empty() { "_" } else { "" };
319 writeln!(out, "{indent} fn serialize(&self, {underscore}buf: &mut impl Extend<u8>) {{")?;
320
321 if def.category == Category::Functions {
322 writeln!(out, "{indent} use crate::Identifiable;")?;
323 writeln!(out, "{indent} Self::CONSTRUCTOR_ID.serialize(buf);")?;
324 }
325
326 for param in &def.params {
327 write_param_serialization(out, indent, def, meta, param)?;
328 }
329
330 writeln!(out, "{indent} }}")?;
331 writeln!(out, "{indent}}}")
332}
333
334fn write_param_serialization<W: Write>(
335 out: &mut W,
336 indent: &str,
337 def: &Definition,
338 meta: &Metadata,
339 param: &layer_tl_parser::tl::Parameter,
340) -> io::Result<()> {
341 use ParameterType::*;
342
343 match ¶m.ty {
344 Flags => {
345 if meta.is_unused_flag(def, param) {
346 writeln!(out, "{indent} 0u32.serialize(buf);")?;
347 return Ok(());
348 }
349 write!(out, "{indent} (")?;
351 let mut first = true;
352 for other in &def.params {
353 if let Normal { flag: Some(fl), ty, .. } = &other.ty {
354 if fl.name != param.name { continue; }
355 if !first { write!(out, " | ")?; }
356 first = false;
357 if ty.name == "true" {
358 write!(out, "if self.{} {{ 1 << {} }} else {{ 0 }}", n::param_attr_name(other), fl.index)?;
359 } else {
360 write!(out, "if self.{}.is_some() {{ 1 << {} }} else {{ 0 }}", n::param_attr_name(other), fl.index)?;
361 }
362 }
363 }
364 if first { write!(out, "0u32")?; }
365 writeln!(out, ").serialize(buf);")?;
366 }
367 Normal { ty, flag } => {
368 let attr = n::param_attr_name(param);
369 if flag.is_some() {
370 if ty.name == "true" {
371 } else {
373 writeln!(out, "{indent} if let Some(v) = &self.{attr} {{ v.serialize(buf); }}")?;
374 }
375 } else {
376 writeln!(out, "{indent} self.{attr}.serialize(buf);")?;
377 }
378 }
379 }
380 Ok(())
381}
382
383fn write_struct_deserializable<W: Write>(
384 out: &mut W,
385 indent: &str,
386 def: &Definition,
387) -> io::Result<()> {
388 let gl_decl = generic_list(def, ": crate::Deserializable");
389 let gl_use = generic_list(def, "");
390
391 let buf_name = if def.params.is_empty() { "_buf" } else { "buf" };
394
395 writeln!(
396 out,
397 "{indent}impl{gl_decl} crate::Deserializable for {}{gl_use} {{",
398 n::def_type_name(def)
399 )?;
400 writeln!(
401 out,
402 "{indent} fn deserialize({buf_name}: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
403 )?;
404
405 let flag_params: Vec<_> = def.params.iter()
407 .filter(|p| p.ty == ParameterType::Flags)
408 .collect();
409
410 for fp in &flag_params {
411 writeln!(
412 out,
413 "{indent} let _{} = u32::deserialize(buf)?;",
414 n::param_attr_name(fp)
415 )?;
416 }
417
418 for param in &def.params {
420 if param.ty == ParameterType::Flags {
421 continue; }
423 if let ParameterType::Normal { ty, flag } = ¶m.ty {
424 let attr = n::param_attr_name(param);
425 if let Some(fl) = flag {
426 if ty.name == "true" {
427 writeln!(
428 out,
429 "{indent} let {attr} = (_{} & (1 << {})) != 0;",
430 fl.name, fl.index
431 )?;
432 } else {
433 writeln!(
434 out,
435 "{indent} let {attr} = if (_{} & (1 << {})) != 0 {{ Some({}::deserialize(buf)?) }} else {{ None }};",
436 fl.name, fl.index, n::type_item_path(ty)
437 )?;
438 }
439 } else {
440 writeln!(
441 out,
442 "{indent} let {attr} = {}::deserialize(buf)?;",
443 n::type_item_path(ty)
444 )?;
445 }
446 }
447 }
448
449 writeln!(out, "{indent} Ok(Self {{")?;
450 for param in &def.params {
451 if param.ty != ParameterType::Flags {
452 let attr = n::param_attr_name(param);
453 writeln!(out, "{indent} {attr},")?;
454 }
455 }
456 writeln!(out, "{indent} }})")?;
457 writeln!(out, "{indent} }}")?;
458 writeln!(out, "{indent}}}")
459}
460
461fn write_remote_call<W: Write>(out: &mut W, indent: &str, def: &Definition) -> io::Result<()> {
462 let gl_decl = generic_list(def, ": crate::Serializable + crate::Deserializable");
465 let gl_use = generic_list(def, "");
466 writeln!(
467 out,
468 "{indent}impl{gl_decl} crate::RemoteCall for {}{gl_use} {{",
469 n::def_type_name(def)
470 )?;
471 writeln!(
472 out,
473 "{indent} type Return = {};",
474 n::type_qual_name(&def.ty)
475 )?;
476 writeln!(out, "{indent}}}")
477}
478
479fn write_enums_mod<W: Write>(
482 defs: &[Definition],
483 config: &Config,
484 meta: &Metadata,
485 out: &mut W,
486) -> io::Result<()> {
487 writeln!(out, "// @generated — do not edit by hand")?;
488 writeln!(out, "pub mod enums {{")?;
489
490 let grouped = grouper::group_types_by_ns(defs);
491 let mut keys: Vec<&Option<String>> = grouped.keys().collect();
492 keys.sort();
493
494 for key in keys {
495 let types = &grouped[key];
496 let indent = if let Some(ns) = key {
497 writeln!(out, " pub mod {ns} {{")?;
498 " ".to_owned()
499 } else {
500 " ".to_owned()
501 };
502
503 for ty in types.iter().filter(|t| !is_builtin(&t.name)) {
504 write_enum(out, &indent, ty, meta, config)?;
505 write_enum_serializable(out, &indent, ty, meta)?;
506 write_enum_deserializable(out, &indent, ty, meta)?;
507 if config.impl_from_type {
508 write_impl_from(out, &indent, ty, meta)?;
509 }
510 if config.impl_from_enum {
511 write_impl_try_from(out, &indent, ty, meta)?;
512 }
513 }
514
515 if key.is_some() {
516 writeln!(out, " }}")?;
517 }
518 }
519
520 writeln!(out, "}}")
521}
522
523fn write_enum<W: Write>(
524 out: &mut W,
525 indent: &str,
526 ty: &layer_tl_parser::tl::Type,
527 meta: &Metadata,
528 config: &Config,
529) -> io::Result<()> {
530 writeln!(
531 out,
532 "\n{indent}/// [`{name}`](https://core.telegram.org/type/{name})",
533 name = n::type_name(ty)
534 )?;
535 if config.impl_debug {
536 writeln!(out, "{indent}#[derive(Debug)]")?;
537 }
538 if config.impl_serde {
539 writeln!(out, "{indent}#[derive(serde::Serialize, serde::Deserialize)]")?;
540 }
541 writeln!(out, "{indent}#[derive(Clone, PartialEq)]")?;
542 writeln!(out, "{indent}pub enum {} {{", n::type_name(ty))?;
543
544 for def in meta.defs_for_type(ty) {
545 let variant = n::def_variant_name(def);
546 if def.params.is_empty() {
547 writeln!(out, "{indent} {variant},")?;
548 } else if meta.is_recursive(def) {
549 writeln!(out, "{indent} {variant}(Box<{}>),", n::def_qual_name(def))?;
550 } else {
551 writeln!(out, "{indent} {variant}({})," , n::def_qual_name(def))?;
552 }
553 }
554
555 writeln!(out, "{indent}}}")
556}
557
558fn write_enum_serializable<W: Write>(
559 out: &mut W,
560 indent: &str,
561 ty: &layer_tl_parser::tl::Type,
562 meta: &Metadata,
563) -> io::Result<()> {
564 writeln!(
565 out,
566 "{indent}impl crate::Serializable for {} {{",
567 n::type_name(ty)
568 )?;
569 writeln!(out, "{indent} fn serialize(&self, buf: &mut impl Extend<u8>) {{")?;
570 writeln!(out, "{indent} use crate::Identifiable;")?;
571 writeln!(out, "{indent} match self {{")?;
572
573 for def in meta.defs_for_type(ty) {
574 let variant = n::def_variant_name(def);
575 let bind = if def.params.is_empty() { "" } else { "(x)" };
576 writeln!(out, "{indent} Self::{variant}{bind} => {{")?;
577 writeln!(out, "{indent} {}::CONSTRUCTOR_ID.serialize(buf);", n::def_qual_name(def))?;
578 if !def.params.is_empty() {
579 writeln!(out, "{indent} x.serialize(buf);")?;
580 }
581 writeln!(out, "{indent} }}")?;
582 }
583
584 writeln!(out, "{indent} }}")?;
585 writeln!(out, "{indent} }}")?;
586 writeln!(out, "{indent}}}")
587}
588
589fn write_enum_deserializable<W: Write>(
590 out: &mut W,
591 indent: &str,
592 ty: &layer_tl_parser::tl::Type,
593 meta: &Metadata,
594) -> io::Result<()> {
595 writeln!(
596 out,
597 "{indent}impl crate::Deserializable for {} {{",
598 n::type_name(ty)
599 )?;
600 writeln!(
601 out,
602 "{indent} fn deserialize(buf: crate::deserialize::Buffer) -> crate::deserialize::Result<Self> {{"
603 )?;
604 writeln!(out, "{indent} use crate::Identifiable;")?;
605 writeln!(out, "{indent} let id = u32::deserialize(buf)?;")?;
606 writeln!(out, "{indent} Ok(match id {{")?;
607
608 for def in meta.defs_for_type(ty) {
609 let variant = n::def_variant_name(def);
610 let qual = n::def_qual_name(def);
611 if def.params.is_empty() {
612 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant},")?;
613 } else if meta.is_recursive(def) {
614 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}(Box::new({qual}::deserialize(buf)?)),")?;
615 } else {
616 writeln!(out, "{indent} {qual}::CONSTRUCTOR_ID => Self::{variant}({qual}::deserialize(buf)?),")?;
617 }
618 }
619
620 writeln!(
621 out,
622 "{indent} _ => return Err(crate::deserialize::Error::UnexpectedConstructor {{ id }}),"
623 )?;
624 writeln!(out, "{indent} }})")?;
625 writeln!(out, "{indent} }}")?;
626 writeln!(out, "{indent}}}")
627}
628
629fn write_impl_from<W: Write>(
630 out: &mut W,
631 indent: &str,
632 ty: &layer_tl_parser::tl::Type,
633 meta: &Metadata,
634) -> io::Result<()> {
635 for def in meta.defs_for_type(ty) {
636 let enum_name = n::type_name(ty);
637 let qual = n::def_qual_name(def);
638 let variant = n::def_variant_name(def);
639
640 writeln!(out, "{indent}impl From<{qual}> for {enum_name} {{")?;
641 let underscore = if def.params.is_empty() { "_" } else { "" };
642 writeln!(out, "{indent} fn from({underscore}x: {qual}) -> Self {{")?;
643 if def.params.is_empty() {
644 writeln!(out, "{indent} Self::{variant}")?;
645 } else if meta.is_recursive(def) {
646 writeln!(out, "{indent} Self::{variant}(Box::new(x))")?;
647 } else {
648 writeln!(out, "{indent} Self::{variant}(x)")?;
649 }
650 writeln!(out, "{indent} }}")?;
651 writeln!(out, "{indent}}}")?;
652 }
653 Ok(())
654}
655
656fn write_impl_try_from<W: Write>(
657 out: &mut W,
658 indent: &str,
659 ty: &layer_tl_parser::tl::Type,
660 meta: &Metadata,
661) -> io::Result<()> {
662 let enum_name = n::type_name(ty);
663 for def in meta.defs_for_type(ty) {
664 if def.params.is_empty() { continue; }
665 let qual = n::def_qual_name(def);
666 let variant = n::def_variant_name(def);
667
668 writeln!(out, "{indent}impl TryFrom<{enum_name}> for {qual} {{")?;
669 writeln!(out, "{indent} type Error = {enum_name};")?;
670 writeln!(out, "{indent} #[allow(unreachable_patterns)]")?;
671 writeln!(out, "{indent} fn try_from(v: {enum_name}) -> Result<Self, Self::Error> {{")?;
672 writeln!(out, "{indent} match v {{")?;
673 if meta.is_recursive(def) {
674 writeln!(out, "{indent} {enum_name}::{variant}(x) => Ok(*x),")?;
675 } else {
676 writeln!(out, "{indent} {enum_name}::{variant}(x) => Ok(x),")?;
677 }
678 writeln!(out, "{indent} other => Err(other),")?;
679 writeln!(out, "{indent} }}")?;
680 writeln!(out, "{indent} }}")?;
681 writeln!(out, "{indent}}}")?;
682 }
683 Ok(())
684}