1use crate::ast::{
2 ArrayLen, ArrayLenValue, Attribute, Comment, ConstDef, ConstValue, Definition, DocString,
3 EnumDef, EnumFallback, EnumVariant, EventDef, EventFallback, FunctionDef, FunctionFallback,
4 FunctionPart, ImportStmt, InlineEnum, InlineStruct, NamedRef, NamedRefKind, NewtypeDef,
5 ServiceDef, ServiceItem, StructDef, StructFallback, StructField, TypeName, TypeNameKind,
6 TypeNameOrInline,
7};
8use crate::error::{Error, ErrorKind};
9use crate::{Parser, Schema};
10use std::io::{Error as IoError, Result as IoResult, Write};
11
12#[derive(Debug)]
13pub struct Formatter<'a> {
14 schema: &'a Schema,
15 newline: bool,
16 first: bool,
17 last_def: Option<DefinitionKind>,
18 last_item: Option<ItemKind>,
19}
20
21impl<'a> Formatter<'a> {
22 pub fn new(parser: &'a Parser) -> Result<Self, Vec<&'a Error>> {
23 fn is_fmt_error(e: &&Error) -> bool {
24 matches!(
25 e.error_kind(),
26 ErrorKind::InvalidSyntax(_) | ErrorKind::IoError(_),
27 )
28 }
29
30 let errs = parser
31 .errors()
32 .iter()
33 .filter(is_fmt_error)
34 .collect::<Vec<_>>();
35
36 if errs.is_empty() {
37 Ok(Self {
38 schema: parser.main_schema(),
39 newline: false,
40 first: true,
41 last_def: None,
42 last_item: None,
43 })
44 } else {
45 Err(errs)
46 }
47 }
48
49 pub fn to_writer(mut self, mut writer: impl Write) -> Result<(), IoError> {
50 self.schema(&mut writer, self.schema)
51 }
52
53 #[allow(clippy::inherent_to_string)]
54 pub fn to_string(self) -> String {
55 let mut buf = Vec::new();
56 self.to_writer(&mut buf).unwrap();
57 String::from_utf8(buf).unwrap()
58 }
59
60 fn schema(&mut self, writer: &mut dyn Write, schema: &Schema) -> IoResult<()> {
61 if !schema.comment().is_empty() {
62 self.newline = true;
63 Self::comment(writer, schema.comment(), 0)?;
64 }
65
66 if !schema.doc().is_empty() {
67 self.newline(writer)?;
68 Self::doc_inline(writer, schema.doc(), 0)?;
69 self.newline = true;
70 }
71
72 self.imports(writer, schema.imports())?;
73 self.definitions(writer, schema.definitions())?;
74
75 Ok(())
76 }
77
78 fn imports(&mut self, writer: &mut dyn Write, imports: &[ImportStmt]) -> IoResult<()> {
79 let mut imports = Vec::from_iter(imports);
80 imports.sort_by_key(|import| import.schema_name().value());
81
82 for import in &imports {
83 self.import(writer, import)?;
84 }
85
86 self.newline |= !imports.is_empty();
87 Ok(())
88 }
89
90 fn import(&mut self, writer: &mut dyn Write, import: &ImportStmt) -> IoResult<()> {
91 let is_multi_line = !import.comment().is_empty();
92 self.newline_with_first(writer, is_multi_line)?;
93 Self::prelude(writer, import.comment(), &[], &[], 0, false)?;
94 writeln!(writer, "import {};", import.schema_name().value())?;
95 self.newline = is_multi_line;
96 Ok(())
97 }
98
99 fn definitions(&mut self, writer: &mut dyn Write, defs: &[Definition]) -> IoResult<()> {
100 for def in defs {
101 match def {
102 Definition::Struct(struct_def) => self.struct_def(writer, struct_def)?,
103 Definition::Enum(enum_def) => self.enum_def(writer, enum_def)?,
104 Definition::Service(svc) => self.service(writer, svc)?,
105 Definition::Const(const_def) => self.const_def(writer, const_def)?,
106 Definition::Newtype(newtype) => self.newtype(writer, newtype)?,
107 }
108 }
109
110 Ok(())
111 }
112
113 fn struct_def(&mut self, writer: &mut dyn Write, struct_def: &StructDef) -> IoResult<()> {
114 let has_fields = !struct_def.fields().is_empty() || struct_def.fallback().is_some();
115
116 let is_multi_line = Self::is_multi_line_struct(
117 struct_def.comment(),
118 struct_def.doc(),
119 struct_def.attributes(),
120 struct_def.fields(),
121 struct_def.fallback(),
122 );
123
124 self.newline_def(writer, DefinitionKind::Struct, is_multi_line)?;
125
126 Self::prelude(
127 writer,
128 struct_def.comment(),
129 struct_def.doc(),
130 struct_def.attributes(),
131 0,
132 false,
133 )?;
134
135 if has_fields {
136 writeln!(writer, "struct {} {{", struct_def.name().value())?;
137 self.fields(writer, struct_def.fields(), struct_def.fallback(), 4)?;
138 writeln!(writer, "}}")?;
139 } else {
140 writeln!(writer, "struct {} {{}}", struct_def.name().value())?;
141 }
142
143 self.newline = is_multi_line;
144 Ok(())
145 }
146
147 fn inline_struct(
148 &mut self,
149 writer: &mut dyn Write,
150 struct_def: &InlineStruct,
151 indent: usize,
152 ) -> IoResult<()> {
153 let has_prelude = !struct_def.doc().is_empty() || !struct_def.attributes().is_empty();
154
155 let is_multi_line = Self::is_multi_line_struct(
156 &[],
157 struct_def.doc(),
158 struct_def.attributes(),
159 struct_def.fields(),
160 struct_def.fallback(),
161 );
162
163 if is_multi_line {
164 writeln!(writer, "struct {{")?;
165
166 if has_prelude {
167 Self::prelude(
168 writer,
169 &[],
170 struct_def.doc(),
171 struct_def.attributes(),
172 indent + 4,
173 true,
174 )?;
175 }
176
177 self.newline = has_prelude;
178
179 self.fields(
180 writer,
181 struct_def.fields(),
182 struct_def.fallback(),
183 indent + 4,
184 )?;
185
186 Self::indent(writer, indent)?;
187 writeln!(writer, "}}")?;
188 } else {
189 writeln!(writer, "struct {{}}")?;
190 }
191
192 Ok(())
193 }
194
195 fn is_multi_line_struct(
196 comment: &[Comment],
197 doc: &[DocString],
198 attrs: &[Attribute],
199 fields: &[StructField],
200 fallback: Option<&StructFallback>,
201 ) -> bool {
202 !comment.is_empty()
203 || !doc.is_empty()
204 || !attrs.is_empty()
205 || !fields.is_empty()
206 || fallback.is_some()
207 }
208
209 fn fields(
210 &mut self,
211 writer: &mut dyn Write,
212 fields: &[StructField],
213 fallback: Option<&StructFallback>,
214 indent: usize,
215 ) -> IoResult<()> {
216 self.first = true;
217
218 for field in fields {
219 self.field(writer, field, indent)?;
220 }
221
222 if let Some(fallback) = fallback {
223 self.fallback_field(writer, fallback, indent)?;
224 }
225
226 Ok(())
227 }
228
229 fn field(
230 &mut self,
231 writer: &mut dyn Write,
232 field: &StructField,
233 indent: usize,
234 ) -> IoResult<()> {
235 let is_multi_line = !field.comment().is_empty() || !field.doc().is_empty();
236 self.newline_with_first(writer, is_multi_line)?;
237
238 Self::prelude(writer, field.comment(), field.doc(), &[], indent, false)?;
239 Self::indent(writer, indent)?;
240
241 if field.required() {
242 write!(writer, "required ")?;
243 }
244
245 write!(
246 writer,
247 "{} @ {} = ",
248 field.name().value(),
249 field.id().value(),
250 )?;
251
252 Self::type_name(writer, field.field_type())?;
253 writeln!(writer, ";")?;
254
255 self.newline = is_multi_line;
256 Ok(())
257 }
258
259 fn fallback_field(
260 &mut self,
261 writer: &mut dyn Write,
262 fallback: &StructFallback,
263 indent: usize,
264 ) -> IoResult<()> {
265 let is_multi_line = !fallback.comment().is_empty() || !fallback.doc().is_empty();
266 self.newline_with_first(writer, is_multi_line)?;
267
268 Self::prelude(
269 writer,
270 fallback.comment(),
271 fallback.doc(),
272 &[],
273 indent,
274 false,
275 )?;
276
277 Self::indent(writer, indent)?;
278 writeln!(writer, "{} = fallback;", fallback.name().value())
279 }
280
281 fn enum_def(&mut self, writer: &mut dyn Write, enum_def: &EnumDef) -> IoResult<()> {
282 let has_vars = !enum_def.variants().is_empty() || enum_def.fallback().is_some();
283
284 let is_multi_line = Self::is_multi_line_enum(
285 enum_def.comment(),
286 enum_def.doc(),
287 enum_def.attributes(),
288 enum_def.variants(),
289 enum_def.fallback(),
290 );
291
292 self.newline_def(writer, DefinitionKind::Enum, is_multi_line)?;
293
294 Self::prelude(
295 writer,
296 enum_def.comment(),
297 enum_def.doc(),
298 enum_def.attributes(),
299 0,
300 false,
301 )?;
302
303 if has_vars {
304 writeln!(writer, "enum {} {{", enum_def.name().value())?;
305 self.variants(writer, enum_def.variants(), enum_def.fallback(), 4)?;
306 writeln!(writer, "}}")?;
307 } else {
308 writeln!(writer, "enum {} {{}}", enum_def.name().value())?;
309 }
310
311 self.newline = is_multi_line;
312 Ok(())
313 }
314
315 fn inline_enum(
316 &mut self,
317 writer: &mut dyn Write,
318 enum_def: &InlineEnum,
319 indent: usize,
320 ) -> IoResult<()> {
321 let has_prelude = !enum_def.doc().is_empty() || !enum_def.attributes().is_empty();
322
323 let is_multi_line = Self::is_multi_line_enum(
324 &[],
325 enum_def.doc(),
326 enum_def.attributes(),
327 enum_def.variants(),
328 enum_def.fallback(),
329 );
330
331 if is_multi_line {
332 writeln!(writer, "enum {{")?;
333
334 if has_prelude {
335 Self::prelude(
336 writer,
337 &[],
338 enum_def.doc(),
339 enum_def.attributes(),
340 indent + 4,
341 true,
342 )?;
343 }
344
345 self.newline = has_prelude;
346 self.variants(writer, enum_def.variants(), enum_def.fallback(), indent + 4)?;
347
348 Self::indent(writer, indent)?;
349 writeln!(writer, "}}")?;
350 } else {
351 writeln!(writer, "enum {{}}")?;
352 }
353
354 Ok(())
355 }
356
357 fn is_multi_line_enum(
358 comment: &[Comment],
359 doc: &[DocString],
360 attrs: &[Attribute],
361 vars: &[EnumVariant],
362 fallback: Option<&EnumFallback>,
363 ) -> bool {
364 !comment.is_empty()
365 || !doc.is_empty()
366 || !attrs.is_empty()
367 || !vars.is_empty()
368 || fallback.is_some()
369 }
370
371 fn variants(
372 &mut self,
373 writer: &mut dyn Write,
374 vars: &[EnumVariant],
375 fallback: Option<&EnumFallback>,
376 indent: usize,
377 ) -> IoResult<()> {
378 self.first = true;
379
380 for var in vars {
381 self.variant(writer, var, indent)?;
382 }
383
384 if let Some(fallback) = fallback {
385 self.fallback_variant(writer, fallback, indent)?;
386 }
387
388 Ok(())
389 }
390
391 fn variant(
392 &mut self,
393 writer: &mut dyn Write,
394 var: &EnumVariant,
395 indent: usize,
396 ) -> IoResult<()> {
397 let is_multi_line = !var.comment().is_empty() || !var.doc().is_empty();
398
399 self.newline_with_first(writer, is_multi_line)?;
400 Self::prelude(writer, var.comment(), var.doc(), &[], indent, false)?;
401
402 Self::indent(writer, indent)?;
403 write!(writer, "{} @ {}", var.name().value(), var.id().value(),)?;
404
405 if let Some(ty) = var.variant_type() {
406 write!(writer, " = ")?;
407 Self::type_name(writer, ty)?;
408 }
409
410 writeln!(writer, ";")?;
411 self.newline = is_multi_line;
412 Ok(())
413 }
414
415 fn fallback_variant(
416 &mut self,
417 writer: &mut dyn Write,
418 fallback: &EnumFallback,
419 indent: usize,
420 ) -> IoResult<()> {
421 let is_multi_line = !fallback.comment().is_empty() || !fallback.doc().is_empty();
422 self.newline_with_first(writer, is_multi_line)?;
423
424 Self::prelude(
425 writer,
426 fallback.comment(),
427 fallback.doc(),
428 &[],
429 indent,
430 false,
431 )?;
432
433 Self::indent(writer, indent)?;
434 writeln!(writer, "{} = fallback;", fallback.name().value())
435 }
436
437 fn service(&mut self, writer: &mut dyn Write, svc: &ServiceDef) -> IoResult<()> {
438 self.newline_def(writer, DefinitionKind::Service, true)?;
439
440 Self::prelude(writer, svc.comment(), svc.doc(), &[], 0, false)?;
441 writeln!(writer, "service {} {{", svc.name().value())?;
442
443 Self::prelude(writer, svc.uuid_comment(), &[], &[], 4, false)?;
444 writeln!(writer, " uuid = {};", svc.uuid().value())?;
445
446 if !svc.uuid_comment().is_empty() || !svc.version_comment().is_empty() {
447 writeln!(writer)?;
448 }
449
450 Self::prelude(writer, svc.version_comment(), &[], &[], 4, false)?;
451 writeln!(writer, " version = {};", svc.version().value())?;
452 self.newline = true;
453
454 self.items(
455 writer,
456 svc.items(),
457 svc.function_fallback(),
458 svc.event_fallback(),
459 )?;
460
461 writeln!(writer, "}}")?;
462 self.newline = true;
463 Ok(())
464 }
465
466 fn items(
467 &mut self,
468 writer: &mut dyn Write,
469 items: &[ServiceItem],
470 fn_fallback: Option<&FunctionFallback>,
471 ev_fallback: Option<&EventFallback>,
472 ) -> IoResult<()> {
473 self.last_item = None;
474 let mut has_fns = false;
475 let mut has_evs = ev_fallback.is_some();
476
477 for item in items {
478 match item {
479 ServiceItem::Function(fn_def) => {
480 has_fns = true;
481 self.fn_def(writer, fn_def)?;
482 }
483
484 ServiceItem::Event(ev) => {
485 has_evs = true;
486 self.ev(writer, ev)?;
487 }
488 }
489 }
490
491 if let Some(fallback) = fn_fallback {
492 self.newline |= has_evs;
493 self.fn_fallback(writer, fallback)?;
494 }
495
496 if let Some(fallback) = ev_fallback {
497 self.newline |= fn_fallback
498 .map(|fallback| !fallback.comment().is_empty() || !fallback.doc().is_empty())
499 .unwrap_or(false)
500 || (fn_fallback.is_none() && has_fns);
501
502 self.ev_fallback(writer, fallback)?;
503 }
504
505 Ok(())
506 }
507
508 fn fn_def(&mut self, writer: &mut dyn Write, fn_def: &FunctionDef) -> IoResult<()> {
509 let is_multi_line = !fn_def.comment().is_empty()
510 || !fn_def.doc().is_empty()
511 || fn_def.args().is_some()
512 || fn_def.err().is_some()
513 || fn_def
514 .ok()
515 .map(|ok| {
516 !ok.comment().is_empty()
517 || Self::is_multi_line_type_name_or_inline(ok.part_type())
518 })
519 .unwrap_or(false);
520
521 self.newline_item(writer, ItemKind::Function, is_multi_line)?;
522 Self::prelude(writer, fn_def.comment(), fn_def.doc(), &[], 4, false)?;
523
524 write!(
525 writer,
526 " fn {} @ {}",
527 fn_def.name().value(),
528 fn_def.id().value(),
529 )?;
530
531 let ok_has_comment = fn_def
532 .ok()
533 .map(|ok| !ok.comment().is_empty())
534 .unwrap_or(false);
535
536 if fn_def.args().is_some() || ok_has_comment || fn_def.err().is_some() {
537 writeln!(writer, " {{")?;
538 self.newline = false;
539 self.first = true;
540
541 if let Some(args) = fn_def.args() {
542 self.fn_part(writer, args, "args")?;
543 }
544
545 if let Some(ok) = fn_def.ok() {
546 self.fn_part(writer, ok, "ok")?;
547 }
548
549 if let Some(err) = fn_def.err() {
550 self.fn_part(writer, err, "err")?;
551 }
552
553 writeln!(writer, " }}")?;
554 } else if let Some(ok) = fn_def.ok() {
555 write!(writer, " = ")?;
556 self.type_name_or_inline(writer, ok.part_type(), 4)?;
557
558 if matches!(ok.part_type(), TypeNameOrInline::TypeName(_)) {
559 writeln!(writer, ";")?;
560 }
561 } else {
562 writeln!(writer, ";")?;
563 }
564
565 self.newline = is_multi_line;
566 Ok(())
567 }
568
569 fn fn_part(&mut self, writer: &mut dyn Write, part: &FunctionPart, kind: &str) -> IoResult<()> {
570 let is_multi_line =
571 !part.comment().is_empty() || Self::is_multi_line_type_name_or_inline(part.part_type());
572
573 self.newline_with_first(writer, is_multi_line)?;
574 Self::prelude(writer, part.comment(), &[], &[], 8, false)?;
575
576 write!(writer, " {kind} = ")?;
577 self.type_name_or_inline(writer, part.part_type(), 8)?;
578
579 if matches!(part.part_type(), TypeNameOrInline::TypeName(_)) {
580 writeln!(writer, ";")?;
581 }
582
583 self.newline = is_multi_line;
584 Ok(())
585 }
586
587 fn ev(&mut self, writer: &mut dyn Write, ev: &EventDef) -> IoResult<()> {
588 let is_multi_line = !ev.comment().is_empty()
589 || !ev.doc().is_empty()
590 || ev
591 .event_type()
592 .map(Self::is_multi_line_type_name_or_inline)
593 .unwrap_or(false);
594
595 self.newline_item(writer, ItemKind::Event, is_multi_line)?;
596 Self::prelude(writer, ev.comment(), ev.doc(), &[], 4, false)?;
597
598 write!(
599 writer,
600 " event {} @ {}",
601 ev.name().value(),
602 ev.id().value(),
603 )?;
604
605 if let Some(ty) = ev.event_type() {
606 write!(writer, " = ")?;
607 self.type_name_or_inline(writer, ty, 4)?;
608
609 if matches!(ty, TypeNameOrInline::TypeName(_)) {
610 writeln!(writer, ";")?;
611 }
612 } else {
613 writeln!(writer, ";")?;
614 }
615
616 self.newline = is_multi_line;
617 Ok(())
618 }
619
620 fn fn_fallback(&mut self, writer: &mut dyn Write, fallback: &FunctionFallback) -> IoResult<()> {
621 let is_multi_line = !fallback.comment().is_empty() || !fallback.doc().is_empty();
622
623 self.newline_with_first(writer, is_multi_line)?;
624 Self::prelude(writer, fallback.comment(), fallback.doc(), &[], 4, false)?;
625
626 writeln!(writer, " fn {} = fallback;", fallback.name().value())?;
627
628 self.newline = is_multi_line;
629 Ok(())
630 }
631
632 fn ev_fallback(&mut self, writer: &mut dyn Write, fallback: &EventFallback) -> IoResult<()> {
633 let is_multi_line = !fallback.comment().is_empty() || !fallback.doc().is_empty();
634
635 self.newline_with_first(writer, is_multi_line)?;
636 Self::prelude(writer, fallback.comment(), fallback.doc(), &[], 4, false)?;
637
638 writeln!(writer, " event {} = fallback;", fallback.name().value())?;
639
640 self.newline = is_multi_line;
641 Ok(())
642 }
643
644 fn const_def(&mut self, writer: &mut dyn Write, const_def: &ConstDef) -> IoResult<()> {
645 let is_multi_line = !const_def.comment().is_empty() || !const_def.doc().is_empty();
646 self.newline_def(writer, DefinitionKind::Const, is_multi_line)?;
647
648 Self::prelude(writer, const_def.comment(), const_def.doc(), &[], 0, false)?;
649
650 let (ty, val) = match const_def.value() {
651 ConstValue::U8(val) => ("u8", val.value()),
652 ConstValue::I8(val) => ("i8", val.value()),
653 ConstValue::U16(val) => ("u16", val.value()),
654 ConstValue::I16(val) => ("i16", val.value()),
655 ConstValue::U32(val) => ("u32", val.value()),
656 ConstValue::I32(val) => ("i32", val.value()),
657 ConstValue::U64(val) => ("u64", val.value()),
658 ConstValue::I64(val) => ("i64", val.value()),
659 ConstValue::String(val) => ("string", val.value()),
660 ConstValue::Uuid(val) => ("uuid", val.value()),
661 };
662
663 writeln!(writer, "const {} = {ty}({val});", const_def.name().value())?;
664
665 self.newline = is_multi_line;
666 Ok(())
667 }
668
669 fn newtype(&mut self, writer: &mut dyn Write, newtype: &NewtypeDef) -> IoResult<()> {
670 let is_multi_line = !newtype.comment().is_empty()
671 || !newtype.doc().is_empty()
672 || !newtype.attributes().is_empty();
673
674 self.newline_def(writer, DefinitionKind::Newtype, is_multi_line)?;
675
676 Self::prelude(
677 writer,
678 newtype.comment(),
679 newtype.doc(),
680 newtype.attributes(),
681 0,
682 false,
683 )?;
684
685 write!(writer, "newtype {} = ", newtype.name().value())?;
686 Self::type_name(writer, newtype.target_type())?;
687 writeln!(writer, ";")?;
688
689 self.newline = is_multi_line;
690 Ok(())
691 }
692
693 fn prelude(
694 writer: &mut dyn Write,
695 comment: &[Comment],
696 doc: &[DocString],
697 attrs: &[Attribute],
698 indent: usize,
699 inline: bool,
700 ) -> IoResult<()> {
701 Self::comment(writer, comment, indent)?;
702
703 if inline {
704 Self::doc_inline(writer, doc, indent)?;
705 } else {
706 Self::doc(writer, doc, indent)?;
707 }
708
709 Self::attributes(writer, attrs, indent, inline)?;
710 Ok(())
711 }
712
713 fn attributes(
714 writer: &mut dyn Write,
715 attrs: &[Attribute],
716 indent: usize,
717 inline: bool,
718 ) -> IoResult<()> {
719 for attr in attrs {
720 Self::attribute(writer, attr, indent, inline)?;
721 }
722
723 Ok(())
724 }
725
726 fn attribute(
727 writer: &mut dyn Write,
728 attr: &Attribute,
729 indent: usize,
730 inline: bool,
731 ) -> IoResult<()> {
732 Self::indent(writer, indent)?;
733
734 if inline {
735 write!(writer, "#![{}", attr.name().value())?;
736 } else {
737 write!(writer, "#[{}", attr.name().value())?;
738 }
739
740 if !attr.options().is_empty() {
741 write!(writer, "(")?;
742 }
743
744 let mut first = true;
745 for opt in attr.options() {
746 if first {
747 first = false;
748 } else {
749 write!(writer, ", ")?;
750 }
751
752 write!(writer, "{}", opt.value())?;
753 }
754
755 if !attr.options().is_empty() {
756 write!(writer, ")")?;
757 }
758
759 writeln!(writer, "]")?;
760 Ok(())
761 }
762
763 fn type_name(writer: &mut dyn Write, ty: &TypeName) -> IoResult<()> {
764 match ty.kind() {
765 TypeNameKind::Bool => write!(writer, "bool")?,
766 TypeNameKind::U8 => write!(writer, "u8")?,
767 TypeNameKind::I8 => write!(writer, "i8")?,
768 TypeNameKind::U16 => write!(writer, "u16")?,
769 TypeNameKind::I16 => write!(writer, "i16")?,
770 TypeNameKind::U32 => write!(writer, "u32")?,
771 TypeNameKind::I32 => write!(writer, "i32")?,
772 TypeNameKind::U64 => write!(writer, "u64")?,
773 TypeNameKind::I64 => write!(writer, "i64")?,
774 TypeNameKind::F32 => write!(writer, "f32")?,
775 TypeNameKind::F64 => write!(writer, "f64")?,
776 TypeNameKind::String => write!(writer, "string")?,
777 TypeNameKind::Uuid => write!(writer, "uuid")?,
778 TypeNameKind::ObjectId => write!(writer, "object_id")?,
779 TypeNameKind::ServiceId => write!(writer, "service_id")?,
780 TypeNameKind::Value => write!(writer, "value")?,
781
782 TypeNameKind::Option(ty) => {
783 write!(writer, "option<")?;
784 Self::type_name(writer, ty)?;
785 write!(writer, ">")?;
786 }
787
788 TypeNameKind::Box(ty) => {
789 write!(writer, "box<")?;
790 Self::type_name(writer, ty)?;
791 write!(writer, ">")?;
792 }
793
794 TypeNameKind::Vec(ty) => {
795 write!(writer, "vec<")?;
796 Self::type_name(writer, ty)?;
797 write!(writer, ">")?;
798 }
799
800 TypeNameKind::Bytes => write!(writer, "bytes")?,
801
802 TypeNameKind::Map(k, v) => {
803 write!(writer, "map<")?;
804 Self::type_name(writer, k)?;
805 write!(writer, " -> ")?;
806 Self::type_name(writer, v)?;
807 write!(writer, ">")?;
808 }
809
810 TypeNameKind::Set(ty) => {
811 write!(writer, "set<")?;
812 Self::type_name(writer, ty)?;
813 write!(writer, ">")?;
814 }
815
816 TypeNameKind::Sender(ty) => {
817 write!(writer, "sender<")?;
818 Self::type_name(writer, ty)?;
819 write!(writer, ">")?;
820 }
821
822 TypeNameKind::Receiver(ty) => {
823 write!(writer, "receiver<")?;
824 Self::type_name(writer, ty)?;
825 write!(writer, ">")?;
826 }
827
828 TypeNameKind::Lifetime => write!(writer, "lifetime")?,
829 TypeNameKind::Unit => write!(writer, "unit")?,
830
831 TypeNameKind::Result(ok, err) => {
832 write!(writer, "result<")?;
833 Self::type_name(writer, ok)?;
834 write!(writer, ", ")?;
835 Self::type_name(writer, err)?;
836 write!(writer, ">")?;
837 }
838
839 TypeNameKind::Array(ty, len) => {
840 write!(writer, "[")?;
841 Self::type_name(writer, ty)?;
842 write!(writer, "; ")?;
843 Self::array_len(writer, len)?;
844 write!(writer, "]")?;
845 }
846
847 TypeNameKind::Ref(ty) => Self::named_ref(writer, ty)?,
848 }
849
850 Ok(())
851 }
852
853 fn array_len(writer: &mut dyn Write, len: &ArrayLen) -> IoResult<()> {
854 match len.value() {
855 ArrayLenValue::Literal(val) => write!(writer, "{}", val.value()),
856 ArrayLenValue::Ref(ty) => Self::named_ref(writer, ty),
857 }
858 }
859
860 fn named_ref(writer: &mut dyn Write, ty: &NamedRef) -> IoResult<()> {
861 match ty.kind() {
862 NamedRefKind::Intern(ty) => write!(writer, "{}", ty.value()),
863
864 NamedRefKind::Extern(schema, ty) => {
865 write!(writer, "{}::{}", schema.value(), ty.value())
866 }
867 }
868 }
869
870 fn type_name_or_inline(
871 &mut self,
872 writer: &mut dyn Write,
873 ty: &TypeNameOrInline,
874 indent: usize,
875 ) -> IoResult<()> {
876 match ty {
877 TypeNameOrInline::TypeName(ty) => Self::type_name(writer, ty),
878 TypeNameOrInline::Struct(struct_def) => self.inline_struct(writer, struct_def, indent),
879 TypeNameOrInline::Enum(enum_def) => self.inline_enum(writer, enum_def, indent),
880 }
881 }
882
883 fn is_multi_line_type_name_or_inline(ty: &TypeNameOrInline) -> bool {
884 match ty {
885 TypeNameOrInline::TypeName(_) => false,
886
887 TypeNameOrInline::Struct(struct_def) => Self::is_multi_line_struct(
888 &[],
889 struct_def.doc(),
890 struct_def.attributes(),
891 struct_def.fields(),
892 struct_def.fallback(),
893 ),
894
895 TypeNameOrInline::Enum(enum_def) => Self::is_multi_line_enum(
896 &[],
897 enum_def.doc(),
898 enum_def.attributes(),
899 enum_def.variants(),
900 enum_def.fallback(),
901 ),
902 }
903 }
904
905 fn comment(writer: &mut dyn Write, comment: &[Comment], indent: usize) -> IoResult<()> {
906 for comment in comment {
907 Self::indent(writer, indent)?;
908
909 let comment = comment.value_inner();
910 if comment.is_empty() {
911 writeln!(writer, "//")?;
912 } else {
913 writeln!(writer, "// {comment}")?;
914 }
915 }
916
917 Ok(())
918 }
919
920 fn doc(writer: &mut dyn Write, doc: &[DocString], indent: usize) -> IoResult<()> {
921 Self::doc_impl(writer, doc, indent, "///")
922 }
923
924 fn doc_inline(writer: &mut dyn Write, doc: &[DocString], indent: usize) -> IoResult<()> {
925 Self::doc_impl(writer, doc, indent, "//!")
926 }
927
928 fn doc_impl(
929 writer: &mut dyn Write,
930 doc: &[DocString],
931 indent: usize,
932 style: &str,
933 ) -> IoResult<()> {
934 for doc in doc {
935 Self::indent(writer, indent)?;
936
937 let doc = doc.value_inner();
938 if doc.is_empty() {
939 writeln!(writer, "{style}")?;
940 } else {
941 writeln!(writer, "{style} {doc}")?;
942 }
943 }
944
945 Ok(())
946 }
947
948 fn newline(&mut self, writer: &mut dyn Write) -> IoResult<()> {
949 if self.newline {
950 writeln!(writer)?;
951 self.newline = false;
952 }
953
954 Ok(())
955 }
956
957 fn newline_with_first(&mut self, writer: &mut dyn Write, is_multi_line: bool) -> IoResult<()> {
958 self.newline |= !self.first && is_multi_line;
959 self.first = false;
960 self.newline(writer)
961 }
962
963 fn newline_def(
964 &mut self,
965 writer: &mut dyn Write,
966 kind: DefinitionKind,
967 is_multi_line: bool,
968 ) -> IoResult<()> {
969 match self.last_def {
970 Some(last_def) => {
971 if last_def != kind {
972 self.newline = true;
973 self.last_def = Some(kind);
974 }
975
976 self.first = false;
977 }
978
979 None => {
980 self.last_def = Some(kind);
981 self.first = true;
982 }
983 }
984
985 self.newline_with_first(writer, is_multi_line)
986 }
987
988 fn newline_item(
989 &mut self,
990 writer: &mut dyn Write,
991 kind: ItemKind,
992 is_multi_line: bool,
993 ) -> IoResult<()> {
994 match self.last_item {
995 Some(last_item) => {
996 if last_item != kind {
997 self.newline = true;
998 self.last_item = Some(kind);
999 }
1000 }
1001
1002 None => self.last_item = Some(kind),
1003 }
1004
1005 self.newline_with_first(writer, is_multi_line)
1006 }
1007
1008 fn indent(writer: &mut dyn Write, len: usize) -> IoResult<()> {
1009 const INDENT: &str = " ";
1010 write!(writer, "{}", &INDENT[..len])
1011 }
1012}
1013
1014#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1015enum DefinitionKind {
1016 Struct,
1017 Enum,
1018 Service,
1019 Const,
1020 Newtype,
1021}
1022
1023#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1024enum ItemKind {
1025 Function,
1026 Event,
1027}