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