Skip to main content

ferogram_tl_gen/
codegen.rs

1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3//
4// ferogram: async Telegram MTProto client in Rust
5// https://github.com/ankit-chaubey/ferogram
6//
7//
8// If you use or modify this code, keep this notice at the top of your file
9// and include the LICENSE-MIT or LICENSE-APACHE file from this repository:
10// https://github.com/ankit-chaubey/ferogram
11
12//! The public code-generation API.
13
14use 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
24/// Generation configuration.
25pub struct Config {
26    /// Emit `name_for_id(id) -> Option<&'static str>` in the common module.
27    pub gen_name_for_id: bool,
28    /// Also implement `Deserializable` for function types (useful for servers).
29    pub deserializable_functions: bool,
30    /// Derive `Debug` on all generated types.
31    pub impl_debug: bool,
32    /// Emit `From<types::Foo> for enums::Bar` impls.
33    pub impl_from_type: bool,
34    /// Emit `TryFrom<enums::Bar> for types::Foo` impls.
35    pub impl_from_enum: bool,
36    /// Derive `serde::{Serialize, Deserialize}` on all types.
37    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
53// Outputs
54
55/// Writers for each generated Rust module.
56pub struct Outputs<W: Write> {
57    /// Receives the layer constant, `name_for_id`, etc.
58    pub common: W,
59    /// Receives `pub mod types { ... }` (concrete constructors as structs).
60    pub types: W,
61    /// Receives `pub mod functions { ... }` (RPC functions as structs).
62    pub functions: W,
63    /// Receives `pub mod enums { ... }` (boxed types as enums).
64    pub enums: W,
65}
66
67impl Outputs<File> {
68    /// Convenience constructor that opens files inside `out_dir`.
69    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    /// Flush all writers.
82    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
90// Special-cased primitives
91
92/// These TL types are handled as Rust primitives; we never emit structs/enums.
93const BUILTIN_TYPES: &[&str] = &["Bool", "True"];
94
95fn is_builtin(ty_name: &str) -> bool {
96    BUILTIN_TYPES.contains(&ty_name)
97}
98
99// Public API
100
101/// Generate Rust source code from a slice of parsed TL definitions.
102///
103/// Write results into `outputs`. Call `outputs.flush()` when done.
104pub 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
119// Common module
120
121fn write_common<W: Write>(defs: &[Definition], config: &Config, out: &mut W) -> io::Result<()> {
122    // Extract LAYER constant from the first `// LAYER N` comment heuristic
123    // for now we derive it from the highest layer seen in definitions or emit 0.
124    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
154// Struct generation (types + functions)
155
156fn 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
233// Struct pieces
234
235fn 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 &param.ty {
293            ParameterType::Flags => {} // computed on-the-fly
294            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 &param.ty {
367        Flags => {
368            if meta.is_unused_flag(def, param) {
369                writeln!(out, "{indent}        0u32.serialize(buf);")?;
370                return Ok(());
371            }
372            // Compute the flags bitmask from optional params
373            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                    // bool flag: nothing to serialize, it's in the flags word
414                } 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    // Empty structs never read from `buf`. Name it `_buf` to suppress the
437    // unused-variable warning in the generated output.
438    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    // Read flags first so optional params can check them
451    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    // Now deserialize each non-flag param
466    for param in &def.params {
467        if param.ty == ParameterType::Flags {
468            continue; // already done above
469        }
470        if let ParameterType::Normal { ty, flag } = &param.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    // Generic functions (e.g. invokeWithLayer<X>) need the type parameter on
512    // the impl header and on the struct name, just like every other write_* helper.
513    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
528// Enum generation
529
530fn 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}