Skip to main content

aldrin_parser/
fmt.rs

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}