Skip to main content

wit_component/
printing.rs

1use anyhow::{Result, anyhow, bail};
2use std::borrow::Cow;
3use std::collections::HashMap;
4use std::fmt::Display;
5use std::mem;
6use std::ops::Deref;
7use wit_parser::*;
8
9/// A utility for printing WebAssembly interface definitions to a string.
10pub struct WitPrinter<O: Output = OutputToString> {
11    /// Visitor that holds the WIT document being printed.
12    pub output: O,
13
14    // Count of how many items in this current block have been printed to print
15    // a blank line between each item, but not the first item.
16    any_items: bool,
17
18    // Whether to print doc comments.
19    emit_docs: bool,
20}
21
22impl Default for WitPrinter {
23    fn default() -> Self {
24        Self::new(OutputToString::default())
25    }
26}
27
28impl<O: Output> WitPrinter<O> {
29    /// Create new instance.
30    pub fn new(output: O) -> Self {
31        Self {
32            output,
33            any_items: false,
34            emit_docs: true,
35        }
36    }
37
38    /// Prints the specified `pkg` which is located in `resolve` to `O`.
39    ///
40    /// The `nested` list of packages are other packages to include at the end
41    /// of the output in `package ... { ... }` syntax.
42    pub fn print(&mut self, resolve: &Resolve, pkg: PackageId, nested: &[PackageId]) -> Result<()> {
43        self.print_package(resolve, pkg, true)?;
44        for (i, pkg_id) in nested.iter().enumerate() {
45            if i > 0 {
46                self.output.newline();
47                self.output.newline();
48            }
49            self.print_package(resolve, *pkg_id, false)?;
50        }
51        Ok(())
52    }
53
54    /// Configure whether doc comments will be printed.
55    ///
56    /// Defaults to true.
57    pub fn emit_docs(&mut self, enabled: bool) -> &mut Self {
58        self.emit_docs = enabled;
59        self
60    }
61
62    /// Prints the specified `pkg`.
63    ///
64    /// If `is_main` is not set, nested package notation is used.
65    pub fn print_package(
66        &mut self,
67        resolve: &Resolve,
68        pkg: PackageId,
69        is_main: bool,
70    ) -> Result<()> {
71        let pkg = &resolve.packages[pkg];
72        self.print_package_outer(pkg)?;
73
74        if is_main {
75            self.output.semicolon();
76            self.output.newline();
77        } else {
78            self.output.indent_start();
79        }
80
81        for (name, id) in pkg.interfaces.iter() {
82            self.print_interface_outer(resolve, *id, name)?;
83            self.output.indent_start();
84            self.print_interface(resolve, *id)?;
85            self.output.indent_end();
86            if is_main {
87                self.output.newline();
88            }
89        }
90
91        for (name, id) in pkg.worlds.iter() {
92            self.print_docs(&resolve.worlds[*id].docs);
93            self.print_stability(&resolve.worlds[*id].stability);
94            self.output.keyword("world");
95            self.output.str(" ");
96            self.print_name_type(name, TypeKind::WorldDeclaration);
97            self.output.indent_start();
98            self.print_world(resolve, *id)?;
99            self.output.indent_end();
100        }
101        if !is_main {
102            self.output.indent_end();
103        }
104        Ok(())
105    }
106
107    /// Print the specified package without its content.
108    /// Does not print the semicolon nor starts the indentation.
109    pub fn print_package_outer(&mut self, pkg: &Package) -> Result<()> {
110        self.print_docs(&pkg.docs);
111        self.output.keyword("package");
112        self.output.str(" ");
113        self.print_name_type(&pkg.name.namespace, TypeKind::NamespaceDeclaration);
114        self.output.str(":");
115        self.print_name_type(&pkg.name.name, TypeKind::PackageNameDeclaration);
116        if let Some(version) = &pkg.name.version {
117            self.print_name_type(&format!("@{version}"), TypeKind::VersionDeclaration);
118        }
119        Ok(())
120    }
121
122    fn new_item(&mut self) {
123        if self.any_items {
124            self.output.newline();
125        }
126        self.any_items = true;
127    }
128
129    /// Print the given WebAssembly interface without its content.
130    /// Does not print the semicolon nor starts the indentation.
131    pub fn print_interface_outer(
132        &mut self,
133        resolve: &Resolve,
134        id: InterfaceId,
135        name: &str,
136    ) -> Result<()> {
137        self.print_docs(&resolve.interfaces[id].docs);
138        self.print_stability(&resolve.interfaces[id].stability);
139        self.output.keyword("interface");
140        self.output.str(" ");
141        self.print_name_type(name, TypeKind::InterfaceDeclaration);
142        Ok(())
143    }
144
145    /// Print the inner content of a given WebAssembly interface.
146    pub fn print_interface(&mut self, resolve: &Resolve, id: InterfaceId) -> Result<()> {
147        let prev_items = mem::replace(&mut self.any_items, false);
148        let interface = &resolve.interfaces[id];
149
150        let mut resource_funcs = HashMap::new();
151        let mut freestanding = Vec::new();
152        for (_, func) in interface.functions.iter() {
153            if let Some(id) = func.kind.resource() {
154                resource_funcs.entry(id).or_insert(Vec::new()).push(func);
155            } else {
156                freestanding.push(func);
157            }
158        }
159
160        self.print_types(
161            resolve,
162            TypeOwner::Interface(id),
163            interface
164                .types
165                .iter()
166                .map(|(name, id)| (name.as_str(), *id)),
167            &resource_funcs,
168        )?;
169
170        for func in freestanding {
171            self.new_item();
172            self.print_docs(&func.docs);
173            self.print_stability(&func.stability);
174            self.print_external_id(func.external_id.as_deref());
175            self.print_name_type(func.item_name(), TypeKind::FunctionFreestanding);
176            self.output.str(": ");
177            self.print_function(resolve, func)?;
178            self.output.semicolon();
179        }
180
181        self.any_items = prev_items;
182
183        Ok(())
184    }
185
186    /// Print types of an interface.
187    pub fn print_types<'a>(
188        &mut self,
189        resolve: &Resolve,
190        owner: TypeOwner,
191        types: impl Iterator<Item = (&'a str, TypeId)>,
192        resource_funcs: &HashMap<TypeId, Vec<&Function>>,
193    ) -> Result<()> {
194        // Partition types defined in this interface into either those imported
195        // from foreign interfaces or those defined locally.
196        let mut types_to_declare = Vec::new();
197        let mut types_to_import: Vec<(_, &TypeDef, Vec<_>)> = Vec::new();
198        for (name, ty_id) in types {
199            let ty = &resolve.types[ty_id];
200
201            // If `ty` points to another type, `other`, then this might actually
202            // be a `use`.
203            if let TypeDefKind::Type(Type::Id(other)) = ty.kind {
204                let other = &resolve.types[other];
205                match other.owner {
206                    TypeOwner::None => {}
207
208                    // `use` is only applicable when the owner of the current
209                    // set of types is different than the owner of `other`. Once
210                    // this is detected `types_to_import` is going to get
211                    // modified.
212                    other_owner if owner != other_owner => {
213                        let other_name = other
214                            .name
215                            .as_ref()
216                            .ok_or_else(|| anyhow!("cannot import unnamed type"))?;
217
218                        // As a convenience push onto the last set of types to
219                        // import if it's to the same interface and with
220                        // matching attributes.
221                        if let Some((prev_owner, prev_ty, list)) = types_to_import.last_mut() {
222                            if *prev_owner == other_owner
223                                && ty.stability == prev_ty.stability
224                                && ty.external_id == prev_ty.external_id
225                            {
226                                list.push((name, other_name));
227                                continue;
228                            }
229                        }
230                        types_to_import.push((other_owner, ty, vec![(name, other_name)]));
231                        continue;
232                    }
233                    _ => {}
234                }
235            }
236
237            types_to_declare.push(ty_id);
238        }
239
240        // Generate a `use` statement for all imported types.
241        let my_pkg = match owner {
242            TypeOwner::Interface(id) => resolve.interfaces[id].package.unwrap(),
243            TypeOwner::World(id) => resolve.worlds[id].package.unwrap(),
244            TypeOwner::None => unreachable!(),
245        };
246        for (owner, ty, tys) in types_to_import {
247            self.any_items = true;
248            self.print_stability(&ty.stability);
249            self.print_external_id(ty.external_id.as_deref());
250            self.output.keyword("use");
251            self.output.str(" ");
252            let id = match owner {
253                TypeOwner::Interface(id) => id,
254                // it's only possible to import types from interfaces at
255                // this time.
256                _ => unreachable!(),
257            };
258            self.print_path_to_interface(resolve, id, my_pkg)?;
259            self.output.str(".{"); // Note: not changing the indentation.
260            for (i, (my_name, other_name)) in tys.into_iter().enumerate() {
261                if i > 0 {
262                    self.output.str(", ");
263                }
264                if my_name == other_name {
265                    self.print_name_type(my_name, TypeKind::TypeImport);
266                } else {
267                    self.print_name_type(other_name, TypeKind::TypeImport);
268                    self.output.str(" ");
269                    self.output.keyword("as");
270                    self.output.str(" ");
271                    self.print_name_type(my_name, TypeKind::TypeAlias);
272                }
273            }
274            self.output.str("}"); // Note: not changing the indentation.
275            self.output.semicolon();
276        }
277
278        for id in types_to_declare {
279            self.new_item();
280            self.print_docs(&resolve.types[id].docs);
281            self.print_stability(&resolve.types[id].stability);
282            self.print_external_id(resolve.types[id].external_id.as_deref());
283            match resolve.types[id].kind {
284                TypeDefKind::Resource => self.print_resource(
285                    resolve,
286                    id,
287                    resource_funcs.get(&id).unwrap_or(&Vec::new()),
288                )?,
289                _ => self.declare_type(resolve, &Type::Id(id))?,
290            }
291        }
292
293        Ok(())
294    }
295
296    fn print_resource(&mut self, resolve: &Resolve, id: TypeId, funcs: &[&Function]) -> Result<()> {
297        let ty = &resolve.types[id];
298        self.output.ty("resource", TypeKind::BuiltIn);
299        self.output.str(" ");
300        self.print_name_type(
301            ty.name.as_ref().expect("resources must be named"),
302            TypeKind::Resource,
303        );
304        if funcs.is_empty() {
305            self.output.semicolon();
306            return Ok(());
307        }
308        self.output.indent_start();
309        for func in funcs {
310            self.print_docs(&func.docs);
311            self.print_stability(&func.stability);
312            self.print_external_id(func.external_id.as_deref());
313
314            match &func.kind {
315                FunctionKind::Constructor(_) => {}
316                FunctionKind::Method(_)
317                | FunctionKind::AsyncMethod(_)
318                | FunctionKind::MethodGetter(_)
319                | FunctionKind::MethodSetter(_) => {
320                    self.print_name_type(func.item_name(), TypeKind::FunctionMethod);
321                    self.output.str(": ");
322                }
323                FunctionKind::Static(_)
324                | FunctionKind::AsyncStatic(_)
325                | FunctionKind::StaticGetter(_)
326                | FunctionKind::StaticSetter(_) => {
327                    self.print_name_type(func.item_name(), TypeKind::FunctionStatic);
328                    self.output.str(": ");
329                    self.output.keyword("static");
330                    self.output.str(" ");
331                }
332                FunctionKind::Freestanding
333                | FunctionKind::AsyncFreestanding
334                | FunctionKind::Getter
335                | FunctionKind::Setter => unreachable!(),
336            }
337            self.print_function(resolve, func)?;
338            self.output.semicolon();
339        }
340        self.output.indent_end();
341
342        Ok(())
343    }
344
345    fn print_function(&mut self, resolve: &Resolve, func: &Function) -> Result<()> {
346        // Handle the `async` prefix if necessary
347        match &func.kind {
348            FunctionKind::AsyncFreestanding
349            | FunctionKind::AsyncMethod(_)
350            | FunctionKind::AsyncStatic(_) => {
351                self.output.keyword("async");
352                self.output.str(" ");
353            }
354            _ => {}
355        }
356
357        // Constructors, getters, and setters are named slightly differently.
358        match &func.kind {
359            FunctionKind::Constructor(_) => {
360                self.output.keyword("constructor");
361                self.output.str("(");
362            }
363            FunctionKind::Getter
364            | FunctionKind::MethodGetter(_)
365            | FunctionKind::StaticGetter(_) => {
366                self.output.keyword("get");
367                self.output.str("(");
368            }
369            FunctionKind::Setter
370            | FunctionKind::MethodSetter(_)
371            | FunctionKind::StaticSetter(_) => {
372                self.output.keyword("set");
373                self.output.str("(");
374            }
375            FunctionKind::Freestanding
376            | FunctionKind::AsyncFreestanding
377            | FunctionKind::Method(_)
378            | FunctionKind::AsyncMethod(_)
379            | FunctionKind::Static(_)
380            | FunctionKind::AsyncStatic(_) => {
381                self.output.keyword("func");
382                self.output.str("(");
383            }
384        }
385
386        // Methods don't print their `self` argument
387        let params_to_skip = match &func.kind {
388            FunctionKind::Method(_)
389            | FunctionKind::AsyncMethod(_)
390            | FunctionKind::MethodGetter(_)
391            | FunctionKind::MethodSetter(_) => 1,
392            _ => 0,
393        };
394        for (i, param) in func.params.iter().skip(params_to_skip).enumerate() {
395            if i > 0 {
396                self.output.str(", ");
397            }
398            self.print_name_param(&param.name);
399            self.output.str(": ");
400            self.print_type_name(resolve, &param.ty)?;
401        }
402        self.output.str(")");
403
404        // shorthand constructors don't have their results printed
405        if func.is_constructor_shorthand(resolve) {
406            return Ok(());
407        }
408
409        if let Some(ty) = &func.result {
410            self.output.str(" -> ");
411            self.print_type_name(resolve, ty)?;
412        }
413        Ok(())
414    }
415
416    /// Prints the world `id` within `resolve`.
417    ///
418    /// This is a little tricky to preserve round-tripping that WIT wants. This
419    /// function inherently can't preserve ordering of imports because resource
420    /// functions aren't guaranteed to be all adjacent to the resource itself
421    /// they're attached to. That means that at the very least, when printing
422    /// resource functions, items may be printed out-of-order.
423    ///
424    /// To help solve this the printing here is kept in sync with WIT encoding
425    /// of worlds which is to print items in the order of:
426    ///
427    /// * Any imported interface. Ordering between interfaces is preserved.
428    /// * Any types, including resource functions on those types. Ordering
429    ///   between types is preserved.
430    /// * Any functions, which may refer to those types. Ordering between
431    ///   functions is preserved.
432    ///
433    /// This keeps things printed in a roughly topological fashion and makes
434    /// round-tripping a bit more reliable.
435    fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
436        let prev_items = mem::replace(&mut self.any_items, false);
437        let world = &resolve.worlds[id];
438        let pkgid = world.package.unwrap();
439        let mut types = Vec::new();
440        let mut resource_funcs = HashMap::new();
441        let mut function_imports_to_print = Vec::new();
442        for (name, import) in world.imports.iter() {
443            match import {
444                WorldItem::Type { id, .. } => match name {
445                    WorldKey::Name(s) => types.push((s.as_str(), *id)),
446                    WorldKey::Interface(_) => unreachable!(),
447                },
448                _ => {
449                    if let WorldItem::Function(f) = import {
450                        if let Some(id) = f.kind.resource() {
451                            resource_funcs.entry(id).or_insert(Vec::new()).push(f);
452                            continue;
453                        }
454                        function_imports_to_print.push((name, import));
455                        continue;
456                    }
457                    self.print_world_item(resolve, name, import, pkgid, "import")?;
458                    // Don't put a blank line between imports, but count
459                    // imports as having printed something so if anything comes
460                    // after them then a blank line is printed after imports.
461                    self.any_items = true;
462                }
463            }
464        }
465        self.print_types(
466            resolve,
467            TypeOwner::World(id),
468            types.into_iter(),
469            &resource_funcs,
470        )?;
471
472        for (name, import) in function_imports_to_print {
473            self.print_world_item(resolve, name, import, pkgid, "import")?;
474            self.any_items = true;
475        }
476        if !world.exports.is_empty() {
477            self.new_item();
478        }
479        for (name, export) in world.exports.iter() {
480            self.print_world_item(resolve, name, export, pkgid, "export")?;
481        }
482        self.any_items = prev_items;
483        Ok(())
484    }
485
486    fn print_world_item(
487        &mut self,
488        resolve: &Resolve,
489        name: &WorldKey,
490        item: &WorldItem,
491        cur_pkg: PackageId,
492        import_or_export_keyword: &str,
493    ) -> Result<()> {
494        // Print docs for this import/export statement. For interfaces, prefer
495        // the docs attached to the statement itself (`WorldItem::Interface`'s
496        // `docs`); for an inline `import x: interface { .. }` with no statement
497        // docs fall back to the interface definition's docs.
498        let docs = match item {
499            WorldItem::Interface { id, docs, .. } => {
500                if docs.contents.is_some() {
501                    Some(docs)
502                } else if matches!(name, WorldKey::Name(_)) {
503                    Some(&resolve.interfaces[*id].docs)
504                } else {
505                    None
506                }
507            }
508            WorldItem::Function(f) => Some(&f.docs),
509            // Types are handled separately
510            WorldItem::Type { .. } => unreachable!(),
511        };
512        if let Some(docs) = docs {
513            self.print_docs(docs);
514        }
515
516        self.print_stability(item.stability(resolve));
517        self.print_external_id(resolve.external_id_value(name, item).as_deref());
518        self.output.keyword(import_or_export_keyword);
519        self.output.str(" ");
520        match name {
521            WorldKey::Name(name) => {
522                match item {
523                    WorldItem::Interface { id, .. } => {
524                        self.print_name_type(name, TypeKind::Other);
525                        self.output.str(": ");
526                        if resolve.interfaces[*id].name.is_none() {
527                            // `import label: interface { .. }` syntax
528                            self.output.keyword("interface");
529                            self.output.indent_start();
530                            self.print_interface(resolve, *id)?;
531                            self.output.indent_end();
532                        } else {
533                            // `import label: use-path;` syntax
534                            self.print_path_to_interface(resolve, *id, cur_pkg)?;
535                            self.output.semicolon();
536                        }
537                    }
538                    WorldItem::Function(f) => {
539                        // Getters and setters are named `[get]foo` and
540                        // `[set]foo`, so print the unmangled name.
541                        self.print_name_type(f.item_name(), TypeKind::Other);
542                        self.output.str(": ");
543                        self.print_function(resolve, f)?;
544                        self.output.semicolon();
545                    }
546                    // Types are handled separately
547                    WorldItem::Type { .. } => unreachable!(),
548                }
549            }
550            WorldKey::Interface(id) => {
551                match item {
552                    WorldItem::Interface { id: id2, .. } => assert_eq!(id, id2),
553                    _ => unreachable!(),
554                }
555                self.print_path_to_interface(resolve, *id, cur_pkg)?;
556                self.output.semicolon();
557            }
558        }
559        Ok(())
560    }
561
562    fn print_path_to_interface(
563        &mut self,
564        resolve: &Resolve,
565        interface: InterfaceId,
566        cur_pkg: PackageId,
567    ) -> Result<()> {
568        let iface = &resolve.interfaces[interface];
569        if iface.package == Some(cur_pkg) {
570            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
571        } else {
572            let pkg = &resolve.packages[iface.package.unwrap()].name;
573            self.print_name_type(&pkg.namespace, TypeKind::NamespacePath);
574            self.output.str(":");
575            self.print_name_type(&pkg.name, TypeKind::PackageNamePath);
576            self.output.str("/");
577            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
578            if let Some(version) = &pkg.version {
579                self.print_name_type(&format!("@{version}"), TypeKind::VersionPath);
580            }
581        }
582        Ok(())
583    }
584
585    /// Print the name of type `ty`.
586    pub fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
587        match ty {
588            Type::Bool => self.output.ty("bool", TypeKind::BuiltIn),
589            Type::U8 => self.output.ty("u8", TypeKind::BuiltIn),
590            Type::U16 => self.output.ty("u16", TypeKind::BuiltIn),
591            Type::U32 => self.output.ty("u32", TypeKind::BuiltIn),
592            Type::U64 => self.output.ty("u64", TypeKind::BuiltIn),
593            Type::S8 => self.output.ty("s8", TypeKind::BuiltIn),
594            Type::S16 => self.output.ty("s16", TypeKind::BuiltIn),
595            Type::S32 => self.output.ty("s32", TypeKind::BuiltIn),
596            Type::S64 => self.output.ty("s64", TypeKind::BuiltIn),
597            Type::F32 => self.output.ty("f32", TypeKind::BuiltIn),
598            Type::F64 => self.output.ty("f64", TypeKind::BuiltIn),
599            Type::Char => self.output.ty("char", TypeKind::BuiltIn),
600            Type::String => self.output.ty("string", TypeKind::BuiltIn),
601            Type::ErrorContext => self.output.ty("error-context", TypeKind::BuiltIn),
602
603            Type::Id(id) => {
604                let ty = &resolve.types[*id];
605                if let Some(name) = &ty.name {
606                    self.print_name_type(name, TypeKind::Other);
607                    return Ok(());
608                }
609
610                match &ty.kind {
611                    TypeDefKind::Handle(h) => {
612                        self.print_handle_type(resolve, h, false)?;
613                    }
614                    TypeDefKind::Resource => {
615                        bail!("resolve has an unnamed resource type");
616                    }
617                    TypeDefKind::Tuple(t) => {
618                        self.print_tuple_type(resolve, t)?;
619                    }
620                    TypeDefKind::Option(t) => {
621                        self.print_option_type(resolve, t)?;
622                    }
623                    TypeDefKind::Result(t) => {
624                        self.print_result_type(resolve, t)?;
625                    }
626                    TypeDefKind::Record(_) => {
627                        bail!("resolve has an unnamed record type");
628                    }
629                    TypeDefKind::Flags(_) => {
630                        bail!("resolve has unnamed flags type")
631                    }
632                    TypeDefKind::Enum(_) => {
633                        bail!("resolve has unnamed enum type")
634                    }
635                    TypeDefKind::Variant(_) => {
636                        bail!("resolve has unnamed variant type")
637                    }
638                    TypeDefKind::List(ty) => {
639                        self.output.ty("list", TypeKind::BuiltIn);
640                        self.output.generic_args_start();
641                        self.print_type_name(resolve, ty)?;
642                        self.output.generic_args_end();
643                    }
644                    TypeDefKind::Map(key_ty, value_ty) => {
645                        self.output.ty("map", TypeKind::BuiltIn);
646                        self.output.generic_args_start();
647                        self.print_type_name(resolve, key_ty)?;
648                        self.output.str(", ");
649                        self.print_type_name(resolve, value_ty)?;
650                        self.output.generic_args_end();
651                    }
652                    TypeDefKind::FixedLengthList(ty, size) => {
653                        self.output.ty("list", TypeKind::BuiltIn);
654                        self.output.generic_args_start();
655                        self.print_type_name(resolve, ty)?;
656                        self.output.push_str(&format!(", {}", *size));
657                        self.output.generic_args_end();
658                    }
659                    TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
660                    TypeDefKind::Future(ty) => {
661                        if let Some(ty) = ty {
662                            self.output.push_str("future<");
663                            self.print_type_name(resolve, ty)?;
664                            self.output.push_str(">");
665                        } else {
666                            self.output.push_str("future");
667                        }
668                    }
669                    TypeDefKind::Stream(ty) => {
670                        if let Some(ty) = ty {
671                            self.output.push_str("stream<");
672                            self.print_type_name(resolve, ty)?;
673                            self.output.push_str(">");
674                        } else {
675                            self.output.push_str("stream");
676                        }
677                    }
678                    TypeDefKind::Unknown => unreachable!(),
679                }
680            }
681        }
682
683        Ok(())
684    }
685
686    fn print_handle_type(
687        &mut self,
688        resolve: &Resolve,
689        handle: &Handle,
690        force_handle_type_printed: bool,
691    ) -> Result<()> {
692        match handle {
693            Handle::Own(ty) => {
694                let ty = &resolve.types[*ty];
695                if force_handle_type_printed {
696                    self.output.ty("own", TypeKind::BuiltIn);
697                    self.output.generic_args_start();
698                }
699                self.print_name_type(
700                    ty.name
701                        .as_ref()
702                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
703                    TypeKind::Resource,
704                );
705                if force_handle_type_printed {
706                    self.output.generic_args_end();
707                }
708            }
709
710            Handle::Borrow(ty) => {
711                self.output.ty("borrow", TypeKind::BuiltIn);
712                self.output.generic_args_start();
713                let ty = &resolve.types[*ty];
714                self.print_name_type(
715                    ty.name
716                        .as_ref()
717                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
718                    TypeKind::Resource,
719                );
720                self.output.generic_args_end();
721            }
722        }
723
724        Ok(())
725    }
726
727    fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> {
728        self.output.ty("tuple", TypeKind::BuiltIn);
729        self.output.generic_args_start();
730        for (i, ty) in tuple.types.iter().enumerate() {
731            if i > 0 {
732                self.output.str(", ");
733            }
734            self.print_type_name(resolve, ty)?;
735        }
736        self.output.generic_args_end();
737
738        Ok(())
739    }
740
741    fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> {
742        self.output.ty("option", TypeKind::BuiltIn);
743        self.output.generic_args_start();
744        self.print_type_name(resolve, payload)?;
745        self.output.generic_args_end();
746        Ok(())
747    }
748
749    fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> {
750        match result {
751            Result_ {
752                ok: Some(ok),
753                err: Some(err),
754            } => {
755                self.output.ty("result", TypeKind::BuiltIn);
756                self.output.generic_args_start();
757                self.print_type_name(resolve, ok)?;
758                self.output.str(", ");
759                self.print_type_name(resolve, err)?;
760                self.output.generic_args_end();
761            }
762            Result_ {
763                ok: None,
764                err: Some(err),
765            } => {
766                self.output.ty("result", TypeKind::BuiltIn);
767                self.output.generic_args_start();
768                self.output.str("_, ");
769                self.print_type_name(resolve, err)?;
770                self.output.generic_args_end();
771            }
772            Result_ {
773                ok: Some(ok),
774                err: None,
775            } => {
776                self.output.ty("result", TypeKind::BuiltIn);
777                self.output.generic_args_start();
778                self.print_type_name(resolve, ok)?;
779                self.output.generic_args_end();
780            }
781            Result_ {
782                ok: None,
783                err: None,
784            } => {
785                self.output.ty("result", TypeKind::BuiltIn);
786            }
787        }
788        Ok(())
789    }
790
791    fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
792        match ty {
793            Type::Bool
794            | Type::U8
795            | Type::U16
796            | Type::U32
797            | Type::U64
798            | Type::S8
799            | Type::S16
800            | Type::S32
801            | Type::S64
802            | Type::F32
803            | Type::F64
804            | Type::Char
805            | Type::String
806            | Type::ErrorContext => return Ok(()),
807
808            Type::Id(id) => {
809                let ty = &resolve.types[*id];
810                match &ty.kind {
811                    TypeDefKind::Handle(h) => {
812                        self.declare_handle(resolve, ty.name.as_deref(), h)?
813                    }
814                    TypeDefKind::Resource => panic!("resources should be processed separately"),
815                    TypeDefKind::Record(r) => {
816                        self.declare_record(resolve, ty.name.as_deref(), r)?
817                    }
818                    TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?,
819                    TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?,
820                    TypeDefKind::Variant(v) => {
821                        self.declare_variant(resolve, ty.name.as_deref(), v)?
822                    }
823                    TypeDefKind::Option(t) => {
824                        self.declare_option(resolve, ty.name.as_deref(), t)?
825                    }
826                    TypeDefKind::Result(r) => {
827                        self.declare_result(resolve, ty.name.as_deref(), r)?
828                    }
829                    TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?,
830                    TypeDefKind::List(inner) => {
831                        self.declare_list(resolve, ty.name.as_deref(), inner)?
832                    }
833                    TypeDefKind::Map(key, value) => {
834                        self.declare_map(resolve, ty.name.as_deref(), key, value)?
835                    }
836                    TypeDefKind::FixedLengthList(inner, size) => {
837                        self.declare_fixed_length_list(resolve, ty.name.as_deref(), inner, *size)?
838                    }
839                    TypeDefKind::Type(inner) => match ty.name.as_deref() {
840                        Some(name) => {
841                            self.output.keyword("type");
842                            self.output.str(" ");
843                            self.print_name_type(name, TypeKind::TypeName);
844                            self.output.str(" = ");
845                            self.print_type_name(resolve, inner)?;
846                            self.output.semicolon();
847                        }
848                        None => bail!("unnamed type in document"),
849                    },
850                    TypeDefKind::Future(inner) => {
851                        self.declare_future(resolve, ty.name.as_deref(), inner.as_ref())?
852                    }
853                    TypeDefKind::Stream(inner) => {
854                        self.declare_stream(resolve, ty.name.as_deref(), inner.as_ref())?
855                    }
856                    TypeDefKind::Unknown => unreachable!(),
857                }
858            }
859        }
860        Ok(())
861    }
862
863    fn declare_handle(
864        &mut self,
865        resolve: &Resolve,
866        name: Option<&str>,
867        handle: &Handle,
868    ) -> Result<()> {
869        match name {
870            Some(name) => {
871                self.output.keyword("type");
872                self.output.str(" ");
873                self.print_name_type(name, TypeKind::Resource);
874                self.output.str(" = ");
875                // Note that the `true` here forces owned handles to be printed
876                // as `own<T>`. The purpose of this is because `type a = b`, if
877                // `b` is a resource, is encoded differently as `type a =
878                // own<b>`. By forcing a handle to be printed here it's staying
879                // true to what's in the WIT document.
880                self.print_handle_type(resolve, handle, true)?;
881                self.output.semicolon();
882
883                Ok(())
884            }
885            None => bail!("document has unnamed handle type"),
886        }
887    }
888
889    fn declare_record(
890        &mut self,
891        resolve: &Resolve,
892        name: Option<&str>,
893        record: &Record,
894    ) -> Result<()> {
895        match name {
896            Some(name) => {
897                self.output.keyword("record");
898                self.output.str(" ");
899                self.print_name_type(name, TypeKind::Record);
900                self.output.indent_start();
901                for field in &record.fields {
902                    self.print_docs(&field.docs);
903                    self.print_name_param(&field.name);
904                    self.output.str(": ");
905                    self.print_type_name(resolve, &field.ty)?;
906                    self.output.str(",");
907                    self.output.newline();
908                }
909                self.output.indent_end();
910                Ok(())
911            }
912            None => bail!("document has unnamed record type"),
913        }
914    }
915
916    fn declare_tuple(
917        &mut self,
918        resolve: &Resolve,
919        name: Option<&str>,
920        tuple: &Tuple,
921    ) -> Result<()> {
922        if let Some(name) = name {
923            self.output.keyword("type");
924            self.output.str(" ");
925            self.print_name_type(name, TypeKind::Tuple);
926            self.output.str(" = ");
927            self.print_tuple_type(resolve, tuple)?;
928            self.output.semicolon();
929        }
930        Ok(())
931    }
932
933    fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> {
934        match name {
935            Some(name) => {
936                self.output.keyword("flags");
937                self.output.str(" ");
938                self.print_name_type(name, TypeKind::Flags);
939                self.output.indent_start();
940                for flag in &flags.flags {
941                    self.print_docs(&flag.docs);
942                    self.print_name_case(&flag.name);
943                    self.output.str(",");
944                    self.output.newline();
945                }
946                self.output.indent_end();
947            }
948            None => bail!("document has unnamed flags type"),
949        }
950        Ok(())
951    }
952
953    fn declare_variant(
954        &mut self,
955        resolve: &Resolve,
956        name: Option<&str>,
957        variant: &Variant,
958    ) -> Result<()> {
959        let name = match name {
960            Some(name) => name,
961            None => bail!("document has unnamed variant type"),
962        };
963        self.output.keyword("variant");
964        self.output.str(" ");
965        self.print_name_type(name, TypeKind::Variant);
966        self.output.indent_start();
967        for case in &variant.cases {
968            self.print_docs(&case.docs);
969            self.print_name_case(&case.name);
970            if let Some(ty) = case.ty {
971                self.output.str("(");
972                self.print_type_name(resolve, &ty)?;
973                self.output.str(")");
974            }
975            self.output.str(",");
976            self.output.newline();
977        }
978        self.output.indent_end();
979        Ok(())
980    }
981
982    fn declare_option(
983        &mut self,
984        resolve: &Resolve,
985        name: Option<&str>,
986        payload: &Type,
987    ) -> Result<()> {
988        if let Some(name) = name {
989            self.output.keyword("type");
990            self.output.str(" ");
991            self.print_name_type(name, TypeKind::Option);
992            self.output.str(" = ");
993            self.print_option_type(resolve, payload)?;
994            self.output.semicolon();
995        }
996        Ok(())
997    }
998
999    fn declare_result(
1000        &mut self,
1001        resolve: &Resolve,
1002        name: Option<&str>,
1003        result: &Result_,
1004    ) -> Result<()> {
1005        if let Some(name) = name {
1006            self.output.keyword("type");
1007            self.output.str(" ");
1008            self.print_name_type(name, TypeKind::Result);
1009            self.output.str(" = ");
1010            self.print_result_type(resolve, result)?;
1011            self.output.semicolon();
1012        }
1013        Ok(())
1014    }
1015
1016    fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> {
1017        let name = match name {
1018            Some(name) => name,
1019            None => bail!("document has unnamed enum type"),
1020        };
1021        self.output.keyword("enum");
1022        self.output.str(" ");
1023        self.print_name_type(name, TypeKind::Enum);
1024        self.output.indent_start();
1025        for case in &enum_.cases {
1026            self.print_docs(&case.docs);
1027            self.print_name_case(&case.name);
1028            self.output.str(",");
1029            self.output.newline();
1030        }
1031        self.output.indent_end();
1032        Ok(())
1033    }
1034
1035    fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
1036        if let Some(name) = name {
1037            self.output.keyword("type");
1038            self.output.str(" ");
1039            self.print_name_type(name, TypeKind::List);
1040            self.output.str(" = ");
1041            self.output.ty("list", TypeKind::BuiltIn);
1042            self.output.str("<");
1043            self.print_type_name(resolve, ty)?;
1044            self.output.str(">");
1045            self.output.semicolon();
1046            return Ok(());
1047        }
1048
1049        Ok(())
1050    }
1051
1052    fn declare_map(
1053        &mut self,
1054        resolve: &Resolve,
1055        name: Option<&str>,
1056        key_ty: &Type,
1057        value_ty: &Type,
1058    ) -> Result<()> {
1059        if let Some(name) = name {
1060            self.output.keyword("type");
1061            self.output.str(" ");
1062            self.print_name_type(name, TypeKind::Map);
1063            self.output.str(" = ");
1064            self.output.ty("map", TypeKind::BuiltIn);
1065            self.output.str("<");
1066            self.print_type_name(resolve, key_ty)?;
1067            self.output.str(", ");
1068            self.print_type_name(resolve, value_ty)?;
1069            self.output.str(">");
1070            self.output.semicolon();
1071            return Ok(());
1072        }
1073
1074        Ok(())
1075    }
1076
1077    fn declare_fixed_length_list(
1078        &mut self,
1079        resolve: &Resolve,
1080        name: Option<&str>,
1081        ty: &Type,
1082        elements: u32,
1083    ) -> Result<()> {
1084        if let Some(name) = name {
1085            self.output.keyword("type");
1086            self.output.str(" ");
1087            self.print_name_type(name, TypeKind::List);
1088            self.output.str(" = ");
1089            self.output.ty("list", TypeKind::BuiltIn);
1090            self.output.str("<");
1091            self.print_type_name(resolve, ty)?;
1092            self.output.str(&format!(", {elements}"));
1093            self.output.str(">");
1094            self.output.semicolon();
1095            return Ok(());
1096        }
1097
1098        Ok(())
1099    }
1100
1101    fn declare_stream(
1102        &mut self,
1103        resolve: &Resolve,
1104        name: Option<&str>,
1105        ty: Option<&Type>,
1106    ) -> Result<()> {
1107        if let Some(name) = name {
1108            self.output.keyword("type");
1109            self.output.str(" ");
1110            self.print_name_type(name, TypeKind::Stream);
1111            self.output.str(" = ");
1112            self.output.ty("stream", TypeKind::BuiltIn);
1113            if let Some(ty) = ty {
1114                self.output.str("<");
1115                self.print_type_name(resolve, ty)?;
1116                self.output.str(">");
1117            }
1118            self.output.semicolon();
1119        }
1120
1121        Ok(())
1122    }
1123
1124    fn declare_future(
1125        &mut self,
1126        resolve: &Resolve,
1127        name: Option<&str>,
1128        ty: Option<&Type>,
1129    ) -> Result<()> {
1130        if let Some(name) = name {
1131            self.output.keyword("type");
1132            self.output.str(" ");
1133            self.print_name_type(name, TypeKind::Future);
1134            self.output.str(" = ");
1135            self.output.ty("future", TypeKind::BuiltIn);
1136            if let Some(ty) = ty {
1137                self.output.str("<");
1138                self.print_type_name(resolve, ty)?;
1139                self.output.str(">");
1140            }
1141            self.output.semicolon();
1142        }
1143
1144        Ok(())
1145    }
1146
1147    fn escape_name(name: &str) -> Cow<'_, str> {
1148        if is_keyword(name) {
1149            Cow::Owned(format!("%{name}"))
1150        } else {
1151            Cow::Borrowed(name)
1152        }
1153    }
1154
1155    fn print_name_type(&mut self, name: &str, kind: TypeKind) {
1156        self.output.ty(Self::escape_name(name).deref(), kind);
1157    }
1158
1159    fn print_name_param(&mut self, name: &str) {
1160        self.output.param(Self::escape_name(name).deref());
1161    }
1162
1163    fn print_name_case(&mut self, name: &str) {
1164        self.output.case(Self::escape_name(name).deref());
1165    }
1166
1167    fn print_docs(&mut self, docs: &Docs) {
1168        if self.emit_docs {
1169            if let Some(contents) = &docs.contents {
1170                for line in contents.lines() {
1171                    self.output.doc(line);
1172                }
1173            }
1174        }
1175    }
1176
1177    fn print_stability(&mut self, stability: &Stability) {
1178        match stability {
1179            Stability::Unknown => {}
1180            Stability::Stable { since, deprecated } => {
1181                self.output.keyword("@since");
1182                self.output.str("(");
1183                self.output.keyword("version");
1184                self.output.str(" = ");
1185                self.print_name_type(&since.to_string(), TypeKind::VersionAnnotation);
1186                self.output.str(")");
1187                self.output.newline();
1188                if let Some(version) = deprecated {
1189                    self.output.keyword("@deprecated");
1190                    self.output.str("(");
1191                    self.output.keyword("version");
1192                    self.output.str(" = ");
1193                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1194                    self.output.str(")");
1195                    self.output.newline();
1196                }
1197            }
1198            Stability::Unstable {
1199                feature,
1200                deprecated,
1201            } => {
1202                self.output.keyword("@unstable");
1203                self.output.str("(");
1204                self.output.keyword("feature");
1205                self.output.str(" = ");
1206                self.output.str(feature);
1207                self.output.str(")");
1208                self.output.newline();
1209                if let Some(version) = deprecated {
1210                    self.output.keyword("@deprecated");
1211                    self.output.str("(");
1212                    self.output.keyword("version");
1213                    self.output.str(" = ");
1214                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1215                    self.output.str(")");
1216                    self.output.newline();
1217                }
1218            }
1219        }
1220    }
1221
1222    fn print_external_id(&mut self, id: Option<&str>) {
1223        let Some(id) = id else {
1224            return;
1225        };
1226        self.output.keyword("@external-id");
1227        self.output.str("(\"");
1228        let mut buf = [0; 4];
1229        for c in id.chars() {
1230            if c.is_ascii_alphanumeric()
1231                || c == '-'
1232                || c == '_'
1233                || c == '.'
1234                || c == '/'
1235                || c == ':'
1236                || c == ' '
1237            {
1238                self.output.push_str(c.encode_utf8(&mut buf));
1239                continue;
1240            }
1241            match c {
1242                '\\' => self.output.push_str("\\\\"),
1243                '"' => self.output.push_str("\\\""),
1244                '\n' => self.output.push_str("\\n"),
1245                '\r' => self.output.push_str("\\r"),
1246                '\t' => self.output.push_str("\\t"),
1247                _ => {
1248                    self.output.push_str(&format!("\\u{{{:x}}}", c as u32));
1249                }
1250            }
1251        }
1252        self.output.str("\")");
1253        self.output.newline();
1254    }
1255}
1256
1257fn is_keyword(name: &str) -> bool {
1258    matches!(
1259        name,
1260        "use"
1261            | "type"
1262            | "func"
1263            | "u8"
1264            | "u16"
1265            | "u32"
1266            | "u64"
1267            | "s8"
1268            | "s16"
1269            | "s32"
1270            | "s64"
1271            | "f32"
1272            | "f64"
1273            | "float32"
1274            | "float64"
1275            | "char"
1276            | "resource"
1277            | "record"
1278            | "flags"
1279            | "variant"
1280            | "enum"
1281            | "bool"
1282            | "string"
1283            | "option"
1284            | "result"
1285            | "future"
1286            | "stream"
1287            | "list"
1288            | "own"
1289            | "borrow"
1290            | "_"
1291            | "as"
1292            | "from"
1293            | "static"
1294            | "interface"
1295            | "tuple"
1296            | "world"
1297            | "import"
1298            | "export"
1299            | "package"
1300            | "with"
1301            | "include"
1302            | "constructor"
1303            | "error-context"
1304            | "async"
1305            | "map"
1306    )
1307}
1308
1309/// Trait defining visitor methods driven by [`WitPrinter`](WitPrinter).
1310///
1311/// Some methods in this trait have default implementations. These default
1312/// implementations may rely on helper functions that are not
1313/// invoked directly by `WitPrinter`.
1314pub trait Output {
1315    /// Push a string slice into a buffer or an output.
1316    ///
1317    /// Parameter `src` can contain punctuation characters, and must be escaped
1318    /// when outputting to languages like HTML.
1319    /// Helper function used exclusively by the default implementations of trait methods.
1320    /// This function is not called directly by `WitPrinter`.
1321    /// When overriding all the trait methods, users do not need to handle this function.
1322    fn push_str(&mut self, src: &str);
1323
1324    /// Set the appropriate indentation.
1325    ///
1326    /// Helper function used exclusively by the default implementations of trait methods.
1327    /// This function is not called directly by `WitPrinter`.
1328    /// When overriding all the trait methods, users do not need to handle this function.
1329    fn indent_if_needed(&mut self) -> bool;
1330
1331    /// Start of indentation. In WIT this represents ` {\n`.
1332    fn indent_start(&mut self);
1333
1334    /// End of indentation. In WIT this represents `}\n`.
1335    fn indent_end(&mut self);
1336
1337    /// This method is designed to be used only by the default methods of this trait.
1338    /// Called only from the default implementation functions of this trait.
1339    fn indent_and_print(&mut self, src: &str) {
1340        assert!(!src.contains('\n'));
1341        let indented = self.indent_if_needed();
1342        if indented && src.starts_with(' ') {
1343            panic!("cannot add a space at the beginning of a line");
1344        }
1345        self.push_str(src);
1346    }
1347
1348    /// A newline is added.
1349    fn newline(&mut self);
1350
1351    /// A keyword is added. Keywords are hardcoded strings from `[a-z]`, but can start with `@`
1352    /// when printing a [Feature Gate](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#feature-gates)
1353    fn keyword(&mut self, src: &str) {
1354        self.indent_and_print(src);
1355    }
1356
1357    /// A type is added.
1358    fn ty(&mut self, src: &str, _kind: TypeKind) {
1359        self.indent_and_print(src);
1360    }
1361
1362    /// A parameter name of a function, record or a named return is added.
1363    fn param(&mut self, src: &str) {
1364        self.indent_and_print(src);
1365    }
1366
1367    /// A case belonging to a variant, enum or flags is added.
1368    fn case(&mut self, src: &str) {
1369        self.indent_and_print(src);
1370    }
1371
1372    /// Generic argument section starts. In WIT this represents the `<` character.
1373    fn generic_args_start(&mut self) {
1374        assert!(
1375            !self.indent_if_needed(),
1376            "`generic_args_start` is never called after newline"
1377        );
1378        self.push_str("<");
1379    }
1380
1381    /// Generic argument section ends. In WIT this represents the '>' character.
1382    fn generic_args_end(&mut self) {
1383        assert!(
1384            !self.indent_if_needed(),
1385            "`generic_args_end` is never called after newline"
1386        );
1387        self.push_str(">");
1388    }
1389
1390    /// Called when a single documentation line is added.
1391    /// The `doc` parameter starts with `///` omitted, and can be an empty string.
1392    fn doc(&mut self, doc: &str) {
1393        assert!(!doc.contains('\n'));
1394        self.indent_if_needed();
1395        self.push_str("///");
1396        if !doc.is_empty() {
1397            self.push_str(" ");
1398            self.push_str(doc);
1399        }
1400        self.newline();
1401    }
1402
1403    /// A semicolon is added.
1404    fn semicolon(&mut self) {
1405        assert!(
1406            !self.indent_if_needed(),
1407            "`semicolon` is never called after newline"
1408        );
1409        self.push_str(";");
1410        self.newline();
1411    }
1412
1413    /// Any string that does not have a specialized function is added.
1414    /// Parameter `src` can contain punctuation characters, and must be escaped
1415    /// when outputting to languages like HTML.
1416    fn str(&mut self, src: &str) {
1417        self.indent_and_print(src);
1418    }
1419}
1420
1421/// Represents the different kinds of types that can be encountered while
1422/// visiting a WIT file.
1423///
1424/// Each variant refers to the name of the respective element (e.g., function, type, or namespace),
1425/// not the entire declaration.
1426#[non_exhaustive]
1427#[derive(Clone, Copy, Debug)]
1428pub enum TypeKind {
1429    /// A built-in type, such as "list" or "option".
1430    BuiltIn,
1431    /// An enumeration type name.
1432    Enum,
1433    /// An error-context type name.
1434    ErrorContext,
1435    /// A flags type name.
1436    Flags,
1437    /// A freestanding function name, not associated with any specific type or namespace.
1438    /// For example, "myfunc" in `myfunc: func() -> string;`.
1439    FunctionFreestanding,
1440    /// A method, associated with a resource.
1441    FunctionMethod,
1442    /// A static function, associated with a resource.
1443    FunctionStatic,
1444    /// A future type name.
1445    Future,
1446    /// An interface declaration name.
1447    InterfaceDeclaration,
1448    /// An interface name when printing a path, for example in `use`.
1449    InterfacePath,
1450    /// A list type name.
1451    List,
1452    /// A map type name.
1453    Map,
1454    /// A namespace declaration.
1455    NamespaceDeclaration,
1456    /// A namespace when printing a path, for example in `use`.
1457    NamespacePath,
1458    /// An option type name.
1459    Option,
1460    /// A package name declaration.
1461    PackageNameDeclaration,
1462    /// A package name when printing a path, for example in `use`.
1463    PackageNamePath,
1464    /// A record type name.
1465    Record,
1466    /// A resource type name.
1467    Resource,
1468    /// A result type name.
1469    Result,
1470    /// A stream type name.
1471    Stream,
1472    /// A tuple type name.
1473    Tuple,
1474    /// A type alias.
1475    TypeAlias,
1476    /// An imported type name.
1477    TypeImport,
1478    /// A user-defined type name.
1479    TypeName,
1480    /// A variant type name.
1481    Variant,
1482    /// A version declaration.
1483    VersionDeclaration,
1484    /// A version when printing a path, for example in `use`.
1485    VersionPath,
1486    /// A version when printing stability annotations, for example in `@since`
1487    VersionAnnotation,
1488    /// A world declaration name.
1489    WorldDeclaration,
1490    /// A fallback for types that do not fit into any other category.
1491    Other,
1492}
1493
1494/// Helper structure to help maintain an indentation level when printing source,
1495/// modeled after the support in `wit-bindgen-core`. Indentation is set to two spaces.
1496#[derive(Default)]
1497pub struct OutputToString {
1498    indent: usize,
1499    output: String,
1500    // set to true after newline, then to false after first item is indented.
1501    needs_indent: bool,
1502}
1503
1504impl Output for OutputToString {
1505    fn push_str(&mut self, src: &str) {
1506        self.output.push_str(src);
1507    }
1508
1509    fn indent_if_needed(&mut self) -> bool {
1510        if self.needs_indent {
1511            for _ in 0..self.indent {
1512                // Indenting by two spaces.
1513                self.output.push_str("  ");
1514            }
1515            self.needs_indent = false;
1516            true
1517        } else {
1518            false
1519        }
1520    }
1521
1522    fn indent_start(&mut self) {
1523        assert!(
1524            !self.needs_indent,
1525            "`indent_start` is never called after newline"
1526        );
1527        self.output.push_str(" {");
1528        self.indent += 1;
1529        self.newline();
1530    }
1531
1532    fn indent_end(&mut self) {
1533        // Note that a `saturating_sub` is used here to prevent a panic
1534        // here in the case of invalid code being generated in debug
1535        // mode. It's typically easier to debug those issues through
1536        // looking at the source code rather than getting a panic.
1537        self.indent = self.indent.saturating_sub(1);
1538        self.indent_if_needed();
1539        self.output.push('}');
1540        self.newline();
1541    }
1542
1543    fn newline(&mut self) {
1544        self.output.push('\n');
1545        self.needs_indent = true;
1546    }
1547}
1548
1549impl From<OutputToString> for String {
1550    fn from(output: OutputToString) -> String {
1551        output.output
1552    }
1553}
1554
1555impl Display for OutputToString {
1556    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1557        self.output.fmt(f)
1558    }
1559}