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 io::{Result, Write},
15 path::PathBuf,
16};
17
18pub struct CodeGenerator<'a> {
20 config: &'a CodeGeneratorConfig,
22 external_qualified_names: HashMap<String, String>,
25}
26
27struct JavaEmitter<'a, T> {
29 out: IndentedWriter<T>,
31 generator: &'a CodeGenerator<'a>,
33 current_namespace: Vec<String>,
35 current_reserved_names: HashMap<String, usize>,
40}
41
42impl<'a> CodeGenerator<'a> {
43 pub fn new(config: &'a CodeGeneratorConfig) -> Self {
45 if config.enums.c_style {
46 panic!("Java does not support generating c-style enums");
47 }
48 let mut external_qualified_names = HashMap::new();
49 for (namespace, names) in &config.external_definitions {
50 for name in names {
51 external_qualified_names.insert(name.to_string(), format!("{namespace}.{name}"));
52 }
53 }
54 Self {
55 config,
56 external_qualified_names,
57 }
58 }
59
60 pub fn write_source_files(
64 &self,
65 install_dir: std::path::PathBuf,
66 registry: &Registry,
67 ) -> Result<()> {
68 let current_namespace = self
69 .config
70 .module_name
71 .split('.')
72 .map(String::from)
73 .collect::<Vec<_>>();
74
75 let mut dir_path = install_dir;
76 for part in ¤t_namespace {
77 dir_path = dir_path.join(part);
78 }
79 std::fs::create_dir_all(&dir_path)?;
80
81 for (name, format) in registry {
82 self.write_container_class(&dir_path, current_namespace.clone(), name, format)?;
83 }
84 if self.config.serialization {
85 self.write_helper_class(&dir_path, current_namespace, registry)?;
86 }
87 Ok(())
88 }
89
90 fn write_container_class(
91 &self,
92 dir_path: &std::path::Path,
93 current_namespace: Vec<String>,
94 name: &str,
95 format: &ContainerFormat,
96 ) -> Result<()> {
97 let mut file = std::fs::File::create(dir_path.join(name.to_string() + ".java"))?;
98 let mut emitter = JavaEmitter {
99 out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
100 generator: self,
101 current_namespace,
102 current_reserved_names: HashMap::new(),
103 };
104
105 emitter.output_preamble()?;
106 emitter.output_container(name, format)
107 }
108
109 fn write_helper_class(
110 &self,
111 dir_path: &std::path::Path,
112 current_namespace: Vec<String>,
113 registry: &Registry,
114 ) -> Result<()> {
115 let mut file = std::fs::File::create(dir_path.join("TraitHelpers.java"))?;
116 let mut emitter = JavaEmitter {
117 out: IndentedWriter::new(&mut file, IndentConfig::Space(4)),
118 generator: self,
119 current_namespace,
120 current_reserved_names: HashMap::new(),
121 };
122
123 emitter.output_preamble()?;
124 emitter.output_trait_helpers(registry)
125 }
126}
127
128impl<'a, T> JavaEmitter<'a, T>
129where
130 T: Write,
131{
132 fn output_preamble(&mut self) -> Result<()> {
133 writeln!(self.out, "package {};\n", self.generator.config.module_name)?;
134 Ok(())
135 }
136
137 fn quote_qualified_name(&self, name: &str) -> String {
142 let qname = self
143 .generator
144 .external_qualified_names
145 .get(name)
146 .cloned()
147 .unwrap_or_else(|| format!("{}.{}", self.generator.config.module_name, name));
148 let mut path = qname.split('.').collect::<Vec<_>>();
149 if path.len() <= 1 {
150 return qname;
151 }
152 let name = path.pop().unwrap();
153 if self.current_reserved_names.contains_key(name) {
154 return qname;
155 }
156 for (index, element) in path.iter().enumerate() {
157 match self.current_namespace.get(index) {
158 Some(e) if e == element => (),
159 _ => {
160 return qname;
161 }
162 }
163 }
164 name.to_string()
165 }
166
167 fn output_comment(&mut self, name: &str) -> std::io::Result<()> {
168 let mut path = self.current_namespace.clone();
169 path.push(name.to_string());
170 if let Some(doc) = self.generator.config.comments.get(&path) {
171 let text = textwrap::indent(doc, " * ").replace("\n\n", "\n *\n");
172 writeln!(self.out, "/**\n{text} */")?;
173 }
174 Ok(())
175 }
176
177 fn output_custom_code(&mut self) -> std::io::Result<()> {
178 if let Some(code) = self
179 .generator
180 .config
181 .custom_code
182 .get(&self.current_namespace)
183 {
184 writeln!(self.out, "\n{code}")?;
185 }
186 Ok(())
187 }
188
189 fn quote_type(&self, format: &Format) -> String {
190 use Format::*;
191 match format {
192 TypeName(x) => self.quote_qualified_name(x),
193 Unit => "com.novi.serde.Unit".into(),
194 Bool => "Boolean".into(),
195 I8 => "Byte".into(),
196 I16 => "Short".into(),
197 I32 => "Integer".into(),
198 I64 => "Long".into(),
199 I128 => "java.math.@com.novi.serde.Int128 BigInteger".into(),
200 U8 => "@com.novi.serde.Unsigned Byte".into(),
201 U16 => "@com.novi.serde.Unsigned Short".into(),
202 U32 => "@com.novi.serde.Unsigned Integer".into(),
203 U64 => "@com.novi.serde.Unsigned Long".into(),
204 U128 => "java.math.@com.novi.serde.Unsigned @com.novi.serde.Int128 BigInteger".into(),
205 F32 => "Float".into(),
206 F64 => "Double".into(),
207 Char => "Character".into(),
208 Str => "String".into(),
209 Bytes => "com.novi.serde.Bytes".into(),
210
211 Option(format) => format!("java.util.Optional<{}>", self.quote_type(format)),
212 Seq(format) => format!("java.util.List<{}>", self.quote_type(format)),
213 Map { key, value } => format!(
214 "java.util.Map<{}, {}>",
215 self.quote_type(key),
216 self.quote_type(value)
217 ),
218 Tuple(formats) => format!(
219 "com.novi.serde.Tuple{}<{}>",
220 formats.len(),
221 self.quote_types(formats)
222 ),
223 TupleArray { content, size } => format!(
224 "java.util.@com.novi.serde.ArrayLen(length={}) List<{}>",
225 size,
226 self.quote_type(content)
227 ),
228 Variable(_) => panic!("unexpected value"),
229 }
230 }
231
232 fn enter_class(&mut self, name: &str, reserved_subclass_names: &[&str]) {
233 self.out.indent();
234 self.current_namespace.push(name.to_string());
235 for name in reserved_subclass_names {
236 let entry = self
237 .current_reserved_names
238 .entry(name.to_string())
239 .or_insert(0);
240 *entry += 1;
241 }
242 }
243
244 fn leave_class(&mut self, reserved_subclass_names: &[&str]) {
245 self.out.unindent();
246 self.current_namespace.pop();
247 for name in reserved_subclass_names {
248 let entry = self.current_reserved_names.get_mut(*name).unwrap();
249 *entry -= 1;
250 if *entry == 0 {
251 self.current_reserved_names.remove(*name);
252 }
253 }
254 }
255
256 fn quote_types(&self, formats: &[Format]) -> String {
257 formats
258 .iter()
259 .map(|f| self.quote_type(f))
260 .collect::<Vec<_>>()
261 .join(", ")
262 }
263
264 fn output_trait_helpers(&mut self, registry: &Registry) -> Result<()> {
265 let mut subtypes = BTreeMap::new();
266 for format in registry.values() {
267 format
268 .visit(&mut |f| {
269 if Self::needs_helper(f) {
270 subtypes.insert(common::mangle_type(f), f.clone());
271 }
272 Ok(())
273 })
274 .unwrap();
275 }
276 writeln!(self.out, "final class TraitHelpers {{")?;
277 let reserved_names = &[];
278 self.enter_class("TraitHelpers", reserved_names);
279 for (mangled_name, subtype) in &subtypes {
280 self.output_serialization_helper(mangled_name, subtype)?;
281 self.output_deserialization_helper(mangled_name, subtype)?;
282 }
283 self.leave_class(reserved_names);
284 writeln!(self.out, "}}\n")
285 }
286
287 fn needs_helper(format: &Format) -> bool {
288 use Format::*;
289 matches!(
290 format,
291 Option(_) | Seq(_) | Map { .. } | Tuple(_) | TupleArray { .. }
292 )
293 }
294
295 fn quote_serialize_value(&self, value: &str, format: &Format) -> String {
296 use Format::*;
297 match format {
298 TypeName(_) => format!("{value}.serialize(serializer);"),
299 Unit => format!("serializer.serialize_unit({value});"),
300 Bool => format!("serializer.serialize_bool({value});"),
301 I8 => format!("serializer.serialize_i8({value});"),
302 I16 => format!("serializer.serialize_i16({value});"),
303 I32 => format!("serializer.serialize_i32({value});"),
304 I64 => format!("serializer.serialize_i64({value});"),
305 I128 => format!("serializer.serialize_i128({value});"),
306 U8 => format!("serializer.serialize_u8({value});"),
307 U16 => format!("serializer.serialize_u16({value});"),
308 U32 => format!("serializer.serialize_u32({value});"),
309 U64 => format!("serializer.serialize_u64({value});"),
310 U128 => format!("serializer.serialize_u128({value});"),
311 F32 => format!("serializer.serialize_f32({value});"),
312 F64 => format!("serializer.serialize_f64({value});"),
313 Char => format!("serializer.serialize_char({value});"),
314 Str => format!("serializer.serialize_str({value});"),
315 Bytes => format!("serializer.serialize_bytes({value});"),
316 _ => format!(
317 "{}.serialize_{}({}, serializer);",
318 self.quote_qualified_name("TraitHelpers"),
319 common::mangle_type(format),
320 value
321 ),
322 }
323 }
324
325 fn quote_deserialize(&self, format: &Format) -> String {
326 use Format::*;
327 match format {
328 TypeName(name) => format!(
329 "{}.deserialize(deserializer)",
330 self.quote_qualified_name(name)
331 ),
332 Unit => "deserializer.deserialize_unit()".to_string(),
333 Bool => "deserializer.deserialize_bool()".to_string(),
334 I8 => "deserializer.deserialize_i8()".to_string(),
335 I16 => "deserializer.deserialize_i16()".to_string(),
336 I32 => "deserializer.deserialize_i32()".to_string(),
337 I64 => "deserializer.deserialize_i64()".to_string(),
338 I128 => "deserializer.deserialize_i128()".to_string(),
339 U8 => "deserializer.deserialize_u8()".to_string(),
340 U16 => "deserializer.deserialize_u16()".to_string(),
341 U32 => "deserializer.deserialize_u32()".to_string(),
342 U64 => "deserializer.deserialize_u64()".to_string(),
343 U128 => "deserializer.deserialize_u128()".to_string(),
344 F32 => "deserializer.deserialize_f32()".to_string(),
345 F64 => "deserializer.deserialize_f64()".to_string(),
346 Char => "deserializer.deserialize_char()".to_string(),
347 Str => "deserializer.deserialize_str()".to_string(),
348 Bytes => "deserializer.deserialize_bytes()".to_string(),
349 _ => format!(
350 "{}.deserialize_{}(deserializer)",
351 self.quote_qualified_name("TraitHelpers"),
352 common::mangle_type(format),
353 ),
354 }
355 }
356
357 fn output_serialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
358 use Format::*;
359
360 write!(
361 self.out,
362 "static void serialize_{}({} value, com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError {{",
363 name,
364 self.quote_type(format0)
365 )?;
366 self.out.indent();
367 match format0 {
368 Option(format) => {
369 write!(
370 self.out,
371 r#"
372if (value.isPresent()) {{
373 serializer.serialize_option_tag(true);
374 {}
375}} else {{
376 serializer.serialize_option_tag(false);
377}}
378"#,
379 self.quote_serialize_value("value.get()", format)
380 )?;
381 }
382
383 Seq(format) => {
384 write!(
385 self.out,
386 r#"
387serializer.serialize_len(value.size());
388for ({} item : value) {{
389 {}
390}}
391"#,
392 self.quote_type(format),
393 self.quote_serialize_value("item", format)
394 )?;
395 }
396
397 Map { key, value } => {
398 write!(
399 self.out,
400 r#"
401serializer.serialize_len(value.size());
402int[] offsets = new int[value.size()];
403int count = 0;
404for (java.util.Map.Entry<{}, {}> entry : value.entrySet()) {{
405 offsets[count++] = serializer.get_buffer_offset();
406 {}
407 {}
408}}
409serializer.sort_map_entries(offsets);
410"#,
411 self.quote_type(key),
412 self.quote_type(value),
413 self.quote_serialize_value("entry.getKey()", key),
414 self.quote_serialize_value("entry.getValue()", value)
415 )?;
416 }
417
418 Tuple(formats) => {
419 writeln!(self.out)?;
420 for (index, format) in formats.iter().enumerate() {
421 let expr = format!("value.field{index}");
422 writeln!(self.out, "{}", self.quote_serialize_value(&expr, format))?;
423 }
424 }
425
426 TupleArray { content, size } => {
427 write!(
428 self.out,
429 r#"
430if (value.size() != {0}) {{
431 throw new java.lang.IllegalArgumentException("Invalid length for fixed-size array: " + value.size() + " instead of "+ {0});
432}}
433for ({1} item : value) {{
434 {2}
435}}
436"#,
437 size,
438 self.quote_type(content),
439 self.quote_serialize_value("item", content),
440 )?;
441 }
442
443 _ => panic!("unexpected case"),
444 }
445 self.out.unindent();
446 writeln!(self.out, "}}\n")
447 }
448
449 fn output_deserialization_helper(&mut self, name: &str, format0: &Format) -> Result<()> {
450 use Format::*;
451
452 write!(
453 self.out,
454 "static {} deserialize_{}(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
455 self.quote_type(format0),
456 name,
457 )?;
458 self.out.indent();
459 match format0 {
460 Option(format) => {
461 write!(
462 self.out,
463 r#"
464boolean tag = deserializer.deserialize_option_tag();
465if (!tag) {{
466 return java.util.Optional.empty();
467}} else {{
468 return java.util.Optional.of({});
469}}
470"#,
471 self.quote_deserialize(format),
472 )?;
473 }
474
475 Seq(format) => {
476 write!(
477 self.out,
478 r#"
479long length = deserializer.deserialize_len();
480java.util.List<{0}> obj = new java.util.ArrayList<{0}>((int) length);
481for (long i = 0; i < length; i++) {{
482 obj.add({1});
483}}
484return obj;
485"#,
486 self.quote_type(format),
487 self.quote_deserialize(format)
488 )?;
489 }
490
491 Map { key, value } => {
492 write!(
493 self.out,
494 r#"
495long length = deserializer.deserialize_len();
496java.util.Map<{0}, {1}> obj = new java.util.HashMap<{0}, {1}>();
497int previous_key_start = 0;
498int previous_key_end = 0;
499for (long i = 0; i < length; i++) {{
500 int key_start = deserializer.get_buffer_offset();
501 {0} key = {2};
502 int key_end = deserializer.get_buffer_offset();
503 if (i > 0) {{
504 deserializer.check_that_key_slices_are_increasing(
505 new com.novi.serde.Slice(previous_key_start, previous_key_end),
506 new com.novi.serde.Slice(key_start, key_end));
507 }}
508 previous_key_start = key_start;
509 previous_key_end = key_end;
510 {1} value = {3};
511 obj.put(key, value);
512}}
513return obj;
514"#,
515 self.quote_type(key),
516 self.quote_type(value),
517 self.quote_deserialize(key),
518 self.quote_deserialize(value),
519 )?;
520 }
521
522 Tuple(formats) => {
523 write!(
524 self.out,
525 r#"
526return new {}({}
527);
528"#,
529 self.quote_type(format0),
530 formats
531 .iter()
532 .map(|f| format!("\n {}", self.quote_deserialize(f)))
533 .collect::<Vec<_>>()
534 .join(",")
535 )?;
536 }
537
538 TupleArray { content, size } => {
539 write!(
540 self.out,
541 r#"
542java.util.List<{0}> obj = new java.util.ArrayList<{0}>({1});
543for (long i = 0; i < {1}; i++) {{
544 obj.add({2});
545}}
546return obj;
547"#,
548 self.quote_type(content),
549 size,
550 self.quote_deserialize(content)
551 )?;
552 }
553
554 _ => panic!("unexpected case"),
555 }
556 self.out.unindent();
557 writeln!(self.out, "}}\n")
558 }
559
560 fn output_variant(
561 &mut self,
562 base: &str,
563 index: u32,
564 name: &str,
565 variant: &VariantFormat,
566 ) -> Result<()> {
567 use VariantFormat::*;
568 let fields = match variant {
569 Unit => Vec::new(),
570 NewType(format) => vec![Named {
571 name: "value".to_string(),
572 value: format.as_ref().clone(),
573 }],
574 Tuple(formats) => formats
575 .iter()
576 .enumerate()
577 .map(|(i, f)| Named {
578 name: format!("field{i}"),
579 value: f.clone(),
580 })
581 .collect(),
582 Struct(fields) => fields.clone(),
583 Variable(_) => panic!("incorrect value"),
584 };
585 self.output_struct_or_variant_container(Some(base), Some(index), name, &fields)
586 }
587
588 fn output_variants(
589 &mut self,
590 base: &str,
591 variants: &BTreeMap<u32, Named<VariantFormat>>,
592 ) -> Result<()> {
593 for (index, variant) in variants {
594 self.output_variant(base, *index, &variant.name, &variant.value)?;
595 }
596 Ok(())
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 writeln!(self.out)?;
608 if let Some(base) = variant_base {
609 self.output_comment(name)?;
610 writeln!(
611 self.out,
612 "public static final class {name} extends {base} {{"
613 )?;
614 } else {
615 self.output_comment(name)?;
616 writeln!(self.out, "public final class {name} {{")?;
617 }
618 let reserved_names = &["Builder"];
619 self.enter_class(name, reserved_names);
620 for field in fields {
622 self.output_comment(&field.name)?;
623 writeln!(
624 self.out,
625 "public final {} {};",
626 self.quote_type(&field.value),
627 field.name
628 )?;
629 }
630 if !fields.is_empty() {
631 writeln!(self.out)?;
632 }
633 writeln!(
635 self.out,
636 "public {}({}) {{",
637 name,
638 fields
639 .iter()
640 .map(|f| format!("{} {}", self.quote_type(&f.value), &f.name))
641 .collect::<Vec<_>>()
642 .join(", ")
643 )?;
644 self.out.indent();
645 for field in fields {
646 writeln!(
647 self.out,
648 "java.util.Objects.requireNonNull({0}, \"{0} must not be null\");",
649 &field.name
650 )?;
651 }
652 for field in fields {
653 writeln!(self.out, "this.{} = {};", &field.name, &field.name)?;
654 }
655 self.out.unindent();
656 writeln!(self.out, "}}")?;
657 if self.generator.config.serialization {
659 writeln!(
660 self.out,
661 "\npublic void serialize(com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError {{",
662 )?;
663 self.out.indent();
664 writeln!(self.out, "serializer.increase_container_depth();")?;
665 if let Some(index) = variant_index {
666 writeln!(self.out, "serializer.serialize_variant_index({index});")?;
667 }
668 for field in fields {
669 writeln!(
670 self.out,
671 "{}",
672 self.quote_serialize_value(&field.name, &field.value)
673 )?;
674 }
675 writeln!(self.out, "serializer.decrease_container_depth();")?;
676 self.out.unindent();
677 writeln!(self.out, "}}")?;
678
679 if variant_index.is_none() {
680 for encoding in &self.generator.config.encodings {
681 self.output_class_serialize_for_encoding(*encoding)?;
682 }
683 }
684 }
685 if self.generator.config.serialization {
687 if variant_index.is_none() {
688 writeln!(
689 self.out,
690 "\npublic static {name} deserialize(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
691 )?;
692 } else {
693 writeln!(
694 self.out,
695 "\nstatic {name} load(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{",
696 )?;
697 }
698 self.out.indent();
699 writeln!(self.out, "deserializer.increase_container_depth();")?;
700 writeln!(self.out, "Builder builder = new Builder();")?;
701 for field in fields {
702 writeln!(
703 self.out,
704 "builder.{} = {};",
705 field.name,
706 self.quote_deserialize(&field.value)
707 )?;
708 }
709 writeln!(self.out, "deserializer.decrease_container_depth();")?;
710 writeln!(self.out, "return builder.build();")?;
711 self.out.unindent();
712 writeln!(self.out, "}}")?;
713
714 if variant_index.is_none() {
715 for encoding in &self.generator.config.encodings {
716 self.output_class_deserialize_for_encoding(name, *encoding)?;
717 }
718 }
719 }
720 write!(self.out, "\npublic boolean equals(Object obj) {{")?;
722 self.out.indent();
723 writeln!(
724 self.out,
725 r#"
726if (this == obj) return true;
727if (obj == null) return false;
728if (getClass() != obj.getClass()) return false;
729{name} other = ({name}) obj;"#,
730 )?;
731 for field in fields {
732 writeln!(
733 self.out,
734 "if (!java.util.Objects.equals(this.{0}, other.{0})) {{ return false; }}",
735 &field.name,
736 )?;
737 }
738 writeln!(self.out, "return true;")?;
739 self.out.unindent();
740 writeln!(self.out, "}}")?;
741 writeln!(self.out, "\npublic int hashCode() {{")?;
743 self.out.indent();
744 writeln!(self.out, "int value = 7;",)?;
745 for field in fields {
746 writeln!(
747 self.out,
748 "value = 31 * value + (this.{0} != null ? this.{0}.hashCode() : 0);",
749 &field.name
750 )?;
751 }
752 writeln!(self.out, "return value;")?;
753 self.out.unindent();
754 writeln!(self.out, "}}")?;
755 self.output_struct_or_variant_container_builder(name, fields)?;
757 self.output_custom_code()?;
759 self.leave_class(reserved_names);
761 writeln!(self.out, "}}")
762 }
763
764 fn output_struct_or_variant_container_builder(
765 &mut self,
766 name: &str,
767 fields: &[Named<Format>],
768 ) -> Result<()> {
769 writeln!(self.out)?;
771 writeln!(self.out, "public static final class Builder {{")?;
772 let reserved_names = &[];
773 self.enter_class("Builder", reserved_names);
774 for field in fields {
776 writeln!(
777 self.out,
778 "public {} {};",
779 self.quote_type(&field.value),
780 field.name
781 )?;
782 }
783 if !fields.is_empty() {
784 writeln!(self.out)?;
785 }
786 writeln!(
788 self.out,
789 r#"public {0} build() {{
790 return new {0}({1}
791 );
792}}"#,
793 name,
794 fields
795 .iter()
796 .map(|f| format!("\n {}", f.name))
797 .collect::<Vec<_>>()
798 .join(",")
799 )?;
800 self.output_custom_code()?;
802 self.leave_class(reserved_names);
804 writeln!(self.out, "}}")
805 }
806
807 fn output_enum_container(
808 &mut self,
809 name: &str,
810 variants: &BTreeMap<u32, Named<VariantFormat>>,
811 ) -> Result<()> {
812 writeln!(self.out)?;
813 self.output_comment(name)?;
814 writeln!(self.out, "public abstract class {name} {{")?;
815 let reserved_names = variants
816 .values()
817 .map(|v| v.name.as_str())
818 .collect::<Vec<_>>();
819 self.enter_class(name, &reserved_names);
820 if self.generator.config.serialization {
821 writeln!(
822 self.out,
823 "\nabstract public void serialize(com.novi.serde.Serializer serializer) throws com.novi.serde.SerializationError;"
824 )?;
825 write!(
826 self.out,
827 "\npublic static {name} deserialize(com.novi.serde.Deserializer deserializer) throws com.novi.serde.DeserializationError {{"
828 )?;
829 self.out.indent();
830 writeln!(
831 self.out,
832 r#"
833int index = deserializer.deserialize_variant_index();
834switch (index) {{"#,
835 )?;
836 self.out.indent();
837 for (index, variant) in variants {
838 writeln!(
839 self.out,
840 "case {}: return {}.load(deserializer);",
841 index, variant.name,
842 )?;
843 }
844 writeln!(
845 self.out,
846 "default: throw new com.novi.serde.DeserializationError(\"Unknown variant index for {name}: \" + index);",
847 )?;
848 self.out.unindent();
849 writeln!(self.out, "}}")?;
850 self.out.unindent();
851 writeln!(self.out, "}}")?;
852
853 for encoding in &self.generator.config.encodings {
854 self.output_class_serialize_for_encoding(*encoding)?;
855 self.output_class_deserialize_for_encoding(name, *encoding)?;
856 }
857 }
858
859 self.output_variants(name, variants)?;
860 self.leave_class(&reserved_names);
861 writeln!(self.out, "}}\n")
862 }
863
864 fn output_class_serialize_for_encoding(&mut self, encoding: Encoding) -> Result<()> {
865 writeln!(
866 self.out,
867 r#"
868public byte[] {0}Serialize() throws com.novi.serde.SerializationError {{
869 com.novi.serde.Serializer serializer = new com.novi.{0}.{1}Serializer();
870 serialize(serializer);
871 return serializer.get_bytes();
872}}"#,
873 encoding.name(),
874 encoding.name().to_camel_case()
875 )
876 }
877
878 fn output_class_deserialize_for_encoding(
879 &mut self,
880 name: &str,
881 encoding: Encoding,
882 ) -> Result<()> {
883 writeln!(
884 self.out,
885 r#"
886public static {0} {1}Deserialize(byte[] input) throws com.novi.serde.DeserializationError {{
887 if (input == null) {{
888 throw new com.novi.serde.DeserializationError("Cannot deserialize null array");
889 }}
890 com.novi.serde.Deserializer deserializer = new com.novi.{1}.{2}Deserializer(input);
891 {0} value = deserialize(deserializer);
892 if (deserializer.get_buffer_offset() < input.length) {{
893 throw new com.novi.serde.DeserializationError("Some input bytes were not read");
894 }}
895 return value;
896}}"#,
897 name,
898 encoding.name(),
899 encoding.name().to_camel_case()
900 )
901 }
902
903 fn output_container(&mut self, name: &str, format: &ContainerFormat) -> Result<()> {
904 use ContainerFormat::*;
905 let fields = match format {
906 UnitStruct => Vec::new(),
907 NewTypeStruct(format) => vec![Named {
908 name: "value".to_string(),
909 value: format.as_ref().clone(),
910 }],
911 TupleStruct(formats) => formats
912 .iter()
913 .enumerate()
914 .map(|(i, f)| Named {
915 name: format!("field{i}"),
916 value: f.clone(),
917 })
918 .collect::<Vec<_>>(),
919 Struct(fields) => fields.clone(),
920 Enum(variants) => {
921 self.output_enum_container(name, variants)?;
922 return Ok(());
923 }
924 };
925 self.output_struct_or_variant_container(None, None, name, &fields)
926 }
927}
928
929pub struct Installer {
931 install_dir: PathBuf,
932}
933
934impl Installer {
935 pub fn new(install_dir: PathBuf) -> Self {
936 Installer { install_dir }
937 }
938
939 fn install_runtime(
940 &self,
941 source_dir: include_dir::Dir,
942 path: &str,
943 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
944 let dir_path = self.install_dir.join(path);
945 std::fs::create_dir_all(&dir_path)?;
946 for entry in source_dir.files() {
947 let mut file = std::fs::File::create(dir_path.join(entry.path()))?;
948 file.write_all(entry.contents())?;
949 }
950 Ok(())
951 }
952}
953
954impl crate::SourceInstaller for Installer {
955 type Error = Box<dyn std::error::Error>;
956
957 fn install_module(
958 &self,
959 config: &CodeGeneratorConfig,
960 registry: &Registry,
961 ) -> std::result::Result<(), Self::Error> {
962 let generator = CodeGenerator::new(config);
963 generator.write_source_files(self.install_dir.clone(), registry)?;
964 Ok(())
965 }
966
967 fn install_serde_runtime(&self) -> std::result::Result<(), Self::Error> {
968 self.install_runtime(
969 include_directory!("runtime/java/com/novi/serde"),
970 "com/novi/serde",
971 )
972 }
973
974 fn install_bincode_runtime(&self) -> std::result::Result<(), Self::Error> {
975 self.install_runtime(
976 include_directory!("runtime/java/com/novi/bincode"),
977 "com/novi/bincode",
978 )
979 }
980
981 fn install_bcs_runtime(&self) -> std::result::Result<(), Self::Error> {
982 self.install_runtime(
983 include_directory!("runtime/java/com/novi/bcs"),
984 "com/novi/bcs",
985 )
986 }
987}