wit_encoder/
world.rs

1use std::fmt;
2
3use crate::{Docs, Include, Interface, Render, RenderOpts, StandaloneFunc, Use, ident::Ident};
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            let opt_async = if func.async_ { "async " } else { "" };
130            write!(f, "{}: {opt_async}func({})", func.name, func.params)?;
131            if let Some(ty) = &func.result {
132                write!(f, " -> {ty}")?;
133            }
134            write!(f, ";\n")?;
135            Ok(())
136        }
137        write!(f, "{}world {} {{\n", opts.spaces(), self.name)?;
138        let opts = &opts.indent();
139        self.uses.render(f, opts)?;
140        for item in &self.items {
141            match item {
142                WorldItem::InlineInterfaceImport(interface) => {
143                    if let Some(docs) = &interface.docs {
144                        docs.render(f, opts)?;
145                    }
146                    import(f, opts)?;
147                    write!(f, "{}: interface {{", interface.name)?;
148                    if !interface.uses.is_empty() || !interface.items.is_empty() {
149                        write!(f, "\n")?;
150                        interface.uses.render(f, &opts.indent())?;
151                        interface.items.render(f, &opts.indent())?;
152                        write!(f, "{}}}\n", opts.spaces())?;
153                    } else {
154                        write!(f, "}}\n")?;
155                    }
156                }
157                WorldItem::InlineInterfaceExport(interface) => {
158                    if let Some(docs) = &interface.docs {
159                        docs.render(f, opts)?;
160                    }
161                    export(f, opts)?;
162                    write!(f, "{}: interface {{", interface.name)?;
163                    if !interface.uses.is_empty() || !interface.items.is_empty() {
164                        write!(f, "\n")?;
165                        interface.uses.render(f, &opts.indent())?;
166                        interface.items.render(f, &opts.indent())?;
167                        write!(f, "{}}}\n", opts.spaces())?;
168                    } else {
169                        write!(f, "}}\n")?;
170                    }
171                }
172                WorldItem::NamedInterfaceImport(interface) => {
173                    if let Some(docs) = &interface.docs {
174                        docs.render(f, opts)?;
175                    }
176                    import(f, opts)?;
177                    write!(f, "{};\n", interface.name)?;
178                }
179                WorldItem::NamedInterfaceExport(interface) => {
180                    if let Some(docs) = &interface.docs {
181                        docs.render(f, opts)?;
182                    }
183                    export(f, opts)?;
184                    write!(f, "{};\n", interface.name)?;
185                }
186                WorldItem::FunctionImport(function) => {
187                    if let Some(docs) = &function.docs {
188                        docs.render(f, opts)?;
189                    }
190                    import(f, opts)?;
191                    render_function(f, opts, function)?;
192                }
193                WorldItem::FunctionExport(function) => {
194                    if let Some(docs) = &function.docs {
195                        docs.render(f, opts)?;
196                    }
197                    export(f, opts)?;
198                    render_function(f, opts, function)?;
199                }
200                WorldItem::Include(include) => include.render(f, opts)?,
201            }
202        }
203        let opts = &opts.outdent();
204        write!(f, "{}}}\n", opts.spaces())?;
205        Ok(())
206    }
207}
208
209#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
211#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
212pub enum WorldItem {
213    /// An imported inline interface
214    InlineInterfaceImport(Interface),
215
216    /// An exported inline interface
217    InlineInterfaceExport(Interface),
218
219    /// Refers to a named interface import
220    NamedInterfaceImport(WorldNamedInterface),
221
222    /// Refers to a named interface export
223    NamedInterfaceExport(WorldNamedInterface),
224
225    /// A function is being directly imported from this world.
226    FunctionImport(StandaloneFunc),
227
228    /// A function is being directly exported from this world.
229    FunctionExport(StandaloneFunc),
230
231    /// Include type
232    Include(Include),
233}
234
235impl WorldItem {
236    pub fn inline_interface_import(value: Interface) -> Self {
237        Self::InlineInterfaceImport(value)
238    }
239    pub fn inline_interface_export(value: Interface) -> Self {
240        Self::InlineInterfaceExport(value)
241    }
242    pub fn named_interface_import(value: impl Into<WorldNamedInterface>) -> Self {
243        Self::NamedInterfaceImport(value.into())
244    }
245    pub fn named_interface_export(value: impl Into<WorldNamedInterface>) -> Self {
246        Self::NamedInterfaceExport(value.into())
247    }
248    pub fn function_import(value: StandaloneFunc) -> Self {
249        Self::FunctionImport(value)
250    }
251    pub fn function_export(value: StandaloneFunc) -> Self {
252        Self::FunctionExport(value)
253    }
254    pub fn include(value: impl Into<Ident>) -> Self {
255        Self::Include(Include::new(value))
256    }
257}
258
259#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
260#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
261#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
262pub struct WorldNamedInterface {
263    /// Name of this interface.
264    pub(crate) name: Ident,
265
266    /// Documentation associated with this interface.
267    pub(crate) docs: Option<Docs>,
268}
269
270impl<N> From<N> for WorldNamedInterface
271where
272    N: Into<Ident>,
273{
274    fn from(name: N) -> Self {
275        Self::new(name)
276    }
277}
278
279impl WorldNamedInterface {
280    pub fn new(name: impl Into<Ident>) -> Self {
281        Self {
282            name: name.into(),
283            docs: None,
284        }
285    }
286
287    pub fn set_name(&mut self, name: impl Into<Ident>) {
288        self.name = name.into();
289    }
290
291    pub fn name(&self) -> &Ident {
292        &self.name
293    }
294
295    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
296        self.docs = docs.map(|d| d.into());
297    }
298
299    pub fn docs(&self) -> Option<&Docs> {
300        self.docs.as_ref()
301    }
302}