trans_gen/gens/cpp/
mod.rs

1use super::*;
2
3fn conv(name: &str) -> String {
4    name.replace("Int32", "Int")
5        .replace("Int64", "Long")
6        .replace("Float32", "Float")
7        .replace("Float64", "Double")
8}
9
10pub struct Generator {
11    files: HashMap<String, String>,
12    model_include: String,
13}
14
15fn type_name(schema: &Schema) -> String {
16    match schema {
17        Schema::Bool => "bool".to_owned(),
18        Schema::Int32 => "int".to_owned(),
19        Schema::Int64 => "long long".to_owned(),
20        Schema::Float32 => "float".to_owned(),
21        Schema::Float64 => "double".to_owned(),
22        Schema::String => "std::string".to_owned(),
23        Schema::OneOf {
24            base_name: name, ..
25        } => format!("std::shared_ptr<{}>", name.camel_case(conv)),
26        Schema::Struct(Struct { name, .. })
27        | Schema::Enum {
28            base_name: name, ..
29        } => format!("{}", name.camel_case(conv)),
30        Schema::Option(inner) => format!("std::shared_ptr<{}>", type_name(inner)),
31        Schema::Vec(inner) => format!("std::vector<{}>", type_name(inner)),
32        Schema::Map(key, value) => format!(
33            "std::unordered_map<{}, {}>",
34            type_name(key),
35            type_name(value)
36        ),
37    }
38}
39
40fn index_var_name(index_var: &mut usize) -> String {
41    let result = "ijk".chars().nth(*index_var).unwrap();
42    *index_var += 1;
43    result.to_string()
44}
45
46fn var_name(name: &str) -> &str {
47    match name.rfind('.') {
48        Some(index) => &name[(index + 1)..],
49        None => name,
50    }
51}
52
53fn write_includes(writer: &mut Writer, schema: &Schema, current: bool) -> std::fmt::Result {
54    let mut includes = vec!["<string>".to_string(), "\"../Stream.hpp\"".to_string()];
55    collect_includes(&mut includes, schema, current);
56    includes.sort();
57    includes.dedup();
58    for include in includes {
59        writeln!(writer, "#include {}", include)?;
60    }
61    Ok(())
62}
63
64fn collect_includes(result: &mut Vec<String>, schema: &Schema, current: bool) {
65    if current {
66        match schema {
67            Schema::Bool
68            | Schema::Int32
69            | Schema::Int64
70            | Schema::Float32
71            | Schema::Float64
72            | Schema::String => {}
73            Schema::Option(_) => {
74                result.push("<memory>".to_string());
75            }
76            Schema::Map(_, _) => {
77                result.push("<unordered_map>".to_string());
78            }
79            Schema::Vec(_) => {
80                result.push("<vector>".to_string());
81            }
82            Schema::Struct(Struct { name, .. })
83            | Schema::OneOf {
84                base_name: name, ..
85            }
86            | Schema::Enum {
87                base_name: name, ..
88            } => {
89                result.push("<stdexcept>".to_string());
90                result.push(format!("\"{}.hpp\"", name.camel_case(conv)));
91            }
92        }
93    }
94    match schema {
95        Schema::Bool
96        | Schema::Int32
97        | Schema::Int64
98        | Schema::Float32
99        | Schema::Float64
100        | Schema::String
101        | Schema::Enum { .. } => {}
102        Schema::Option(inner) => {
103            collect_includes(result, inner, true);
104        }
105        Schema::Map(key_type, value_type) => {
106            collect_includes(result, key_type, true);
107            collect_includes(result, value_type, true);
108        }
109        Schema::Vec(inner) => {
110            collect_includes(result, inner, true);
111        }
112        Schema::Struct(Struct { fields, .. }) => {
113            for field in fields {
114                collect_includes(result, &field.schema, true);
115            }
116        }
117        Schema::OneOf { variants, .. } => {
118            for variant in variants {
119                for field in &variant.fields {
120                    collect_includes(result, &field.schema, true);
121                }
122            }
123        }
124    }
125}
126
127fn write_struct_def(
128    writer: &mut Writer,
129    schema: &Schema,
130    struc: &Struct,
131    base: Option<(&Name, usize)>,
132) -> std::fmt::Result {
133    let full_name = if let Some((base_name, _)) = base {
134        format!(
135            "{}::{}",
136            base_name.camel_case(conv),
137            struc.name.camel_case(conv)
138        )
139    } else {
140        struc.name.camel_case(conv)
141    };
142
143    // Class
144    if let Some((base_name, _)) = base {
145        writeln!(
146            writer,
147            "class {}::{} : public {} {{",
148            base_name.camel_case(conv),
149            struc.name.camel_case(conv),
150            base_name.camel_case(conv),
151        )?;
152    } else {
153        writeln!(writer, "class {} {{", struc.name.camel_case(conv))?;
154    }
155    writer.inc_ident();
156    if let Some((_, tag)) = base {
157        writer.dec_ident();
158        writeln!(writer, "public:")?;
159        writer.inc_ident();
160        writeln!(writer, "static const int TAG = {};", tag)?;
161    }
162
163    // Fields
164    writer.dec_ident();
165    writeln!(writer, "public:")?;
166    writer.inc_ident();
167    for field in &struc.fields {
168        writeln!(
169            writer,
170            "{} {};",
171            type_name(&field.schema),
172            field.name.mixed_case(conv)
173        )?;
174    }
175
176    // Constructor
177    writeln!(writer, "{}();", struc.name.camel_case(conv))?;
178    if !struc.fields.is_empty() {
179        write!(writer, "{}(", struc.name.camel_case(conv))?;
180        for (index, field) in struc.fields.iter().enumerate() {
181            if index > 0 {
182                write!(writer, ", ")?;
183            }
184            write!(
185                writer,
186                "{} {}",
187                type_name(&field.schema),
188                field.name.mixed_case(conv)
189            )?;
190        }
191        writeln!(writer, ");")?;
192    }
193
194    // Read/write
195    writeln!(
196        writer,
197        "static {} readFrom(InputStream& stream);",
198        struc.name.camel_case(conv)
199    )?;
200    writeln!(
201        writer,
202        "void writeTo(OutputStream& stream) const{};",
203        if base.is_some() { " override" } else { "" }
204    )?;
205
206    // Eq
207    if schema.hashable() {
208        writeln!(
209            writer,
210            "bool operator ==(const {}& other) const;",
211            struc.name.camel_case(conv)
212        )?;
213    }
214
215    writer.dec_ident();
216    writeln!(writer, "}};").unwrap();
217
218    // Hash
219    if schema.hashable() {
220        writeln!(writer, "namespace std {{")?;
221        writer.inc_ident();
222        writeln!(writer, "template<>")?;
223        writeln!(writer, "struct hash<{}> {{", full_name)?;
224        writeln!(
225            writer,
226            "    size_t operator ()(const {}& value) const;",
227            full_name
228        )?;
229        writeln!(writer, "}};")?;
230        writer.dec_ident();
231        writeln!(writer, "}}")?;
232    }
233
234    Ok(())
235}
236
237fn write_struct_impl(
238    writer: &mut Writer,
239    schema: &Schema,
240    struc: &Struct,
241    base: Option<(&Name, usize)>,
242) -> std::fmt::Result {
243    let full_name = if let Some((base_name, _)) = base {
244        format!(
245            "{}::{}",
246            base_name.camel_case(conv),
247            struc.name.camel_case(conv)
248        )
249    } else {
250        struc.name.camel_case(conv)
251    };
252
253    // Constructor
254    writeln!(
255        writer,
256        "{}::{}() {{ }}",
257        full_name,
258        struc.name.camel_case(conv)
259    )?;
260    if !struc.fields.is_empty() {
261        write!(writer, "{}::{}(", full_name, struc.name.camel_case(conv))?;
262        for (index, field) in struc.fields.iter().enumerate() {
263            if index > 0 {
264                write!(writer, ", ")?;
265            }
266            write!(
267                writer,
268                "{} {}",
269                type_name(&field.schema),
270                field.name.mixed_case(conv),
271            )?;
272        }
273        write!(writer, ") : ")?;
274        for (index, field) in struc.fields.iter().enumerate() {
275            write!(
276                writer,
277                "{}({})",
278                field.name.mixed_case(conv),
279                field.name.mixed_case(conv),
280            )?;
281            if index + 1 < struc.fields.len() {
282                write!(writer, ", ")?;
283            } else {
284                writeln!(writer, " {{ }}")?;
285            }
286        }
287    }
288
289    // Read
290    writeln!(
291        writer,
292        "{} {}::readFrom(InputStream& stream) {{",
293        full_name, full_name,
294    )?;
295    writer.inc_ident();
296    writeln!(writer, "{} result;", full_name)?;
297    for field in &struc.fields {
298        fn assign(
299            writer: &mut Writer,
300            to: &str,
301            schema: &Schema,
302            index_var: &mut usize,
303        ) -> std::fmt::Result {
304            match schema {
305                Schema::Bool => {
306                    writeln!(writer, "{} = stream.readBool();", to)?;
307                }
308                Schema::Int32 => {
309                    writeln!(writer, "{} = stream.readInt();", to)?;
310                }
311                Schema::Int64 => {
312                    writeln!(writer, "{} = stream.readLongLong();", to)?;
313                }
314                Schema::Float32 => {
315                    writeln!(writer, "{} = stream.readFloat();", to)?;
316                }
317                Schema::Float64 => {
318                    writeln!(writer, "{} = stream.readDouble();", to)?;
319                }
320                Schema::String => {
321                    writeln!(writer, "{} = stream.readString();", to)?;
322                }
323                Schema::Struct(Struct { name, .. })
324                | Schema::OneOf {
325                    base_name: name, ..
326                } => {
327                    writeln!(
328                        writer,
329                        "{} = {}::readFrom(stream);",
330                        to,
331                        name.camel_case(conv)
332                    )?;
333                }
334                Schema::Option(inner) => {
335                    writeln!(writer, "if (stream.readBool()) {{")?;
336                    writer.inc_ident();
337                    writeln!(
338                        writer,
339                        "{} = std::shared_ptr<{}>(new {}());",
340                        to,
341                        type_name(inner),
342                        type_name(inner)
343                    )?;
344                    assign(writer, &format!("*{}", to), inner, index_var)?;
345                    writer.dec_ident();
346                    writeln!(writer, "}} else {{")?;
347                    writeln!(
348                        writer,
349                        "    {} = std::shared_ptr<{}>();",
350                        to,
351                        type_name(inner)
352                    )?;
353                    writeln!(writer, "}}")?;
354                }
355                Schema::Vec(inner) => {
356                    writeln!(
357                        writer,
358                        "{} = std::vector<{}>(stream.readInt());",
359                        to,
360                        type_name(inner),
361                    )?;
362                    let index_var_name = index_var_name(index_var);
363                    writeln!(
364                        writer,
365                        "for (size_t {} = 0; {} < {}.size(); {}++) {{",
366                        index_var_name, index_var_name, to, index_var_name
367                    )?;
368                    writer.inc_ident();
369                    assign(
370                        writer,
371                        &format!("{}[{}]", to, index_var_name),
372                        inner,
373                        index_var,
374                    )?;
375                    writer.dec_ident();
376                    writeln!(writer, "}}")?;
377                }
378                Schema::Map(key_type, value_type) => {
379                    let to_size = format!("{}Size", var_name(to));
380                    writeln!(writer, "size_t {} = stream.readInt();", to_size)?;
381                    writeln!(
382                        writer,
383                        "{} = std::unordered_map<{}, {}>();",
384                        to,
385                        type_name(key_type),
386                        type_name(value_type)
387                    )?;
388                    writeln!(writer, "{}.reserve({});", to, to_size)?;
389                    let index_var_name = index_var_name(index_var);
390                    writeln!(
391                        writer,
392                        "for (size_t {} = 0; {} < {}; {}++) {{",
393                        index_var_name, index_var_name, to_size, index_var_name
394                    )?;
395                    writer.inc_ident();
396                    writeln!(writer, "{} {}Key;", type_name(key_type), var_name(to))?;
397                    assign(writer, &format!("{}Key", var_name(to)), key_type, index_var)?;
398                    writeln!(writer, "{} {}Value;", type_name(value_type), var_name(to))?;
399                    assign(
400                        writer,
401                        &format!("{}Value", var_name(to)),
402                        value_type,
403                        index_var,
404                    )?;
405                    writeln!(
406                        writer,
407                        "{}.emplace(std::make_pair({}Key, {}Value));",
408                        to,
409                        var_name(to),
410                        var_name(to)
411                    )?;
412                    writer.dec_ident();
413                    writeln!(writer, "}}")?;
414                }
415                Schema::Enum {
416                    documentation: _,
417                    base_name,
418                    variants,
419                } => {
420                    writeln!(writer, "switch (stream.readInt()) {{")?;
421                    for (tag, variant) in variants.iter().enumerate() {
422                        writeln!(writer, "case {}:", tag)?;
423                        writeln!(
424                            writer,
425                            "    {} = {}::{};",
426                            to,
427                            base_name.camel_case(conv),
428                            variant.name.shouty_snake_case(conv)
429                        )?;
430                        writeln!(writer, "    break;")?;
431                    }
432                    writeln!(writer, "default:")?;
433                    writeln!(
434                        writer,
435                        "    throw std::runtime_error(\"Unexpected tag value\");"
436                    )?;
437                    writeln!(writer, "}}")?;
438                }
439            }
440            Ok(())
441        }
442        assign(
443            writer,
444            &format!("result.{}", field.name.mixed_case(conv)),
445            &field.schema,
446            &mut 0,
447        )?;
448    }
449    writeln!(writer, "return result;")?;
450    writer.dec_ident();
451    writeln!(writer, "}}")?;
452
453    // Writing
454    writeln!(
455        writer,
456        "void {}::writeTo(OutputStream& stream) const {{",
457        full_name,
458    )?;
459    writer.inc_ident();
460    if base.is_some() {
461        writeln!(writer, "stream.write(TAG);")?;
462    }
463    if let Some(magic) = struc.magic {
464        writeln!(writer, "stream.write({});", magic)?;
465    }
466    for field in &struc.fields {
467        fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
468            match schema {
469                Schema::Bool => {
470                    writeln!(writer, "stream.write({});", value)?;
471                }
472                Schema::Int32 => {
473                    writeln!(writer, "stream.write({});", value)?;
474                }
475                Schema::Int64 => {
476                    writeln!(writer, "stream.write({});", value)?;
477                }
478                Schema::Float32 => {
479                    writeln!(writer, "stream.write({});", value)?;
480                }
481                Schema::Float64 => {
482                    writeln!(writer, "stream.write({});", value)?;
483                }
484                Schema::String => {
485                    writeln!(writer, "stream.write({});", value)?;
486                }
487                Schema::Struct(_) => {
488                    writeln!(writer, "{}.writeTo(stream);", value)?;
489                }
490                Schema::OneOf { .. } => {
491                    writeln!(writer, "{}->writeTo(stream);", value)?;
492                }
493                Schema::Option(inner) => {
494                    writeln!(writer, "if ({}) {{", value)?;
495                    writer.inc_ident();
496                    writeln!(writer, "stream.write(true);")?;
497                    write(writer, &format!("(*{})", value), inner)?;
498                    writer.dec_ident();
499                    writeln!(writer, "}} else {{")?;
500                    writeln!(writer, "    stream.write(false);")?;
501                    writeln!(writer, "}}")?;
502                }
503                Schema::Vec(inner) => {
504                    writeln!(writer, "stream.write((int)({}.size()));", value)?;
505                    writeln!(
506                        writer,
507                        "for (const {}& {}Element : {}) {{",
508                        type_name(inner),
509                        var_name(value),
510                        value
511                    )?;
512                    writer.inc_ident();
513                    write(writer, &format!("{}Element", var_name(value)), inner)?;
514                    writer.dec_ident();
515                    writeln!(writer, "}}")?;
516                }
517                Schema::Map(key_type, value_type) => {
518                    writeln!(writer, "stream.write((int)({}.size()));", value)?;
519                    writeln!(
520                        writer,
521                        "for (const auto& {}Entry : {}) {{",
522                        var_name(value),
523                        value
524                    )?;
525                    writer.inc_ident();
526                    write(writer, &format!("{}Entry.first", var_name(value)), key_type)?;
527                    write(
528                        writer,
529                        &format!("{}Entry.second", var_name(value)),
530                        value_type,
531                    )?;
532                    writer.dec_ident();
533                    writeln!(writer, "}}")?;
534                }
535                Schema::Enum { .. } => {
536                    writeln!(writer, "stream.write((int)({}));", value)?;
537                }
538            }
539            Ok(())
540        }
541        write(writer, &field.name.mixed_case(conv), &field.schema)?;
542    }
543    writer.dec_ident();
544    writeln!(writer, "}}")?;
545
546    // Eq
547    if schema.hashable() {
548        writeln!(
549            writer,
550            "bool {}::operator ==(const {}& other) const {{",
551            full_name, full_name,
552        )?;
553        write!(writer, "    return ")?;
554        for (index, field) in struc.fields.iter().enumerate() {
555            if index > 0 {
556                write!(writer, " && ")?;
557            }
558            write!(
559                writer,
560                "{} == other.{}",
561                field.name.mixed_case(conv),
562                field.name.mixed_case(conv),
563            )?;
564        }
565        writeln!(writer, ";")?;
566        writeln!(writer, "}}")?;
567    }
568
569    // Hash
570    if schema.hashable() {
571        writeln!(
572            writer,
573            "size_t std::hash<{}>::operator ()(const {}& value) const {{",
574            full_name, full_name,
575        )?;
576        writer.inc_ident();
577        writeln!(writer, "size_t result = 0;")?;
578        for field in &struc.fields {
579            writeln!(
580                writer,
581                "result ^= std::hash<{}>{{}}(value.{}) + 0x9e3779b9 + (result<<6) + (result>>2);",
582                type_name(&field.schema),
583                field.name.mixed_case(conv),
584            )?;
585        }
586        writeln!(writer, "return result;")?;
587        writer.dec_ident();
588        writeln!(writer, "}}")?;
589    }
590
591    Ok(())
592}
593
594impl crate::Generator for Generator {
595    type Options = ();
596    fn new(_name: &str, _version: &str, _: ()) -> Self {
597        let mut files = HashMap::new();
598        files.insert(
599            "Stream.hpp".to_owned(),
600            include_str!("Stream.hpp").to_owned(),
601        );
602        files.insert(
603            "Stream.cpp".to_owned(),
604            include_str!("Stream.cpp").to_owned(),
605        );
606        Self {
607            files,
608            model_include: "#ifndef _MODEL_HPP_\n#define _MODEL_HPP_\n\n".to_owned(),
609        }
610    }
611    fn result(self) -> GenResult {
612        let Self {
613            mut files,
614            mut model_include,
615        } = self;
616        model_include.push_str("\n#endif\n");
617        files.insert("model/Model.hpp".to_owned(), model_include.to_owned());
618        files.into()
619    }
620    fn add_only(&mut self, schema: &Schema) {
621        match schema {
622            Schema::Enum {
623                documentation: _,
624                base_name,
625                variants,
626            } => {
627                let file_name = format!("model/{}.hpp", base_name.camel_case(conv));
628                self.model_include.push_str(&format!(
629                    "#include \"{}.hpp\"\n",
630                    base_name.camel_case(conv)
631                ));
632                let mut writer = Writer::new();
633                writeln!(
634                    writer,
635                    "#ifndef _MODEL_{}_HPP_",
636                    base_name.shouty_snake_case(conv)
637                )
638                .unwrap();
639                writeln!(
640                    writer,
641                    "#define _MODEL_{}_HPP_",
642                    base_name.shouty_snake_case(conv)
643                )
644                .unwrap();
645                writeln!(writer).unwrap();
646                writeln!(writer, "#include \"../Stream.hpp\"").unwrap();
647                writeln!(writer).unwrap();
648                writeln!(writer, "enum {} {{", base_name.camel_case(conv)).unwrap();
649                writer.inc_ident();
650                for (index, variant) in variants.iter().enumerate() {
651                    writeln!(
652                        writer,
653                        "{} = {}{}",
654                        variant.name.shouty_snake_case(conv),
655                        index,
656                        if index + 1 < variants.len() { "," } else { "" }
657                    )
658                    .unwrap();
659                }
660                writer.dec_ident();
661                writeln!(writer, "}};").unwrap();
662                writeln!(writer).unwrap();
663                writeln!(writer, "#endif").unwrap();
664                self.files.insert(file_name, writer.get());
665            }
666            Schema::Struct(struc) => {
667                let file_name = format!("model/{}.hpp", struc.name.camel_case(conv));
668                self.model_include.push_str(&format!(
669                    "#include \"{}.hpp\"\n",
670                    struc.name.camel_case(conv)
671                ));
672                let mut writer = Writer::new();
673                writeln!(
674                    writer,
675                    "#ifndef _MODEL_{}_HPP_",
676                    struc.name.shouty_snake_case(conv)
677                )
678                .unwrap();
679                writeln!(
680                    writer,
681                    "#define _MODEL_{}_HPP_",
682                    struc.name.shouty_snake_case(conv)
683                )
684                .unwrap();
685                writeln!(writer).unwrap();
686                write_includes(&mut writer, schema, false).unwrap();
687                writeln!(writer).unwrap();
688                write_struct_def(&mut writer, schema, struc, None).unwrap();
689                writeln!(writer).unwrap();
690                writeln!(writer, "#endif").unwrap();
691                self.files.insert(file_name, writer.get());
692
693                let file_name = format!("model/{}.cpp", struc.name.camel_case(conv));
694                let mut writer = Writer::new();
695                writeln!(writer, "#include \"{}.hpp\"", struc.name.camel_case(conv)).unwrap();
696                writeln!(writer).unwrap();
697                write_struct_impl(&mut writer, schema, struc, None).unwrap();
698                self.files.insert(file_name, writer.get());
699            }
700            Schema::OneOf {
701                documentation: _,
702                base_name,
703                variants,
704            } => {
705                let file_name = format!("model/{}.hpp", base_name.camel_case(conv));
706                self.model_include.push_str(&format!(
707                    "#include \"{}.hpp\"\n",
708                    base_name.camel_case(conv)
709                ));
710                let mut writer = Writer::new();
711                writeln!(
712                    writer,
713                    "#ifndef _MODEL_{}_HPP_",
714                    base_name.shouty_snake_case(conv)
715                )
716                .unwrap();
717                writeln!(
718                    writer,
719                    "#define _MODEL_{}_HPP_",
720                    base_name.shouty_snake_case(conv)
721                )
722                .unwrap();
723                writeln!(writer).unwrap();
724                writeln!(writer, "#include <memory>").unwrap();
725                write_includes(&mut writer, schema, false).unwrap();
726                writeln!(writer).unwrap();
727                writeln!(writer, "class {} {{", base_name.camel_case(conv)).unwrap();
728                writeln!(writer, "public:").unwrap();
729                writer.inc_ident();
730                for variant in variants {
731                    writeln!(writer, "class {};", variant.name.camel_case(conv)).unwrap();
732                }
733                writeln!(writer).unwrap();
734                writeln!(
735                    writer,
736                    "static std::shared_ptr<{}> readFrom(InputStream& stream);",
737                    base_name.camel_case(conv)
738                )
739                .unwrap();
740                writeln!(
741                    writer,
742                    "virtual void writeTo(OutputStream& stream) const = 0;",
743                )
744                .unwrap();
745                writer.dec_ident();
746                writeln!(writer, "}};").unwrap();
747                for (tag, variant) in variants.iter().enumerate() {
748                    writeln!(writer).unwrap();
749                    write_struct_def(&mut writer, schema, variant, Some((base_name, tag))).unwrap();
750                }
751                writeln!(writer).unwrap();
752                writeln!(writer, "#endif").unwrap();
753                self.files.insert(file_name, writer.get());
754
755                let file_name = format!("model/{}.cpp", base_name.camel_case(conv));
756                let mut writer = Writer::new();
757                writeln!(writer, "#include \"{}.hpp\"", base_name.camel_case(conv)).unwrap();
758                writeln!(writer, "#include <stdexcept>").unwrap();
759                for (tag, variant) in variants.iter().enumerate() {
760                    writeln!(writer).unwrap();
761                    write_struct_impl(&mut writer, schema, variant, Some((base_name, tag)))
762                        .unwrap();
763                }
764
765                // Reading
766                writeln!(
767                    writer,
768                    "std::shared_ptr<{}> {}::readFrom(InputStream& stream) {{",
769                    base_name.camel_case(conv),
770                    base_name.camel_case(conv),
771                )
772                .unwrap();
773                writer.inc_ident();
774                writeln!(writer, "switch (stream.readInt()) {{").unwrap();
775                for (tag, variant) in variants.iter().enumerate() {
776                    writeln!(writer, "case {}:", tag).unwrap();
777                    let variant_name = format!(
778                        "{}::{}",
779                        base_name.camel_case(conv),
780                        variant.name.camel_case(conv)
781                    );
782                    writeln!(
783                        writer,
784                        "    return std::shared_ptr<{}>(new {}({}::readFrom(stream)));",
785                        variant_name, variant_name, variant_name,
786                    )
787                    .unwrap();
788                }
789                writeln!(writer, "default:").unwrap();
790                writeln!(
791                    writer,
792                    "    throw std::runtime_error(\"Unexpected tag value\");"
793                )
794                .unwrap();
795                writeln!(writer, "}}").unwrap();
796                writer.dec_ident();
797                writeln!(writer, "}};").unwrap();
798
799                self.files.insert(file_name, writer.get());
800            }
801            Schema::Bool
802            | Schema::Int32
803            | Schema::Int64
804            | Schema::Float32
805            | Schema::Float64
806            | Schema::String
807            | Schema::Option(_)
808            | Schema::Vec(_)
809            | Schema::Map(_, _) => {}
810        }
811    }
812}