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