1use 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
19pub struct CodeGenerator<'a> {
21 config: &'a CodeGeneratorConfig,
23 external_qualified_names: HashMap<String, String>,
26}
27
28struct CSharpEmitter<'a, T> {
30 out: IndentedWriter<T>,
32 generator: &'a CodeGenerator<'a>,
34 current_namespace: Vec<String>,
36 current_reserved_names: HashMap<String, usize>,
41 cstyle_enum_names: Vec<String>,
44}
45
46impl<'a> CodeGenerator<'a> {
47 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 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 ¤t_namespace {
79 dir_path = dir_path.join(part);
80 }
81 std::fs::create_dir_all(&dir_path)?;
82
83 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 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 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 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 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 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 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 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 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 if variant_base.is_none() {
862 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 self.output_custom_code()?;
877
878 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 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 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 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 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
1147pub 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}