linera_witty/wit_generation/
mod.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Generation of WIT files.
5
6mod stub_instance;
7
8use std::{collections::BTreeMap, io::Write};
9
10pub use self::stub_instance::StubInstance;
11pub use crate::type_traits::RegisterWitTypes;
12
13/// Generates WIT snippets for an interface.
14pub trait WitInterface {
15    /// The [`WitType`][`crate::WitType`]s that this interface uses.
16    type Dependencies: RegisterWitTypes;
17
18    /// The name of the package the interface belongs to.
19    fn wit_package() -> &'static str;
20
21    /// The name of the interface.
22    fn wit_name() -> &'static str;
23
24    /// The WIT definitions of each function in this interface.
25    fn wit_functions() -> Vec<String>;
26}
27
28/// Trait for content generation.
29pub trait FileContentGenerator {
30    /// Generate file contents.
31    fn generate_file_contents(&self, writer: impl Write) -> std::io::Result<()>;
32}
33
34/// Helper type to write a [`WitInterface`] to a file.
35#[derive(Clone, Debug)]
36pub struct WitInterfaceWriter {
37    package: &'static str,
38    name: &'static str,
39    types: BTreeMap<String, String>,
40    functions: Vec<String>,
41}
42
43impl WitInterfaceWriter {
44    /// Prepares a new [`WitInterfaceWriter`] to write the provided `Interface`.
45    pub fn new<Interface>() -> Self
46    where
47        Interface: WitInterface,
48    {
49        let mut types = BTreeMap::new();
50
51        Interface::Dependencies::register_wit_types(&mut types);
52
53        WitInterfaceWriter {
54            package: Interface::wit_package(),
55            name: Interface::wit_name(),
56            types,
57            functions: Interface::wit_functions(),
58        }
59    }
60}
61
62impl FileContentGenerator for WitInterfaceWriter {
63    fn generate_file_contents(&self, mut writer: impl Write) -> std::io::Result<()> {
64        writeln!(writer, "package {};\n", self.package)?;
65
66        writeln!(writer, "interface {} {{", self.name)?;
67
68        for function in &self.functions {
69            writeln!(writer, "{}", function)?;
70        }
71
72        for type_declaration in self.types.values() {
73            if !type_declaration.is_empty() {
74                writeln!(writer)?;
75                write!(writer, "{}", type_declaration)?;
76            }
77        }
78
79        writeln!(writer, "}}")?;
80        Ok(())
81    }
82}
83
84/// Helper type to write a WIT file declaring a
85/// [world](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#wit-worlds).
86#[derive(Clone, Debug)]
87pub struct WitWorldWriter {
88    package: Option<&'static str>,
89    name: String,
90    imports: Vec<&'static str>,
91    exports: Vec<&'static str>,
92}
93
94impl WitWorldWriter {
95    /// Creates a new [`WitWorldWriter`] to write a world with the provided `name`.
96    pub fn new(package: impl Into<Option<&'static str>>, name: impl Into<String>) -> Self {
97        WitWorldWriter {
98            package: package.into(),
99            name: name.into(),
100            imports: Vec::new(),
101            exports: Vec::new(),
102        }
103    }
104
105    /// Registers a [`WitInterface`] to be imported into this world.
106    pub fn import<Interface>(mut self) -> Self
107    where
108        Interface: WitInterface,
109    {
110        self.imports.push(Interface::wit_name());
111        self
112    }
113
114    /// Registers a [`WitInterface`] to be exported from this world.
115    pub fn export<Interface>(mut self) -> Self
116    where
117        Interface: WitInterface,
118    {
119        self.exports.push(Interface::wit_name());
120        self
121    }
122}
123
124impl FileContentGenerator for WitWorldWriter {
125    fn generate_file_contents(&self, mut writer: impl Write) -> std::io::Result<()> {
126        if let Some(package) = &self.package {
127            writeln!(writer, "package {};\n", package)?;
128        }
129
130        writeln!(writer, "world {} {{", &self.name)?;
131
132        for import in &self.imports {
133            writeln!(writer, "    import {};", import)?;
134        }
135
136        if !self.imports.is_empty() {
137            writeln!(writer)?;
138        }
139
140        for export in &self.exports {
141            writeln!(writer, "    export {};", export)?;
142        }
143
144        writeln!(writer, "}}")?;
145        Ok(())
146    }
147}