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        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}