serde_generate/
csharp.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    common,
6    indent::{IndentConfig, IndentedWriter},
7    CodeGeneratorConfig, Encoding,
8};
9use heck::CamelCase;
10use include_dir::include_dir as include_directory;
11use serde_reflection::{ContainerFormat, Format, FormatHolder, Named, Registry, VariantFormat};
12use std::{
13    collections::{BTreeMap, HashMap},
14    fmt::Write as _,
15    io::{Result, Write},
16    path::PathBuf,
17};
18
19/// Main configuration object for code-generation in C#.
20pub struct CodeGenerator<'a> {
21    /// Language-independent configuration.
22    config: &'a CodeGeneratorConfig,
23    /// Mapping from external type names to fully-qualified class names (e.g. "MyClass" -> "MyNamespace.MyClass").
24    /// Derived from `config.external_definitions`.
25    external_qualified_names: HashMap<String, String>,
26}
27
28/// Shared state for the code generation of a C# source file.
29struct CSharpEmitter<'a, T> {
30    /// Writer.
31    out: IndentedWriter<T>,
32    /// Generator.
33    generator: &'a CodeGenerator<'a>,
34    /// Current namespace (e.g. vec!["MyNamespace", "MyClass"])
35    current_namespace: Vec<String>,
36    /// Current (non-qualified) generated class names that could clash with names in the registry
37    /// (e.g. "Builder" or variant classes).
38    /// * We count multiplicities to allow inplace backtracking.
39    /// * Names in the registry (and a few base types such as "Decimal") are assumed to never clash.
40    current_reserved_names: HashMap<String, usize>,
41    /// When we find an enum with all Unit variants, we ser/de as a regular C# enum.
42    /// We keep track of this so we can use the enum's extension class for ser/de since enums can't have methods.
43    cstyle_enum_names: Vec<String>,
44}
45
46impl<'a> CodeGenerator<'a> {
47    /// Create a C# code generator for the given config.
48    pub fn new(config: &'a CodeGeneratorConfig) -> Self {
49        let mut external_qualified_names = HashMap::new();
50        for (namespace, names) in &config.external_definitions {
51            for name in names {
52                external_qualified_names
53                    .insert(name.to_string(), format!("{}.{}", namespace, name));
54            }
55        }
56        Self {
57            config,
58            external_qualified_names,
59        }
60    }
61
62    /// Output class definitions for `registry` in separate source files.
63    /// Source files will be created in a subdirectory of `install_dir` corresponding to the given
64    /// package name (if any, otherwise `install_dir` itself).
65    pub fn write_source_files(
66        &self,
67        install_dir: std::path::PathBuf,
68        registry: &Registry,
69    ) -> Result<std::path::PathBuf> {
70        let current_namespace = self
71            .config
72            .module_name
73            .split('.')
74            .map(String::from)
75            .collect::<Vec<_>>();
76
77        let mut dir_path = install_dir;
78        for part in &current_namespace {
79            dir_path = dir_path.join(part);
80        }
81        std::fs::create_dir_all(&dir_path)?;
82
83        // When we find an enum with all Unit variants, we ser/de as a regular C# enum.
84        // We keep track of this so we can use the enum's extension class for ser/de since enums can't have methods.
85        let mut cstyle_enum_names = Vec::new();
86        if self.config.c_style_enums {
87            for (name, format) in registry {
88                if let ContainerFormat::Enum(variants) = format {
89                    if variants.values().all(|f| f.value == VariantFormat::Unit) {
90                        cstyle_enum_names.push(name.clone());
91                    }
92                }
93            }
94        }
95
96        for (name, format) in registry {
97            self.write_container_class(
98                &dir_path,
99                current_namespace.clone(),
100                cstyle_enum_names.clone(),
101                name,
102                format,
103            )?;
104        }
105        if self.config.serialization {
106            self.write_helper_class(&dir_path, current_namespace, cstyle_enum_names, registry)?;
107        }
108        Ok(dir_path)
109    }
110
111    fn write_container_class(
112        &self,
113        dir_path: &std::path::Path,
114        current_namespace: Vec<String>,
115        cstyle_enum_names: Vec<String>,
116        name: &str,
117        format: &ContainerFormat,
118    ) -> Result<()> {
119        let mut file = std::fs::File::create(dir_path.join(name.to_string() + ".cs"))?;
120        let mut emitter = CSharpEmitter {
121            out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
122            generator: self,
123            current_namespace,
124            current_reserved_names: HashMap::new(),
125            cstyle_enum_names,
126        };
127
128        emitter.output_preamble()?;
129        emitter.output_open_namespace()?;
130        emitter.output_container(name, format)?;
131        emitter.output_close_namespace()?;
132
133        Ok(())
134    }
135
136    fn write_helper_class(
137        &self,
138        dir_path: &std::path::Path,
139        current_namespace: Vec<String>,
140        cstyle_enum_names: Vec<String>,
141        registry: &Registry,
142    ) -> Result<()> {
143        let mut file = std::fs::File::create(dir_path.join("TraitHelpers.cs"))?;
144        let mut emitter = CSharpEmitter {
145            out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
146            generator: self,
147            current_namespace,
148            current_reserved_names: HashMap::new(),
149            cstyle_enum_names,
150        };
151
152        emitter.output_preamble()?;
153        emitter.output_open_namespace()?;
154        emitter.output_trait_helpers(registry)?;
155        emitter.output_close_namespace()?;
156
157        Ok(())
158    }
159}
160
161impl<'a, T> CSharpEmitter<'a, T>
162where
163    T: Write,
164{
165    fn output_preamble(&mut self) -> Result<()> {
166        writeln!(
167            self.out,
168            r"using System;
169using System.Collections.Generic;
170using System.IO;
171using System.Linq;
172using System.Text;
173using System.Numerics;"
174        )?;
175        Ok(())
176    }
177
178    fn output_open_namespace(&mut self) -> Result<()> {
179        writeln!(
180            self.out,
181            "\nnamespace {} {{",
182            self.generator.config.module_name
183        )?;
184        self.out.indent();
185        Ok(())
186    }
187
188    fn output_close_namespace(&mut self) -> Result<()> {
189        self.out.unindent();
190        writeln!(
191            self.out,
192            "\n}} // end of namespace {}",
193            self.generator.config.module_name
194        )?;
195        Ok(())
196    }
197
198    /// Compute a safe reference to the registry type `name` in the given context.
199    /// If `name` is not marked as "reserved" (e.g. "Builder"), we compare the global
200    /// name `self.external_qualified_names[name]` with the current namespace and try to use the
201    /// short string `name` if possible.
202    fn quote_qualified_name(&self, name: &str) -> String {
203        let qname = self
204            .generator
205            .external_qualified_names
206            .get(name)
207            .cloned()
208            .unwrap_or_else(|| format!("{}.{}", self.generator.config.module_name, name));
209        let mut path = qname.split('.').collect::<Vec<_>>();
210        if path.len() <= 1 {
211            return qname;
212        }
213        let name = path.pop().unwrap();
214        if self.current_reserved_names.contains_key(name) {
215            return qname;
216        }
217        for (index, element) in path.iter().enumerate() {
218            match self.current_namespace.get(index) {
219                Some(e) if e == element => (),
220                _ => {
221                    return qname;
222                }
223            }
224        }
225        name.to_string()
226    }
227
228    fn output_comment(&mut self, name: &str) -> std::io::Result<()> {
229        let mut path = self.current_namespace.clone();
230        path.push(name.to_string());
231        if let Some(doc) = self.generator.config.comments.get(&path) {
232            let text = textwrap::indent(doc, "/// ").replace("\n\n", "\n///\n");
233            write!(self.out, "{}", text)?;
234        }
235        Ok(())
236    }
237
238    fn output_custom_code(&mut self) -> std::io::Result<()> {
239        if let Some(code) = self
240            .generator
241            .config
242            .custom_code
243            .get(&self.current_namespace)
244        {
245            writeln!(self.out, "\n{}", code)?;
246        }
247        Ok(())
248    }
249
250    fn is_nullable(&self, format: &Format) -> bool {
251        use Format::*;
252        match format {
253            TypeName(name) => !self.cstyle_enum_names.contains(name),
254            Str | Seq(_) | Map { .. } | TupleArray { .. } => true,
255            Variable(_) => panic!("unexpected value"),
256            _ => false,
257        }
258    }
259
260    fn quote_type(&self, format: &Format) -> String {
261        use Format::*;
262        match format {
263            TypeName(x) => self.quote_qualified_name(x),
264            Unit => "Serde.Unit".into(),
265            Bool => "bool".into(),
266            I8 => "sbyte".into(),
267            I16 => "short".into(),
268            I32 => "int".into(),
269            I64 => "long".into(),
270            I128 => "BigInteger".into(),
271            U8 => "byte".into(),
272            U16 => "ushort".into(),
273            U32 => "uint".into(),
274            U64 => "ulong".into(),
275            U128 => "BigInteger".into(),
276            F32 => "float".into(),
277            F64 => "double".into(),
278            Char => "char".into(),
279            Str => "string".into(),
280            Bytes => "Serde.ValueArray<byte>".into(),
281
282            Option(format) => format!("Serde.Option<{}>", self.quote_type(format)),
283            Seq(format) => format!("Serde.ValueArray<{}>", self.quote_type(format)),
284            Map { key, value } => format!(
285                "Serde.ValueDictionary<{}, {}>",
286                self.quote_type(key),
287                self.quote_type(value)
288            ),
289            Tuple(formats) => format!("({})", self.quote_types(formats)),
290            TupleArray {
291                content,
292                size: _size,
293            } => format!("Serde.ValueArray<{}>", self.quote_type(content),),
294            Variable(_) => panic!("unexpected value"),
295        }
296    }
297
298    fn enter_class(&mut self, name: &str, reserved_subclass_names: &[&str]) {
299        self.out.indent();
300        self.current_namespace.push(name.to_string());
301        for name in reserved_subclass_names {
302            let entry = self
303                .current_reserved_names
304                .entry(name.to_string())
305                .or_insert(0);
306            *entry += 1;
307        }
308    }
309
310    fn leave_class(&mut self, reserved_subclass_names: &[&str]) {
311        self.out.unindent();
312        self.current_namespace.pop();
313        for name in reserved_subclass_names {
314            let entry = self.current_reserved_names.get_mut(*name).unwrap();
315            *entry -= 1;
316            if *entry == 0 {
317                self.current_reserved_names.remove(*name);
318            }
319        }
320    }
321
322    fn quote_types(&self, formats: &[Format]) -> String {
323        formats
324            .iter()
325            .map(|f| self.quote_type(f))
326            .collect::<Vec<_>>()
327            .join(", ")
328    }
329
330    fn output_trait_helpers(&mut self, registry: &Registry) -> Result<()> {
331        let mut subtypes = BTreeMap::new();
332        for format in registry.values() {
333            format
334                .visit(&mut |f| {
335                    if Self::needs_helper(f) {
336                        subtypes.insert(common::mangle_type(f), f.clone());
337                    }
338                    Ok(())
339                })
340                .unwrap();
341        }
342        writeln!(self.out, "static class TraitHelpers {{")?;
343        let reserved_names = &[];
344        self.enter_class("TraitHelpers", reserved_names);
345        for (mangled_name, subtype) in &subtypes {
346            self.output_serialization_helper(mangled_name, subtype)?;
347            self.output_deserialization_helper(mangled_name, subtype)?;
348        }
349        self.leave_class(reserved_names);
350        writeln!(self.out, "}}\n")
351    }
352
353    fn needs_helper(format: &Format) -> bool {
354        use Format::*;
355        matches!(
356            format,
357            Option(_) | Seq(_) | Map { .. } | Tuple(_) | TupleArray { .. }
358        )
359    }
360
361    fn quote_serialize_value(&self, value: &str, format: &Format) -> String {
362        use Format::*;
363        match format {
364            TypeName(_) => format!("{}.Serialize(serializer);", value),
365            Unit => format!("serializer.serialize_unit({});", value),
366            Bool => format!("serializer.serialize_bool({});", value),
367            I8 => format!("serializer.serialize_i8({});", value),
368            I16 => format!("serializer.serialize_i16({});", value),
369            I32 => format!("serializer.serialize_i32({});", value),
370            I64 => format!("serializer.serialize_i64({});", value),
371            I128 => format!("serializer.serialize_i128({});", value),
372            U8 => format!("serializer.serialize_u8({});", value),
373            U16 => format!("serializer.serialize_u16({});", value),
374            U32 => format!("serializer.serialize_u32({});", value),
375            U64 => format!("serializer.serialize_u64({});", value),
376            U128 => format!("serializer.serialize_u128({});", value),
377            F32 => format!("serializer.serialize_f32({});", value),
378            F64 => format!("serializer.serialize_f64({});", value),
379            Char => format!("serializer.serialize_char({});", value),
380            Str => format!("serializer.serialize_str({});", value),
381            Bytes => format!("serializer.serialize_bytes({});", value),
382            _ => format!(
383                "{}.serialize_{}({}, serializer);",
384                self.quote_qualified_name("TraitHelpers"),
385                common::mangle_type(format),
386                value
387            ),
388        }
389    }
390
391    fn quote_deserialize(&self, format: &Format) -> String {
392        use Format::*;
393        match format {
394            TypeName(name) => {
395                if self.cstyle_enum_names.contains(name) {
396                    let extensions_name = format!("{}Extensions", name.to_camel_case());
397                    format!(
398                        "{}.Deserialize(deserializer)",
399                        self.quote_qualified_name(&extensions_name)
400                    )
401                } else {
402                    format!(
403                        "{}.Deserialize(deserializer)",
404                        self.quote_qualified_name(name)
405                    )
406                }
407            }
408            Unit => "deserializer.deserialize_unit()".to_string(),
409            Bool => "deserializer.deserialize_bool()".to_string(),
410            I8 => "deserializer.deserialize_i8()".to_string(),
411            I16 => "deserializer.deserialize_i16()".to_string(),
412            I32 => "deserializer.deserialize_i32()".to_string(),
413            I64 => "deserializer.deserialize_i64()".to_string(),
414            I128 => "deserializer.deserialize_i128()".to_string(),
415            U8 => "deserializer.deserialize_u8()".to_string(),
416            U16 => "deserializer.deserialize_u16()".to_string(),
417            U32 => "deserializer.deserialize_u32()".to_string(),
418            U64 => "deserializer.deserialize_u64()".to_string(),
419            U128 => "deserializer.deserialize_u128()".to_string(),
420            F32 => "deserializer.deserialize_f32()".to_string(),
421            F64 => "deserializer.deserialize_f64()".to_string(),
422            Char => "deserializer.deserialize_char()".to_string(),
423            Str => "deserializer.deserialize_str()".to_string(),
424            Bytes => "deserializer.deserialize_bytes()".to_string(),
425            _ => format!(
426                "{}.deserialize_{}(deserializer)",
427                self.quote_qualified_name("TraitHelpers"),
428                common::mangle_type(format),
429            ),
430        }
431    }
432
433    fn output_serialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
434        use Format::*;
435
436        write!(
437            self.out,
438            "public static void serialize_{}({} value, Serde.ISerializer serializer) {{",
439            name,
440            self.quote_type(format0)
441        )?;
442        self.out.indent();
443        match format0 {
444            Option(format) => {
445                write!(
446                    self.out,
447                    r#"
448if (value.IsSome(out var val)) {{
449    serializer.serialize_option_tag(true);
450    {}
451}} else {{
452    serializer.serialize_option_tag(false);
453}}
454"#,
455                    self.quote_serialize_value("val", format)
456                )?;
457            }
458
459            Seq(format) => {
460                write!(
461                    self.out,
462                    r#"
463serializer.serialize_len(value.Count);
464foreach (var item in value) {{
465    {}
466}}
467"#,
468                    self.quote_serialize_value("item", format)
469                )?;
470            }
471
472            Map { key, value } => {
473                write!(
474                    self.out,
475                    r#"
476serializer.serialize_len(value.Count);
477int[] offsets = new int[value.Count];
478int count = 0;
479foreach (KeyValuePair<{}, {}> entry in value) {{
480    offsets[count++] = serializer.get_buffer_offset();
481    {}
482    {}
483}}
484serializer.sort_map_entries(offsets);
485"#,
486                    self.quote_type(key),
487                    self.quote_type(value),
488                    self.quote_serialize_value("entry.Key", key),
489                    self.quote_serialize_value("entry.Value", value)
490                )?;
491            }
492
493            Tuple(formats) => {
494                writeln!(self.out)?;
495                for (index, format) in formats.iter().enumerate() {
496                    let expr = format!("value.Item{}", index + 1);
497                    writeln!(self.out, "{}", self.quote_serialize_value(&expr, format))?;
498                }
499            }
500
501            TupleArray { content, size } => {
502                write!(
503                    self.out,
504                    r#"
505if (value.Count != {0}) {{
506    throw new Serde.SerializationException("Invalid length for fixed-size array: " + value.Count + " instead of " + {0});
507}}
508foreach (var item in value) {{
509    {1}
510}}
511"#,
512                    size,
513                    self.quote_serialize_value("item", content),
514                )?;
515            }
516
517            _ => panic!("unexpected case"),
518        }
519        self.out.unindent();
520        writeln!(self.out, "}}\n")
521    }
522
523    fn output_deserialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
524        use Format::*;
525
526        write!(
527            self.out,
528            "public static {} deserialize_{}(Serde.IDeserializer deserializer) {{",
529            self.quote_type(format0),
530            name,
531        )?;
532        self.out.indent();
533        match format0 {
534            Option(format) => {
535                write!(
536                    self.out,
537                    r#"
538bool tag = deserializer.deserialize_option_tag();
539if (!tag) {{
540    return Serde.Option<{0}>.None;
541}} else {{
542    return Serde.Option<{0}>.Some({1});
543}}
544"#,
545                    self.quote_type(format),
546                    self.quote_deserialize(format),
547                )?;
548            }
549
550            Seq(format) => {
551                write!(
552                    self.out,
553                    r#"
554long length = deserializer.deserialize_len();
555{0}[] obj = new {0}[length];
556for (int i = 0; i < length; i++) {{
557    obj[i] = {1};
558}}
559return new Serde.ValueArray<{0}>(obj);
560"#,
561                    self.quote_type(format),
562                    self.quote_deserialize(format)
563                )?;
564            }
565
566            Map { key, value } => {
567                write!(
568                    self.out,
569                    r#"
570long length = deserializer.deserialize_len();
571var obj = new Dictionary<{0}, {1}>();
572int previous_key_start = 0;
573int previous_key_end = 0;
574for (long i = 0; i < length; i++) {{
575    int key_start = deserializer.get_buffer_offset();
576    var key = {2};
577    int key_end = deserializer.get_buffer_offset();
578    if (i > 0) {{
579        deserializer.check_that_key_slices_are_increasing(
580            new Serde.Range(previous_key_start, previous_key_end),
581            new Serde.Range(key_start, key_end));
582    }}
583    previous_key_start = key_start;
584    previous_key_end = key_end;
585    var value = {3};
586    obj[key] = value;
587}}
588return new Serde.ValueDictionary<{0}, {1}>(obj);
589"#,
590                    self.quote_type(key),
591                    self.quote_type(value),
592                    self.quote_deserialize(key),
593                    self.quote_deserialize(value),
594                )?;
595            }
596
597            Tuple(formats) => {
598                write!(
599                    self.out,
600                    r#"
601return ({}
602);
603"#,
604                    formats
605                        .iter()
606                        .map(|f| format!("\n    {}", self.quote_deserialize(f)))
607                        .collect::<Vec<_>>()
608                        .join(",")
609                )?;
610            }
611
612            TupleArray { content, size } => {
613                write!(
614                    self.out,
615                    r#"
616{0}[] obj = new {0}[{1}];
617for (int i = 0; i < {1}; i++) {{
618    obj[i] = {2};
619}}
620return new Serde.ValueArray<{0}>(obj);
621"#,
622                    self.quote_type(content),
623                    size,
624                    self.quote_deserialize(content)
625                )?;
626            }
627
628            _ => panic!("unexpected case"),
629        }
630        self.out.unindent();
631        writeln!(self.out, "}}\n")
632    }
633
634    fn output_variant(
635        &mut self,
636        base: &str,
637        index: u32,
638        name: &str,
639        variant: &VariantFormat,
640    ) -> Result<()> {
641        use VariantFormat::*;
642        let fields = match variant {
643            Unit => Vec::new(),
644            NewType(format) => vec![Named {
645                name: "value".to_string(),
646                value: format.as_ref().clone(),
647            }],
648            Tuple(formats) => formats
649                .iter()
650                .enumerate()
651                .map(|(i, f)| Named {
652                    name: format!("field{}", i),
653                    value: f.clone(),
654                })
655                .collect(),
656            Struct(fields) => fields.clone(),
657            Variable(_) => panic!("incorrect value"),
658        };
659        self.output_struct_or_variant_container(Some(base), Some(index), name, &fields)
660    }
661
662    fn output_variants(
663        &mut self,
664        base: &str,
665        variants: &BTreeMap<u32, Named<VariantFormat>>,
666    ) -> Result<()> {
667        for (index, variant) in variants {
668            self.output_variant(base, *index, &variant.name, &variant.value)?;
669        }
670        Ok(())
671    }
672
673    fn output_struct_or_variant_container(
674        &mut self,
675        variant_base: Option<&str>,
676        variant_index: Option<u32>,
677        name: &str,
678        fields: &[Named<Format>],
679    ) -> Result<()> {
680        // Beginning of class
681        writeln!(self.out)?;
682        let fn_mods = if let Some(base) = variant_base {
683            self.output_comment(name)?;
684            writeln!(
685                self.out,
686                "public sealed class {0}: {1}, IEquatable<{0}>, ICloneable {{",
687                name, base
688            )?;
689            "override "
690        } else {
691            self.output_comment(name)?;
692            writeln!(
693                self.out,
694                "public sealed class {0}: IEquatable<{0}>, ICloneable {{",
695                name
696            )?;
697            ""
698        };
699        let reserved_names = &[];
700        self.enter_class(name, reserved_names);
701
702        // Fields
703        for field in fields {
704            self.output_comment(&field.name)?;
705            writeln!(
706                self.out,
707                "public {} {};",
708                self.quote_type(&field.value),
709                field.name
710            )?;
711        }
712        if !fields.is_empty() {
713            writeln!(self.out)?;
714        }
715
716        // Constructor.
717        writeln!(
718            self.out,
719            "public {}({}) {{",
720            name,
721            fields
722                .iter()
723                .map(|f| format!("{} _{}", self.quote_type(&f.value), &f.name))
724                .collect::<Vec<_>>()
725                .join(", ")
726        )?;
727        self.out.indent();
728        for field in fields {
729            if self.is_nullable(&field.value) {
730                writeln!(
731                    self.out,
732                    "if (_{0} == null) throw new ArgumentNullException(nameof(_{0}));",
733                    &field.name
734                )?;
735            }
736            writeln!(self.out, "{0} = _{0};", &field.name)?;
737        }
738        self.out.unindent();
739        writeln!(self.out, "}}")?;
740
741        // Serialize
742        if self.generator.config.serialization {
743            writeln!(
744                self.out,
745                "\npublic {}void Serialize(Serde.ISerializer serializer) {{",
746                fn_mods
747            )?;
748            self.out.indent();
749            writeln!(self.out, "serializer.increase_container_depth();")?;
750            if let Some(index) = variant_index {
751                writeln!(self.out, "serializer.serialize_variant_index({});", index)?;
752            }
753            for field in fields {
754                writeln!(
755                    self.out,
756                    "{}",
757                    self.quote_serialize_value(&field.name, &field.value)
758                )?;
759            }
760            writeln!(self.out, "serializer.decrease_container_depth();")?;
761            self.out.unindent();
762            writeln!(self.out, "}}")?;
763
764            if variant_index.is_none() {
765                for encoding in &self.generator.config.encodings {
766                    self.output_class_serialize_for_encoding(*encoding)?;
767                }
768            }
769        }
770
771        // Deserialize (struct) or Load (variant)
772        if self.generator.config.serialization {
773            if variant_index.is_none() {
774                writeln!(
775                    self.out,
776                    "\npublic static {}{} Deserialize(Serde.IDeserializer deserializer) {{",
777                    fn_mods, name,
778                )?;
779            } else {
780                writeln!(
781                    self.out,
782                    "\ninternal static {} Load(Serde.IDeserializer deserializer) {{",
783                    name,
784                )?;
785            }
786            self.out.indent();
787            writeln!(self.out, "deserializer.increase_container_depth();")?;
788            writeln!(
789                self.out,
790                "{0} obj = new {0}(\n\t{1});",
791                name,
792                fields
793                    .iter()
794                    .map(|f| self.quote_deserialize(&f.value))
795                    .collect::<Vec<_>>()
796                    .join(",\n\t")
797            )?;
798            writeln!(self.out, "deserializer.decrease_container_depth();")?;
799            writeln!(self.out, "return obj;")?;
800            self.out.unindent();
801            writeln!(self.out, "}}")?;
802
803            if variant_index.is_none() {
804                for encoding in &self.generator.config.encodings {
805                    self.output_class_deserialize_for_encoding(name, *encoding)?;
806                }
807            }
808        }
809        // Equality
810        writeln!(
811            self.out,
812            "public override bool Equals(object obj) => obj is {} other && Equals(other);\n",
813            name
814        )?;
815        writeln!(
816            self.out,
817            "public static bool operator ==({0} left, {0} right) => Equals(left, right);\n",
818            name
819        )?;
820        writeln!(
821            self.out,
822            "public static bool operator !=({0} left, {0} right) => !Equals(left, right);\n",
823            name
824        )?;
825
826        writeln!(self.out, "public bool Equals({} other) {{", name)?;
827        self.out.indent();
828        writeln!(self.out, "if (other == null) return false;")?;
829        writeln!(self.out, "if (ReferenceEquals(this, other)) return true;")?;
830        for field in fields {
831            writeln!(
832                self.out,
833                "if (!{0}.Equals(other.{0})) return false;",
834                &field.name,
835            )?;
836        }
837        writeln!(self.out, "return true;")?;
838        self.out.unindent();
839        writeln!(self.out, "}}")?;
840
841        // Hashing
842        writeln!(self.out, "\npublic override int GetHashCode() {{")?;
843        self.out.indent();
844        writeln!(self.out, "unchecked {{")?;
845        self.out.indent();
846        writeln!(self.out, "int value = 7;")?;
847        for field in fields {
848            writeln!(
849                self.out,
850                "value = 31 * value + {0}.GetHashCode();",
851                &field.name
852            )?;
853        }
854        writeln!(self.out, "return value;")?;
855        self.out.unindent();
856        writeln!(self.out, "}}")?;
857        self.out.unindent();
858        writeln!(self.out, "}}\n")?;
859
860        // Clone
861        if variant_base.is_none() {
862            // Derived classes can use the method inherited from the base class, it works with derived fields.
863            writeln!(
864                self.out,
865                "/// <summary>Creates a shallow clone of the object.</summary>"
866            )?;
867            writeln!(
868                self.out,
869                "public {0} Clone() => ({0})MemberwiseClone();\n",
870                name
871            )?;
872            writeln!(self.out, "object ICloneable.Clone() => Clone();\n")?;
873        }
874
875        // Custom code
876        self.output_custom_code()?;
877
878        // End of class
879        self.leave_class(reserved_names);
880        writeln!(self.out, "}}")
881    }
882
883    fn output_enum_container(
884        &mut self,
885        name: &str,
886        variants: &BTreeMap<u32, Named<VariantFormat>>,
887    ) -> Result<()> {
888        writeln!(self.out)?;
889        self.output_comment(name)?;
890        writeln!(
891            self.out,
892            "public abstract class {0}: IEquatable<{0}>, ICloneable {{",
893            name
894        )?;
895        let reserved_names = variants
896            .values()
897            .map(|v| v.name.as_str())
898            .collect::<Vec<_>>();
899        self.enter_class(name, &reserved_names);
900
901        // Serialize/Deserialize
902        if self.generator.config.serialization {
903            writeln!(
904                self.out,
905                "\npublic abstract void Serialize(Serde.ISerializer serializer);"
906            )?;
907            write!(
908                self.out,
909                "\npublic static {} Deserialize(Serde.IDeserializer deserializer) {{",
910                name
911            )?;
912            self.out.indent();
913            writeln!(
914                self.out,
915                r#"
916int index = deserializer.deserialize_variant_index();
917switch (index) {{"#,
918            )?;
919            self.out.indent();
920            for (index, variant) in variants {
921                writeln!(
922                    self.out,
923                    "case {}: return {}.Load(deserializer);",
924                    index, variant.name,
925                )?;
926            }
927            writeln!(
928                self.out,
929                r#"default: throw new Serde.DeserializationException("Unknown variant index for {}: " + index);"#,
930                name,
931            )?;
932            self.out.unindent();
933            writeln!(self.out, "}}")?;
934            self.out.unindent();
935            writeln!(self.out, "}}")?;
936
937            for encoding in &self.generator.config.encodings {
938                self.output_class_serialize_for_encoding(*encoding)?;
939                self.output_class_deserialize_for_encoding(name, *encoding)?;
940            }
941        }
942
943        // HashCode
944        writeln!(self.out, "public override int GetHashCode() {{")?;
945        self.out.indent();
946        writeln!(self.out, "switch (this) {{")?;
947        for variant in variants.values() {
948            writeln!(self.out, "case {} x: return x.GetHashCode();", variant.name)?;
949        }
950        writeln!(
951            self.out,
952            r#"default: throw new InvalidOperationException("Unknown variant type");"#
953        )?;
954        writeln!(self.out, "}}")?;
955        self.out.unindent();
956        writeln!(self.out, "}}")?;
957
958        // Equals
959        writeln!(
960            self.out,
961            "public override bool Equals(object obj) => obj is {} other && Equals(other);\n",
962            name
963        )?;
964
965        writeln!(self.out, "public bool Equals({} other) {{", name)?;
966        self.out.indent();
967        writeln!(self.out, "if (other == null) return false;")?;
968        writeln!(self.out, "if (ReferenceEquals(this, other)) return true;")?;
969        writeln!(self.out, "if (GetType() != other.GetType()) return false;")?;
970        writeln!(self.out, "switch (this) {{")?;
971        for variant in variants.values() {
972            writeln!(
973                self.out,
974                "case {0} x: return x.Equals(({0})other);",
975                variant.name
976            )?;
977        }
978        writeln!(
979            self.out,
980            r#"default: throw new InvalidOperationException("Unknown variant type");"#
981        )?;
982        writeln!(self.out, "}}")?;
983        self.out.unindent();
984        writeln!(self.out, "}}\n")?;
985
986        // Clone
987        writeln!(
988            self.out,
989            "/// <summary>Creates a shallow clone of the object.</summary>"
990        )?;
991        writeln!(
992            self.out,
993            "public {0} Clone() => ({0})MemberwiseClone();\n",
994            name
995        )?;
996        writeln!(self.out, "object ICloneable.Clone() => Clone();\n")?;
997
998        self.output_variants(name, variants)?;
999        self.leave_class(&reserved_names);
1000        writeln!(self.out, "}}\n")
1001    }
1002
1003    fn output_cstyle_enum(
1004        &mut self,
1005        name: &str,
1006        variants: &BTreeMap<u32, Named<VariantFormat>>,
1007    ) -> Result<()> {
1008        writeln!(self.out)?;
1009        self.output_comment(name)?;
1010        writeln!(self.out, "public enum {} {{", name)?;
1011        self.out.indent();
1012        for (index, variant) in variants {
1013            writeln!(self.out, "{} = {},", variant.name, index)?;
1014        }
1015        self.out.unindent();
1016        writeln!(self.out, "}}")?;
1017
1018        if self.generator.config.serialization {
1019            let ext_name = format!("{}Extensions", name.to_camel_case());
1020            writeln!(self.out, "public static class {} {{", ext_name)?;
1021            self.enter_class(&ext_name, &[]);
1022
1023            writeln!(
1024                self.out,
1025                r#"
1026public static void Serialize(this {0} value, Serde.ISerializer serializer) {{
1027    serializer.increase_container_depth();
1028    serializer.serialize_variant_index((int)value);
1029    serializer.decrease_container_depth();
1030}}
1031
1032public static {0} Deserialize(Serde.IDeserializer deserializer) {{
1033    deserializer.increase_container_depth();
1034    int index = deserializer.deserialize_variant_index();
1035    if (!Enum.IsDefined(typeof({0}), index))
1036        throw new Serde.DeserializationException("Unknown variant index for {}: " + index);
1037    {0} value = ({0})index;
1038    deserializer.decrease_container_depth();
1039    return value;
1040}}"#,
1041                name
1042            )?;
1043
1044            for encoding in &self.generator.config.encodings {
1045                writeln!(
1046                    self.out,
1047                    r#"
1048public static byte[] {0}Serialize(this {1} value)  {{
1049    Serde.ISerializer serializer = new {0}.{0}Serializer();
1050    Serialize(value, serializer);
1051    return serializer.get_bytes();
1052}}"#,
1053                    encoding.name().to_camel_case(),
1054                    name
1055                )?;
1056                self.output_class_deserialize_for_encoding(name, *encoding)?;
1057            }
1058
1059            self.leave_class(&[]);
1060            writeln!(self.out, "}}")?;
1061        }
1062
1063        Ok(())
1064    }
1065
1066    fn output_class_serialize_for_encoding(&mut self, encoding: Encoding) -> Result<()> {
1067        writeln!(
1068            self.out,
1069            r#"
1070public int {0}Serialize(byte[] outputBuffer) => {0}Serialize(new ArraySegment<byte>(outputBuffer));
1071
1072public int {0}Serialize(ArraySegment<byte> outputBuffer) {{
1073    Serde.ISerializer serializer = new {0}.{0}Serializer(outputBuffer);
1074    Serialize(serializer);
1075    return serializer.get_buffer_offset();
1076}}
1077
1078public byte[] {0}Serialize()  {{
1079    Serde.ISerializer serializer = new {0}.{0}Serializer();
1080    Serialize(serializer);
1081    return serializer.get_bytes();
1082}}"#,
1083            encoding.name().to_camel_case()
1084        )
1085    }
1086
1087    fn output_class_deserialize_for_encoding(
1088        &mut self,
1089        name: &str,
1090        encoding: Encoding,
1091    ) -> Result<()> {
1092        writeln!(
1093            self.out,
1094            r#"
1095public static {0} {1}Deserialize(byte[] input) => {1}Deserialize(new ArraySegment<byte>(input));
1096
1097public static {0} {1}Deserialize(ArraySegment<byte> input) {{
1098    if (input == null) {{
1099         throw new Serde.DeserializationException("Cannot deserialize null array");
1100    }}
1101    Serde.IDeserializer deserializer = new {1}.{1}Deserializer(input);
1102    {0} value = Deserialize(deserializer);
1103    if (deserializer.get_buffer_offset() < input.Count) {{
1104         throw new Serde.DeserializationException("Some input bytes were not read");
1105    }}
1106    return value;
1107}}"#,
1108            name,
1109            encoding.name().to_camel_case()
1110        )
1111    }
1112
1113    fn output_container(&mut self, name: &str, format: &ContainerFormat) -> Result<()> {
1114        use ContainerFormat::*;
1115        let fields = match format {
1116            UnitStruct => Vec::new(),
1117            NewTypeStruct(format) => vec![Named {
1118                name: "value".to_string(),
1119                value: format.as_ref().clone(),
1120            }],
1121            TupleStruct(formats) => formats
1122                .iter()
1123                .enumerate()
1124                .map(|(i, f)| Named {
1125                    name: format!("field{}", i),
1126                    value: f.clone(),
1127                })
1128                .collect::<Vec<_>>(),
1129            Struct(fields) => fields.clone(),
1130            Enum(variants) => {
1131                if variants
1132                    .iter()
1133                    .all(|(_i, v)| v.value == VariantFormat::Unit)
1134                    && self.cstyle_enum_names.contains(&name.into())
1135                {
1136                    self.output_cstyle_enum(name, variants)?;
1137                } else {
1138                    self.output_enum_container(name, variants)?;
1139                }
1140                return Ok(());
1141            }
1142        };
1143        self.output_struct_or_variant_container(None, None, name, &fields)
1144    }
1145}
1146
1147/// Installer for generated source files in C#.
1148pub struct Installer {
1149    install_dir: PathBuf,
1150}
1151
1152impl Installer {
1153    pub fn new(install_dir: PathBuf) -> Self {
1154        Installer { install_dir }
1155    }
1156
1157    fn install_runtime(
1158        &self,
1159        source_dir: include_dir::Dir,
1160        path: &str,
1161    ) -> std::result::Result<(), Box<dyn std::error::Error>> {
1162        let dir_path = self.install_dir.join(path);
1163        std::fs::create_dir_all(&dir_path)?;
1164        for entry in source_dir.files() {
1165            let mut file = std::fs::File::create(dir_path.join(entry.path()))?;
1166            file.write_all(entry.contents())?;
1167        }
1168        Ok(())
1169    }
1170}
1171
1172impl crate::SourceInstaller for Installer {
1173    type Error = Box<dyn std::error::Error>;
1174
1175    fn install_module(
1176        &self,
1177        config: &CodeGeneratorConfig,
1178        registry: &Registry,
1179    ) -> std::result::Result<(), Self::Error> {
1180        let name = config.module_name.clone();
1181        let generator = CodeGenerator::new(config);
1182        let dir_path = generator.write_source_files(self.install_dir.clone(), registry)?;
1183
1184        if !config.package_manifest {
1185            return Ok(());
1186        }
1187
1188        let back_path: String = "..\\"
1189            .to_string()
1190            .repeat(dir_path.strip_prefix(&self.install_dir)?.iter().count());
1191        let mut deps = vec!["Serde".to_string()];
1192        for encoding in &config.encodings {
1193            deps.push(encoding.name().to_camel_case());
1194        }
1195        let mut dependencies = String::new();
1196        for dep in deps {
1197            writeln!(
1198                &mut dependencies,
1199                "        <ProjectReference Include=\"{1}{0}\\{0}.csproj\" />",
1200                dep, back_path
1201            )?;
1202        }
1203        let mut proj = std::fs::File::create(dir_path.join(name + ".csproj"))?;
1204        write!(
1205            proj,
1206            r#"
1207<Project Sdk="Microsoft.NET.Sdk">
1208    <PropertyGroup>
1209        <TargetFramework>netstandard2.0</TargetFramework>
1210        <LangVersion>7.2</LangVersion>
1211    </PropertyGroup>
1212    <ItemGroup>
1213        <PackageReference Include="System.Memory" Version="4.5.4" />
1214        <PackageReference Include="System.ValueTuple" Version="4.5.0" />
1215    </ItemGroup>
1216    <ItemGroup>
1217{}    
1218    </ItemGroup>
1219</Project>
1220"#,
1221            dependencies
1222        )?;
1223
1224        Ok(())
1225    }
1226
1227    fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
1228        self.install_runtime(include_directory!("runtime/csharp/Serde"), "Serde")
1229    }
1230
1231    fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
1232        self.install_runtime(include_directory!("runtime/csharp/Bincode"), "Bincode")
1233    }
1234
1235    fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
1236        self.install_runtime(include_directory!("runtime/csharp/Bcs"), "Bcs")
1237    }
1238}