1use crate::{
5 common,
6 indent::{IndentConfig, IndentedWriter},
7 CodeGeneratorConfig, Encoding,
8};
9use heck::{CamelCase, MixedCase, SnakeCase};
10use include_dir::include_dir as include_directory;
11use serde_reflection::{ContainerFormat, Format, FormatHolder, Named, Registry, VariantFormat};
12use std::{
13 collections::{BTreeMap, HashMap},
14 io::{Result, Write},
15 path::{Path, PathBuf},
16};
17
18pub struct CodeGenerator<'a> {
20 config: &'a CodeGeneratorConfig,
22}
23
24struct DartEmitter<'a, T> {
26 out: IndentedWriter<T>,
28 generator: &'a CodeGenerator<'a>,
30 current_namespace: Vec<String>,
32 registry: &'a Registry,
34}
35
36impl<'a> CodeGenerator<'a> {
37 pub fn new(config: &'a CodeGeneratorConfig) -> Self {
39 let mut external_qualified_names = HashMap::new();
40 for (namespace, names) in &config.external_definitions {
41 for name in names {
42 external_qualified_names
43 .insert(name.to_string(), format!("{}.{}", namespace, name));
44 }
45 }
46 Self { config }
47 }
48
49 pub fn output(&self, install_dir: std::path::PathBuf, registry: &Registry) -> Result<()> {
51 let current_namespace = self
52 .config
53 .module_name
54 .split('.')
55 .map(String::from)
56 .collect::<Vec<_>>();
57
58 let mut dir_path = install_dir;
59 std::fs::create_dir_all(&dir_path)?;
60 dir_path = dir_path.join("lib").join("src");
61 for part in ¤t_namespace {
62 dir_path = dir_path.join(part);
63 }
64 std::fs::create_dir_all(&dir_path)?;
65
66 for (name, format) in registry {
67 self.write_container_class(
68 &dir_path,
69 current_namespace.clone(),
70 name,
71 format,
72 registry,
73 )?;
74 }
75 self.write_helper_class(&dir_path, current_namespace.clone(), registry)?;
76 self.write_library(&dir_path, current_namespace, registry)?;
77 Ok(())
78 }
79
80 fn write_library(
81 &self,
82 install_dir: &Path,
83 current_namespace: Vec<String>,
84 registry: &Registry,
85 ) -> Result<()> {
86 let mut file =
87 std::fs::File::create(install_dir.join(self.config.module_name.clone() + ".dart"))?;
88 let mut emitter = DartEmitter {
89 out: IndentedWriter::new(&mut file, IndentConfig::Space(2)),
90 generator: self,
91 current_namespace,
92 registry,
93 };
94
95 writeln!(
96 &mut emitter.out,
97 r#"// ignore_for_file: unused_import
98library {}_types;
99
100import 'dart:typed_data';
101import 'package:meta/meta.dart';
102import 'package:tuple/tuple.dart';
103import '../serde/serde.dart';"#,
104 self.config.module_name,
105 )?;
106
107 for encoding in &self.config.encodings {
108 writeln!(
109 &mut emitter.out,
110 "import '../{0}/{0}.dart';",
111 encoding.name()
112 )?;
113 }
114
115 if let Some(files) = &self.config.external_definitions.get("import") {
116 for file in *files {
117 writeln!(&mut emitter.out, "import '{0}';", file)?;
118 }
119 }
120
121 writeln!(&mut emitter.out, "\nexport '../serde/serde.dart';")?;
122
123 writeln!(&mut emitter.out, "\npart 'trait_helpers.dart';")?;
124 for name in registry.keys() {
125 writeln!(&mut emitter.out, "part '{}.dart';", name.to_snake_case())?;
126 }
127
128 Ok(())
129 }
130
131 fn write_container_class(
132 &self,
133 dir_path: &std::path::Path,
134 current_namespace: Vec<String>,
135 name: &str,
136 format: &ContainerFormat,
137 registry: &Registry,
138 ) -> Result<()> {
139 let mut file =
140 std::fs::File::create(dir_path.join(name.to_string().to_snake_case() + ".dart"))?;
141 let mut emitter = DartEmitter {
142 out: IndentedWriter::new(&mut file, IndentConfig::Space(2)),
143 generator: self,
144 current_namespace,
145 registry,
146 };
147
148 emitter.output_preamble()?;
149 emitter.output_container(name, format)
150 }
151
152 fn write_helper_class(
153 &self,
154 dir_path: &std::path::Path,
155 current_namespace: Vec<String>,
156 registry: &Registry,
157 ) -> Result<()> {
158 let mut file = std::fs::File::create(dir_path.join("trait_helpers.dart"))?;
159 let mut emitter = DartEmitter {
160 out: IndentedWriter::new(&mut file, IndentConfig::Space(2)),
161 generator: self,
162 current_namespace,
163 registry,
164 };
165
166 emitter.output_preamble()?;
167 emitter.output_trait_helpers(registry)
168 }
169}
170
171impl<'a, T> DartEmitter<'a, T>
172where
173 T: Write,
174{
175 fn output_preamble(&mut self) -> Result<()> {
176 writeln!(
177 self.out,
178 "// ignore_for_file: type=lint, type=warning\npart of '{}.dart';",
179 self.generator.config.module_name
180 )?;
181
182 Ok(())
183 }
184
185 fn get_field_container_type(&self, name: &str) -> Option<&ContainerFormat> {
186 match self.registry.get(name) {
187 Some(container) => Some(container),
188 None => None,
189 }
190 }
191
192 fn get_class(&self, name: &str) -> String {
195 if self.generator.config.c_style_enums {
196 use ContainerFormat::Enum;
197 match self.get_field_container_type(name) {
198 Some(Enum(variants))
201 if variants.values().all(|f| f.value == VariantFormat::Unit) =>
202 {
203 format!("{}Extension", name)
204 }
205 _ => name.to_string(),
206 }
207 } else {
208 name.to_string()
209 }
210 }
211
212 fn quote_qualified_name(&self, name: &str) -> String {
213 match name {
214 "List" => "List_".to_string(),
215 "Map" => "Map_".to_string(),
216 name => name.to_string(),
217 }
218 }
219
220 fn quote_field(&self, name: &str) -> String {
221 match name {
222 "hashCode" => "hashCode_".to_string(),
223 "runtimeType" => "runtimeType_".to_string(),
224 name => name.to_string(),
225 }
226 }
227
228 fn quote_type(&self, format: &Format) -> String {
229 use Format::*;
230 match format {
231 TypeName(x) => self.quote_qualified_name(x),
232 Unit => "Unit".into(),
233 Bool => "bool".into(),
234 I8 => "int".into(),
235 I16 => "int".into(),
236 I32 => "int".into(),
237 I64 => "int".into(),
238 I128 => "Int128".into(),
239 U8 => "int".into(),
240 U16 => "int".into(),
241 U32 => "int".into(),
242 U64 => "Uint64".into(),
243 U128 => "Uint128".into(),
244 F32 => "double".into(),
245 F64 => "double".into(),
246 Char => "int".into(),
247 Str => "String".into(),
248 Bytes => "Bytes".into(),
249
250 Option(format) => format!("{}?", self.quote_type(format)),
251 Seq(format) => format!("List<{}>", self.quote_type(format)),
252 Map { key, value } => {
253 format!("Map<{}, {}>", self.quote_type(key), self.quote_type(value))
254 }
255 Tuple(formats) => format!("Tuple{}<{}>", formats.len(), self.quote_types(formats)),
256 TupleArray { content, size: _ } => format!("List<{}>", self.quote_type(content)),
257 Variable(_) => panic!("unexpected value"),
258 }
259 }
260
261 fn quote_types(&self, formats: &[Format]) -> String {
262 formats
263 .iter()
264 .map(|f| self.quote_type(f))
265 .collect::<Vec<_>>()
266 .join(", ")
267 }
268
269 fn quote_serialize_value(&self, value: &str, format: &Format) -> String {
270 use Format::*;
271 match format {
272 TypeName(_) => format!("{}.serialize(serializer);", value),
273 Unit => format!("serializer.serializeUnit({});", value),
274 Bool => format!("serializer.serializeBool({});", value),
275 I8 => format!("serializer.serializeInt8({});", value),
276 I16 => format!("serializer.serializeInt16({});", value),
277 I32 => format!("serializer.serializeInt32({});", value),
278 I64 => format!("serializer.serializeInt64({});", value),
279 I128 => format!("serializer.serializeInt128({});", value),
280 U8 => format!("serializer.serializeUint8({});", value),
281 U16 => format!("serializer.serializeUint16({});", value),
282 U32 => format!("serializer.serializeUint32({});", value),
283 U64 => format!("serializer.serializeUint64({});", value),
284 U128 => format!("serializer.serializeUint128({});", value),
285 F32 => format!("serializer.serializeFloat32({});", value),
286 F64 => format!("serializer.serializeFloat64({});", value),
287 Char => format!("serializer.serializeChar({});", value),
288 Str => format!("serializer.serializeString({});", value),
289 Bytes => format!("serializer.serializeBytes({});", value),
290 _ => format!(
291 "{}.serialize{}({}, serializer);",
292 self.quote_qualified_name("TraitHelpers"),
293 common::mangle_type(format).to_camel_case(),
294 value
295 ),
296 }
297 }
298
299 fn quote_deserialize(&self, format: &Format) -> String {
300 use Format::*;
301 match format {
302 TypeName(name) => {
303 format!(
304 "{}.deserialize(deserializer)",
305 self.quote_qualified_name(&self.get_class(name))
306 )
307 }
308 Unit => "deserializer.deserializeUnit()".to_string(),
309 Bool => "deserializer.deserializeBool()".to_string(),
310 I8 => "deserializer.deserializeInt8()".to_string(),
311 I16 => "deserializer.deserializeInt16()".to_string(),
312 I32 => "deserializer.deserializeInt32()".to_string(),
313 I64 => "deserializer.deserializeInt64()".to_string(),
314 I128 => "deserializer.deserializeInt128()".to_string(),
315 U8 => "deserializer.deserializeUint8()".to_string(),
316 U16 => "deserializer.deserializeUint16()".to_string(),
317 U32 => "deserializer.deserializeUint32()".to_string(),
318 U64 => "deserializer.deserializeUint64()".to_string(),
319 U128 => "deserializer.deserializeUint128()".to_string(),
320 F32 => "deserializer.deserializeFloat32()".to_string(),
321 F64 => "deserializer.deserializeFloat64()".to_string(),
322 Char => "deserializer.deserializeChar()".to_string(),
323 Str => "deserializer.deserializeString()".to_string(),
324 Bytes => "deserializer.deserializeBytes()".to_string(),
325 _ => format!(
326 "{}.deserialize{}(deserializer)",
327 self.quote_qualified_name("TraitHelpers"),
328 common::mangle_type(format).to_camel_case(),
329 ),
330 }
331 }
332
333 fn enter_class(&mut self, name: &str) {
334 self.out.indent();
335 self.current_namespace.push(name.to_string());
336 }
337
338 fn leave_class(&mut self) {
339 self.out.unindent();
340 self.current_namespace.pop();
341 }
342
343 fn output_trait_helpers(&mut self, registry: &Registry) -> Result<()> {
344 let mut subtypes = BTreeMap::new();
345 for format in registry.values() {
346 format
347 .visit(&mut |f| {
348 if Self::needs_helper(f) {
349 subtypes.insert(common::mangle_type(f), f.clone());
350 }
351 Ok(())
352 })
353 .unwrap();
354 }
355 writeln!(self.out, "class TraitHelpers {{")?;
356 self.enter_class("TraitHelpers");
357 for (mangled_name, subtype) in &subtypes {
358 self.output_serialization_helper(mangled_name, subtype)?;
359 self.output_deserialization_helper(mangled_name, subtype)?;
360 }
361 self.leave_class();
362 writeln!(self.out, "}}\n")
363 }
364
365 fn needs_helper(format: &Format) -> bool {
366 use Format::*;
367 matches!(
368 format,
369 Option(_) | Seq(_) | Map { .. } | Tuple(_) | TupleArray { .. }
370 )
371 }
372
373 fn output_serialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
374 use Format::*;
375
376 write!(
377 self.out,
378 "static void serialize{}({} value, BinarySerializer serializer) {{",
379 name.to_camel_case(),
380 self.quote_type(format0)
381 )?;
382 self.out.indent();
383 match format0 {
384 Option(format) => {
385 write!(
386 self.out,
387 r#"
388if (value == null) {{
389 serializer.serializeOptionTag(false);
390}} else {{
391 serializer.serializeOptionTag(true);
392 {}
393}}
394"#,
395 self.quote_serialize_value("value", format)
396 )?;
397 }
398
399 Seq(format) => {
400 write!(
401 self.out,
402 r#"
403serializer.serializeLength(value.length);
404for (final item in value) {{
405 {}
406}}
407"#,
408 self.quote_serialize_value("item", format)
409 )?;
410 }
411
412 Map { key, value } => {
413 write!(
414 self.out,
415 r#"
416serializer.serializeLength(value.length);
417final offsets = List<int>.filled(value.length, 0);
418var count = 0;
419value.entries.forEach((entry) {{
420 offsets[count++] = serializer.offset;
421 {}
422 {}
423}});
424"#,
425 self.quote_serialize_value("entry.key", key),
426 self.quote_serialize_value("entry.value", value)
427 )?;
428 }
429
430 Tuple(formats) => {
431 writeln!(self.out)?;
432 for (index, format) in formats.iter().enumerate() {
433 let expr = format!("value.item{}", index + 1);
434 writeln!(self.out, "{}", self.quote_serialize_value(&expr, format))?;
435 }
436 }
437
438 TupleArray { content, size } => {
439 write!(
440 self.out,
441 r#"
442assert (value.length == {});
443for (final item in value) {{
444 {}
445}}
446"#,
447 size,
448 self.quote_serialize_value("item", content),
449 )?;
450 }
451
452 _ => panic!("unexpected case"),
453 }
454 self.out.unindent();
455 writeln!(self.out, "}}\n")
456 }
457
458 fn output_deserialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
459 use Format::*;
460
461 write!(
462 self.out,
463 "static {} deserialize{}(BinaryDeserializer deserializer) {{",
464 self.quote_type(format0),
465 name.to_camel_case(),
466 )?;
467 self.out.indent();
468 match format0 {
469 Option(format) => {
470 write!(
471 self.out,
472 r#"
473final tag = deserializer.deserializeOptionTag();
474if (tag) {{
475 return {};
476}} else {{
477 return null;
478}}
479"#,
480 self.quote_deserialize(format),
481 )?;
482 }
483
484 Seq(format) => {
485 write!(
486 self.out,
487 r#"
488final length = deserializer.deserializeLength();
489return List.generate(length, (_) => {0});
490"#,
491 self.quote_deserialize(format)
492 )?;
493 }
494
495 Map { key, value } => {
496 write!(
497 self.out,
498 r#"
499final length = deserializer.deserializeLength();
500final obj = <{0}, {1}>{{}};
501var previousKeyStart = 0;
502var previousKeyEnd = 0;
503for (var i = 0; i < length; i++) {{
504 final keyStart = deserializer.offset;
505 {0} key = {2};
506 final keyEnd = deserializer.offset;
507 if (i > 0) {{
508 deserializer.checkThatKeySlicesAreIncreasing(
509 Slice(previousKeyStart, previousKeyEnd),
510 Slice(keyStart, keyEnd),
511 );
512 }}
513 previousKeyStart = keyStart;
514 previousKeyEnd = keyEnd;
515 {1} value = {3};
516 obj.putIfAbsent(key, () => value);
517}}
518return obj;
519"#,
520 self.quote_type(key),
521 self.quote_type(value),
522 self.quote_deserialize(key),
523 self.quote_deserialize(value),
524 )?;
525 }
526
527 Tuple(formats) => {
528 write!(
529 self.out,
530 r#"
531return {}({}
532);
533"#,
534 self.quote_type(format0),
535 formats
536 .iter()
537 .map(|f| format!("\n {}", self.quote_deserialize(f)))
538 .collect::<Vec<_>>()
539 .join(",")
540 )?;
541 }
542
543 TupleArray { content, size } => {
544 write!(
545 self.out,
546 r#"
547final obj = List<{0}>.filled({1}, 0);
548for (var i = 0; i < {1}; i++) {{
549 obj[i] = {2};
550}}
551return obj;
552"#,
553 self.quote_type(content),
554 size,
555 self.quote_deserialize(content)
556 )?;
557 }
558
559 _ => panic!("unexpected case"),
560 }
561 self.out.unindent();
562 writeln!(self.out, "}}\n")
563 }
564
565 fn output_container(&mut self, name: &str, format: &ContainerFormat) -> Result<()> {
566 use ContainerFormat::*;
567 let fields = match format {
568 UnitStruct => Vec::new(),
569 NewTypeStruct(format) => {
570 vec![Named {
571 name: "value".to_string(),
572 value: format.as_ref().clone(),
573 }]
574 }
575 TupleStruct(formats) => formats
576 .iter()
577 .enumerate()
578 .map(|(i, f)| Named {
579 name: format!("field{}", i),
580 value: f.clone(),
581 })
582 .collect::<Vec<_>>(),
583 Struct(fields) => fields.clone(),
584 Enum(variants) => {
585 if self.generator.config.c_style_enums
587 && variants.values().all(|f| f.value == VariantFormat::Unit)
588 {
589 self.output_enum_container(name, variants)?;
590 } else {
591 self.output_enum_class_container(name, variants)?;
592 }
593 return Ok(());
594 }
595 };
596 self.output_struct_or_variant_container(None, None, name, &fields)
597 }
598
599 fn output_struct_or_variant_container(
600 &mut self,
601 variant_base: Option<&str>,
602 variant_index: Option<u32>,
603 name: &str,
604 fields: &[Named<Format>],
605 ) -> Result<()> {
606 let field_count = fields.len();
607
608 writeln!(self.out)?;
610 self.output_comment(name)?;
611 if let Some(base) = variant_base {
612 writeln!(
613 self.out,
614 "@immutable\nclass {} extends {} {{",
615 self.quote_qualified_name(name),
616 base
617 )?;
618 } else {
619 writeln!(
620 self.out,
621 "@immutable\nclass {} {{",
622 self.quote_qualified_name(name)
623 )?;
624 }
625 self.enter_class(name);
626
627 writeln!(
629 self.out,
630 "const {}({}",
631 self.quote_qualified_name(name),
632 if !fields.is_empty() { "{" } else { "" }
633 )?;
634 self.out.indent();
635 for field in fields.iter() {
636 let field_name = self.quote_field(&field.name.to_mixed_case());
637 match &field.value {
638 Format::Option(_) => writeln!(self.out, "this.{},", field_name)?,
639 _ => writeln!(self.out, "required this.{},", field_name)?,
640 }
641 }
642 self.out.unindent();
643 if variant_base.is_some() {
644 writeln!(
645 self.out,
646 "{}) : super();",
647 if !fields.is_empty() { "}" } else { "" }
648 )?;
649 } else {
650 writeln!(self.out, "{});", if !fields.is_empty() { "}" } else { "" })?;
651 }
652
653 if self.generator.config.serialization {
654 if variant_index.is_none() {
656 writeln!(
657 self.out,
658 "\nstatic {} deserialize(BinaryDeserializer deserializer) {{",
659 self.quote_qualified_name(name)
660 )?;
661 } else {
662 writeln!(
663 self.out,
664 "\nstatic {} load(BinaryDeserializer deserializer) {{",
665 self.quote_qualified_name(name)
666 )?;
667 }
668
669 self.out.indent();
670 writeln!(self.out, "deserializer.increaseContainerDepth();")?;
671 writeln!(
672 self.out,
673 "final instance = {}(",
674 self.quote_qualified_name(name)
675 )?;
676 self.out.indent();
677 for field in fields {
678 writeln!(
679 self.out,
680 "{}: {},",
681 self.quote_field(&field.name.to_mixed_case()),
682 self.quote_deserialize(&field.value)
683 )?;
684 }
685 self.out.unindent();
686 writeln!(self.out, ");")?;
687 writeln!(self.out, "deserializer.decreaseContainerDepth();")?;
688 writeln!(self.out, "return instance;")?;
689 self.out.unindent();
690 writeln!(self.out, "}}")?;
691
692 if variant_index.is_none() {
693 for encoding in &self.generator.config.encodings {
694 self.output_class_deserialize_for_encoding(name, *encoding)?;
695 }
696 }
697 }
698
699 if !fields.is_empty() {
701 writeln!(self.out)?;
702 }
703 for field in fields {
704 writeln!(
705 self.out,
706 "final {} {};",
707 self.quote_type(&field.value),
708 self.quote_field(&field.name.to_mixed_case())
709 )?;
710 }
711 if !fields.is_empty() {
712 writeln!(self.out)?;
713
714 let cls_name = self.quote_qualified_name(name);
715 writeln!(self.out, "{} copyWith({{", cls_name)?;
716 self.out.indent();
717 for field in fields {
718 let field_name = self.quote_field(&field.name.to_mixed_case());
719 let field_type = self.quote_type(&field.value);
720
721 match field.value {
722 Format::Option(_) => {
723 writeln!(self.out, "{} Function()? {},", field_type, field_name)?
724 }
725 _ => writeln!(self.out, "{}? {},", field_type, field_name)?,
726 }
727 }
728 self.out.unindent();
729 writeln!(self.out, "}}) {{")?;
730 self.out.indent();
731 writeln!(self.out, "return {}(", cls_name)?;
732 self.out.indent();
733
734 for field in fields {
735 let field_name = self.quote_field(&field.name.to_mixed_case());
736
737 match field.value {
738 Format::Option(_) => {
739 writeln!(self.out, "{0}: {0} == null ? this.{0} : {0}(),", field_name)?
740 }
741 _ => writeln!(self.out, "{0}: {0} ?? this.{0},", field_name)?,
742 }
743 }
744 self.out.unindent();
745 writeln!(self.out, ");")?;
746 self.out.unindent();
747 writeln!(self.out, "}}")?;
748 }
749
750 if self.generator.config.serialization {
752 writeln!(self.out, "\nvoid serialize(BinarySerializer serializer) {{",)?;
753 self.out.indent();
754 writeln!(self.out, "serializer.increaseContainerDepth();")?;
755 if let Some(index) = variant_index {
756 writeln!(self.out, "serializer.serializeVariantIndex({});", index)?;
757 }
758 for field in fields {
759 writeln!(
760 self.out,
761 "{}",
762 self.quote_serialize_value(
763 &self.quote_field(&field.name.to_mixed_case()),
764 &field.value
765 )
766 )?;
767 }
768 writeln!(self.out, "serializer.decreaseContainerDepth();")?;
769 self.out.unindent();
770 writeln!(self.out, "}}")?;
771
772 if variant_index.is_none() {
773 for encoding in &self.generator.config.encodings {
774 self.output_class_serialize_for_encoding(*encoding)?;
775 }
776 }
777 }
778
779 write!(self.out, "\n@override")?;
781 write!(self.out, "\nbool operator ==(Object other) {{")?;
782 self.out.indent();
783
784 writeln!(self.out, "\nif (identical(this, other)) return true;")?;
785 writeln!(
786 self.out,
787 "if (other.runtimeType != runtimeType) return false;"
788 )?;
789 write!(self.out, "\nreturn other is {}", name)?;
790
791 self.out.indent();
792 for field in fields.iter() {
793 let value = if let Format::Option(value) = &field.value {
796 value
797 } else {
798 &field.value
799 };
800
801 let stmt = match value {
802 Format::Seq(_) => {
803 format!(
804 "listEquals({0}, other.{0})",
805 self.quote_field(&field.name.to_mixed_case())
806 )
807 }
808 Format::TupleArray {
809 content: _,
810 size: _,
811 } => format!(
812 "listEquals({0}, other.{0})",
813 self.quote_field(&field.name.to_mixed_case())
814 ),
815 Format::Map { .. } => {
816 format!(
817 "mapEquals({0}, other.{0})",
818 self.quote_field(&field.name.to_mixed_case())
819 )
820 }
821 _ => format!(
822 "{0} == other.{0}",
823 self.quote_field(&field.name.to_mixed_case())
824 ),
825 };
826
827 write!(self.out, "\n&& {}", stmt)?;
828 }
829 writeln!(self.out, ";")?;
830 self.out.unindent();
831
832 self.out.unindent();
833 writeln!(self.out, "}}")?;
834
835 write!(self.out, "\n@override")?;
837 if field_count == 0 {
838 writeln!(self.out, "\nint get hashCode => runtimeType.hashCode;")?;
839 } else if field_count == 1 {
840 writeln!(
841 self.out,
842 "\nint get hashCode => {}.hashCode;",
843 fields.first().unwrap().name.to_mixed_case()
844 )?;
845 } else {
846 let use_hash_all = field_count > 20;
847
848 if use_hash_all {
849 writeln!(self.out, "\nint get hashCode => Object.hashAll([")?;
850 } else {
851 writeln!(self.out, "\nint get hashCode => Object.hash(")?;
852 }
853
854 self.out.indent();
855 self.out.indent();
856 self.out.indent();
857
858 for field in fields {
859 writeln!(
860 self.out,
861 "{},",
862 self.quote_field(&field.name.to_mixed_case())
863 )?;
864 }
865
866 self.out.unindent();
867
868 if use_hash_all {
869 writeln!(self.out, "]);")?;
870 } else {
871 writeln!(self.out, ");")?;
872 }
873
874 self.out.unindent();
875 self.out.unindent();
876 }
877
878 writeln!(self.out, "\n@override\nString toString() {{")?;
880 self.out.indent();
881 writeln!(self.out, "String? fullString;")?;
882 writeln!(self.out, "\nassert(() {{")?;
883 self.out.indent();
884 writeln!(self.out, "fullString = '$runtimeType('")?;
885 self.out.indent();
886 for (index, field) in fields.iter().enumerate() {
887 if index == field_count - 1 {
888 writeln!(
889 self.out,
890 "'{0}: ${0}'",
891 self.quote_field(&field.name.to_mixed_case())
892 )?;
893 } else {
894 writeln!(
895 self.out,
896 "'{0}: ${0}, '",
897 self.quote_field(&field.name.to_mixed_case())
898 )?;
899 }
900 }
901 writeln!(self.out, "')';")?;
902 self.out.unindent();
903 writeln!(self.out, "return true;")?;
904 self.out.unindent();
905 writeln!(self.out, "}}());")?;
906 writeln!(self.out, "\nreturn fullString ?? '{}';", name)?;
907 self.out.unindent();
908 writeln!(self.out, "}}")?;
909
910 self.out.unindent();
911 self.leave_class();
913 writeln!(self.out, "}}")
914 }
915
916 fn output_class_serialize_for_encoding(&mut self, encoding: Encoding) -> Result<()> {
917 writeln!(
918 self.out,
919 r#"
920Uint8List {0}Serialize() {{
921 final serializer = {1}Serializer();
922 serialize(serializer);
923 return serializer.bytes;
924}}"#,
925 encoding.name(),
926 encoding.name().to_camel_case(),
927 )
928 }
929
930 fn output_class_deserialize_for_encoding(
931 &mut self,
932 name: &str,
933 encoding: Encoding,
934 ) -> Result<()> {
935 writeln!(
936 self.out,
937 r#"
938static {klass} {encoding}Deserialize(Uint8List input) {{
939 final deserializer = {encoding_class}Deserializer(input);
940 final value = {static_class}.deserialize(deserializer);
941 if (deserializer.offset < input.length) {{
942 throw Exception('Some input bytes were not read');
943 }}
944 return value;
945}}"#,
946 klass = self.quote_qualified_name(name),
947 static_class = self.quote_qualified_name(&self.get_class(name)),
948 encoding = encoding.name(),
949 encoding_class = encoding.name().to_camel_case()
950 )
951 }
952
953 fn output_enum_container(
954 &mut self,
955 name: &str,
956 variants: &BTreeMap<u32, Named<VariantFormat>>,
957 ) -> Result<()> {
958 writeln!(self.out)?;
959 self.output_comment(name)?;
960 writeln!(self.out, "enum {} {{", self.quote_qualified_name(name))?;
961 self.enter_class(name);
962
963 for variant in variants.values() {
964 writeln!(
965 self.out,
966 "{},",
967 self.quote_field(&variant.name.to_mixed_case())
968 )?;
969 }
970
971 self.out.unindent();
972 writeln!(self.out, "}}\n")?;
973
974 if self.generator.config.serialization {
975 writeln!(
976 self.out,
977 "extension {name}Extension on {n} {{",
978 name = name,
979 n = self.quote_qualified_name(name)
980 )?;
981 self.out.indent();
982 write!(
983 self.out,
984 "static {} deserialize(BinaryDeserializer deserializer) {{",
985 self.quote_qualified_name(name)
986 )?;
987 self.out.indent();
988 writeln!(
989 self.out,
990 r#"
991final index = deserializer.deserializeVariantIndex();
992switch (index) {{"#,
993 )?;
994 self.out.indent();
995 for (index, variant) in variants {
996 writeln!(
997 self.out,
998 "case {}: return {}.{};",
999 index,
1000 self.quote_qualified_name(name),
1001 self.quote_field(&variant.name.to_mixed_case()),
1002 )?;
1003 }
1004 writeln!(
1005 self.out,
1006 "default: throw Exception('Unknown variant index for {}: ' + index.toString());",
1007 self.quote_qualified_name(name),
1008 )?;
1009 self.out.unindent();
1010 writeln!(self.out, "}}")?;
1011 self.out.unindent();
1012 writeln!(self.out, "}}\n")?;
1013
1014 write!(self.out, "void serialize(BinarySerializer serializer) {{")?;
1015
1016 self.out.indent();
1017 writeln!(
1018 self.out,
1019 r#"
1020switch (this) {{"#,
1021 )?;
1022 self.out.indent();
1023 for (index, variant) in variants {
1024 writeln!(
1025 self.out,
1026 "case {}.{}: return serializer.serializeVariantIndex({});",
1027 self.quote_qualified_name(name),
1028 self.quote_field(&variant.name.to_mixed_case()),
1029 index,
1030 )?;
1031 }
1032 self.out.unindent();
1033 writeln!(self.out, "}}")?;
1034 self.out.unindent();
1035 writeln!(self.out, "}}")?;
1036
1037 for encoding in &self.generator.config.encodings {
1038 self.output_class_serialize_for_encoding(*encoding)?;
1039 self.output_class_deserialize_for_encoding(name, *encoding)?;
1040 }
1041 }
1042 self.out.unindent();
1043 self.out.unindent();
1044
1045 writeln!(self.out, "}}\n")?;
1046
1047 self.leave_class();
1048 Ok(())
1049 }
1050
1051 fn output_enum_class_container(
1052 &mut self,
1053 name: &str,
1054 variants: &BTreeMap<u32, Named<VariantFormat>>,
1055 ) -> Result<()> {
1056 writeln!(self.out)?;
1057 self.output_comment(name)?;
1058 writeln!(
1059 self.out,
1060 "abstract class {} {{",
1061 self.quote_qualified_name(name)
1062 )?;
1063 self.enter_class(name);
1064 writeln!(self.out, "const {}();", self.quote_qualified_name(name))?;
1065
1066 if self.generator.config.serialization {
1067 writeln!(self.out, "\nvoid serialize(BinarySerializer serializer);")?;
1068 write!(
1069 self.out,
1070 "\nstatic {} deserialize(BinaryDeserializer deserializer) {{",
1071 self.quote_qualified_name(name)
1072 )?;
1073 self.out.indent();
1074 writeln!(
1075 self.out,
1076 r#"
1077int index = deserializer.deserializeVariantIndex();
1078switch (index) {{"#,
1079 )?;
1080 self.out.indent();
1081 for (index, variant) in variants {
1082 writeln!(
1083 self.out,
1084 "case {}: return {}{}.load(deserializer);",
1085 index,
1086 self.quote_qualified_name(name).to_camel_case(),
1087 self.quote_field(&variant.name),
1088 )?;
1089 }
1090 writeln!(
1091 self.out,
1092 "default: throw Exception('Unknown variant index for {}: ' + index.toString());",
1093 self.quote_qualified_name(name),
1094 )?;
1095 self.out.unindent();
1096 writeln!(self.out, "}}")?;
1097 self.out.unindent();
1098 writeln!(self.out, "}}")?;
1099
1100 for encoding in &self.generator.config.encodings {
1101 self.output_class_serialize_for_encoding(*encoding)?;
1102 self.output_class_deserialize_for_encoding(name, *encoding)?;
1103 }
1104 }
1105 self.out.unindent();
1106 self.out.unindent();
1107
1108 writeln!(self.out, "}}\n")?;
1109
1110 self.output_variants(name, variants)?;
1111 self.leave_class();
1112 Ok(())
1113 }
1114
1115 fn output_variants(
1116 &mut self,
1117 base: &str,
1118 variants: &BTreeMap<u32, Named<VariantFormat>>,
1119 ) -> Result<()> {
1120 for (index, variant) in variants {
1121 self.output_variant(
1122 base,
1123 *index,
1124 &format!("{}{}", base, &variant.name),
1125 &variant.value,
1126 )?;
1127 }
1128 Ok(())
1129 }
1130
1131 fn output_variant(
1132 &mut self,
1133 base: &str,
1134 index: u32,
1135 name: &str,
1136 variant: &VariantFormat,
1137 ) -> Result<()> {
1138 use VariantFormat::*;
1139 let fields = match variant {
1140 Unit => Vec::new(),
1141 NewType(format) => vec![Named {
1142 name: "value".to_string(),
1143 value: format.as_ref().clone(),
1144 }],
1145 Tuple(formats) => formats
1146 .iter()
1147 .enumerate()
1148 .map(|(i, f)| Named {
1149 name: format!("field{}", i),
1150 value: f.clone(),
1151 })
1152 .collect(),
1153 Struct(fields) => fields.clone(),
1154 Variable(_) => panic!("incorrect value"),
1155 };
1156 self.output_struct_or_variant_container(
1157 Some(&self.quote_qualified_name(base)),
1158 Some(index),
1159 name,
1160 &fields,
1161 )
1162 }
1163
1164 fn output_comment(&mut self, name: &str) -> std::io::Result<()> {
1165 let mut path = self.current_namespace.clone();
1166 path.push(name.to_string());
1167 if let Some(doc) = self.generator.config.comments.get(&path) {
1168 let text = textwrap::indent(doc, "/// ").replace("\n\n", "\n///\n");
1169 write!(self.out, "{}", text)?;
1170 }
1171 Ok(())
1172 }
1173}
1174
1175pub struct Installer {
1177 install_dir: PathBuf,
1178}
1179
1180impl Installer {
1181 pub fn new(install_dir: PathBuf) -> Self {
1182 Installer { install_dir }
1183 }
1184
1185 fn install_runtime(
1186 &self,
1187 source_dir: include_dir::Dir,
1188 path: &str,
1189 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
1190 let dir_path = self.install_dir.join(path);
1191 std::fs::create_dir_all(&dir_path)?;
1192 for entry in source_dir.files() {
1193 let mut file = std::fs::File::create(dir_path.join(entry.path()))?;
1194 file.write_all(entry.contents())?;
1195 }
1196 Ok(())
1197 }
1198
1199 fn write_package(&self, install_dir: &Path, module_name: &str) -> Result<()> {
1200 let mut file = std::fs::File::create(install_dir.join("pubspec.yaml"))?;
1201 let mut out = IndentedWriter::new(&mut file, IndentConfig::Space(2));
1202 writeln!(
1203 &mut out,
1204 r#"name: {}
1205
1206environment:
1207 sdk: '>=3.0.0 <4.0.0'
1208
1209dependencies:
1210 meta: ^1.0.0
1211 tuple: ^2.0.0
1212"#,
1213 module_name
1214 )?;
1215 Ok(())
1216 }
1217}
1218
1219impl crate::SourceInstaller for Installer {
1220 type Error = Box<dyn std::error::Error>;
1221
1222 fn install_module(
1223 &self,
1224 config: &CodeGeneratorConfig,
1225 registry: &Registry,
1226 ) -> std::result::Result<(), Self::Error> {
1227 let generator = CodeGenerator::new(config);
1228 generator.output(self.install_dir.clone(), registry)?;
1229
1230 if config.package_manifest {
1232 self.write_package(&self.install_dir, &config.module_name)?;
1233 }
1234
1235 std::fs::write(
1237 self.install_dir
1238 .join("lib")
1239 .join(format!("{}.dart", &config.module_name)),
1240 format!(
1241 "export 'src/{name}/{name}.dart';",
1242 name = &config.module_name
1243 ),
1244 )?;
1245
1246 Ok(())
1247 }
1248
1249 fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
1250 self.install_runtime(include_directory!("runtime/dart/serde"), "lib/src/serde")
1251 }
1252
1253 fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
1254 self.install_runtime(
1255 include_directory!("runtime/dart/bincode"),
1256 "lib/src/bincode",
1257 )
1258 }
1259
1260 fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
1261 self.install_runtime(include_directory!("runtime/dart/bcs"), "lib/src/bcs")
1262 }
1263}