wit_encoder/
world.rs

1use std::fmt;
2
3use crate::{ident::Ident, Docs, Include, Interface, Render, RenderOpts, StandaloneFunc, Use};
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
8pub struct World {
9    /// The WIT identifier name of this world.
10    name: Ident,
11
12    /// Interface uses
13    uses: Vec<Use>,
14
15    /// All imported and exported items into this world.
16    items: Vec<WorldItem>,
17
18    /// Documentation associated with this world declaration.
19    docs: Option<Docs>,
20}
21
22impl World {
23    /// Create a new world.
24    pub fn new(name: impl Into<Ident>) -> Self {
25        Self {
26            name: name.into(),
27            uses: vec![],
28            items: vec![],
29            docs: None,
30        }
31    }
32
33    /// Add a `name` to the world
34    pub fn set_name(&mut self, name: impl Into<Ident>) {
35        self.name = name.into();
36    }
37
38    pub fn name(&self) -> &Ident {
39        &self.name
40    }
41
42    pub fn items(&self) -> &[WorldItem] {
43        &self.items
44    }
45
46    pub fn items_mut(&mut self) -> &mut Vec<WorldItem> {
47        &mut self.items
48    }
49
50    /// Add an import or export to the world
51    pub fn item(&mut self, item: WorldItem) {
52        self.items.push(item);
53    }
54
55    pub fn inline_interface_import(&mut self, value: Interface) {
56        self.item(WorldItem::inline_interface_import(value));
57    }
58    pub fn inline_interface_export(&mut self, value: Interface) {
59        self.item(WorldItem::inline_interface_export(value));
60    }
61    pub fn named_interface_import(&mut self, value: impl Into<WorldNamedInterface>) {
62        self.item(WorldItem::named_interface_import(value));
63    }
64    pub fn named_interface_export(&mut self, value: impl Into<WorldNamedInterface>) {
65        self.item(WorldItem::named_interface_export(value));
66    }
67    pub fn function_import(&mut self, value: StandaloneFunc) {
68        self.item(WorldItem::function_import(value));
69    }
70    pub fn function_export(&mut self, value: StandaloneFunc) {
71        self.item(WorldItem::function_export(value));
72    }
73    pub fn include(&mut self, include: Include) {
74        self.item(WorldItem::Include(include));
75    }
76
77    pub fn uses(&self) -> &[Use] {
78        &self.uses
79    }
80    pub fn uses_mut(&mut self) -> &mut [Use] {
81        &mut self.uses
82    }
83    pub fn use_(&mut self, use_: Use) {
84        self.uses.push(use_);
85    }
86    pub fn use_type(
87        &mut self,
88        target: impl Into<Ident>,
89        item: impl Into<Ident>,
90        rename: Option<Ident>,
91    ) {
92        let target = target.into();
93        let use_ = self.uses.iter_mut().find(|u| u.target() == &target);
94        match use_ {
95            Some(use_) => use_.item(item, rename),
96            None => {
97                self.use_({
98                    let mut use_ = Use::new(target);
99                    use_.item(item, rename);
100                    use_
101                });
102            }
103        }
104    }
105
106    pub fn docs(&self) -> Option<&Docs> {
107        self.docs.as_ref()
108    }
109
110    /// Set the documentation
111    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
112        self.docs = docs.map(|d| d.into());
113    }
114}
115
116impl Render for World {
117    fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
118        fn import(f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
119            write!(f, "{}import ", opts.spaces())
120        }
121        fn export(f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
122            write!(f, "{}export ", opts.spaces())
123        }
124        fn render_function(
125            f: &mut fmt::Formatter<'_>,
126            _opts: &RenderOpts,
127            func: &StandaloneFunc,
128        ) -> fmt::Result {
129            write!(f, "{}: func({})", func.name, func.params)?;
130            if let Some(ty) = &func.result {
131                write!(f, " -> {ty}")?;
132            }
133            write!(f, ";\n")?;
134            Ok(())
135        }
136        write!(f, "{}world {} {{\n", opts.spaces(), self.name)?;
137        let opts = &opts.indent();
138        self.uses.render(f, opts)?;
139        for item in &self.items {
140            match item {
141                WorldItem::InlineInterfaceImport(interface) => {
142                    if let Some(docs) = &interface.docs {
143                        docs.render(f, opts)?;
144                    }
145                    import(f, opts)?;
146                    write!(f, "{}: interface {{", interface.name)?;
147                    if !interface.uses.is_empty() || !interface.items.is_empty() {
148                        write!(f, "\n")?;
149                        interface.uses.render(f, &opts.indent())?;
150                        interface.items.render(f, &opts.indent())?;
151                        write!(f, "{}}}\n", opts.spaces())?;
152                    } else {
153                        write!(f, "}}\n")?;
154                    }
155                }
156                WorldItem::InlineInterfaceExport(interface) => {
157                    if let Some(docs) = &interface.docs {
158                        docs.render(f, opts)?;
159                    }
160                    export(f, opts)?;
161                    write!(f, "{}: interface {{", interface.name)?;
162                    if !interface.items.is_empty() {
163                        write!(f, "\n")?;
164                        interface.items.render(f, &opts.indent())?;
165                        write!(f, "{}}}\n", opts.spaces())?;
166                    } else {
167                        write!(f, "}}\n")?;
168                    }
169                }
170                WorldItem::NamedInterfaceImport(interface) => {
171                    if let Some(docs) = &interface.docs {
172                        docs.render(f, opts)?;
173                    }
174                    import(f, opts)?;
175                    write!(f, "{};\n", interface.name)?;
176                }
177                WorldItem::NamedInterfaceExport(interface) => {
178                    if let Some(docs) = &interface.docs {
179                        docs.render(f, opts)?;
180                    }
181                    export(f, opts)?;
182                    write!(f, "{};\n", interface.name)?;
183                }
184                WorldItem::FunctionImport(function) => {
185                    if let Some(docs) = &function.docs {
186                        docs.render(f, opts)?;
187                    }
188                    import(f, opts)?;
189                    render_function(f, opts, function)?;
190                }
191                WorldItem::FunctionExport(function) => {
192                    if let Some(docs) = &function.docs {
193                        docs.render(f, opts)?;
194                    }
195                    export(f, opts)?;
196                    render_function(f, opts, function)?;
197                }
198                WorldItem::Include(include) => include.render(f, opts)?,
199            }
200        }
201        let opts = &opts.outdent();
202        write!(f, "{}}}\n", opts.spaces())?;
203        Ok(())
204    }
205}
206
207#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
208#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
209#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
210pub enum WorldItem {
211    /// An imported inline interface
212    InlineInterfaceImport(Interface),
213
214    /// An exported inline interface
215    InlineInterfaceExport(Interface),
216
217    /// Refers to a named interface import
218    NamedInterfaceImport(WorldNamedInterface),
219
220    /// Refers to a named interface export
221    NamedInterfaceExport(WorldNamedInterface),
222
223    /// A function is being directly imported from this world.
224    FunctionImport(StandaloneFunc),
225
226    /// A function is being directly exported from this world.
227    FunctionExport(StandaloneFunc),
228
229    /// Include type
230    Include(Include),
231}
232
233impl WorldItem {
234    pub fn inline_interface_import(value: Interface) -> Self {
235        Self::InlineInterfaceImport(value)
236    }
237    pub fn inline_interface_export(value: Interface) -> Self {
238        Self::InlineInterfaceExport(value)
239    }
240    pub fn named_interface_import(value: impl Into<WorldNamedInterface>) -> Self {
241        Self::NamedInterfaceImport(value.into())
242    }
243    pub fn named_interface_export(value: impl Into<WorldNamedInterface>) -> Self {
244        Self::NamedInterfaceExport(value.into())
245    }
246    pub fn function_import(value: StandaloneFunc) -> Self {
247        Self::FunctionImport(value)
248    }
249    pub fn function_export(value: StandaloneFunc) -> Self {
250        Self::FunctionExport(value)
251    }
252    pub fn include(value: impl Into<Ident>) -> Self {
253        Self::Include(Include::new(value))
254    }
255}
256
257#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
258#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
259#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
260pub struct WorldNamedInterface {
261    /// Name of this interface.
262    pub(crate) name: Ident,
263
264    /// Documentation associated with this interface.
265    pub(crate) docs: Option<Docs>,
266}
267
268impl<N> From<N> for WorldNamedInterface
269where
270    N: Into<Ident>,
271{
272    fn from(name: N) -> Self {
273        Self::new(name)
274    }
275}
276
277impl WorldNamedInterface {
278    pub fn new(name: impl Into<Ident>) -> Self {
279        Self {
280            name: name.into(),
281            docs: None,
282        }
283    }
284
285    pub fn set_name(&mut self, name: impl Into<Ident>) {
286        self.name = name.into();
287    }
288
289    pub fn name(&self) -> &Ident {
290        &self.name
291    }
292
293    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
294        self.docs = docs.map(|d| d.into());
295    }
296
297    pub fn docs(&self) -> Option<&Docs> {
298        self.docs.as_ref()
299    }
300}