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 name: Ident,
11
12 uses: Vec<Use>,
14
15 items: Vec<WorldItem>,
17
18 docs: Option<Docs>,
20}
21
22impl World {
23 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 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 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 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.items.is_empty() {
164 write!(f, "\n")?;
165 interface.items.render(f, &opts.indent())?;
166 write!(f, "{}}}\n", opts.spaces())?;
167 } else {
168 write!(f, "}}\n")?;
169 }
170 }
171 WorldItem::NamedInterfaceImport(interface) => {
172 if let Some(docs) = &interface.docs {
173 docs.render(f, opts)?;
174 }
175 import(f, opts)?;
176 write!(f, "{};\n", interface.name)?;
177 }
178 WorldItem::NamedInterfaceExport(interface) => {
179 if let Some(docs) = &interface.docs {
180 docs.render(f, opts)?;
181 }
182 export(f, opts)?;
183 write!(f, "{};\n", interface.name)?;
184 }
185 WorldItem::FunctionImport(function) => {
186 if let Some(docs) = &function.docs {
187 docs.render(f, opts)?;
188 }
189 import(f, opts)?;
190 render_function(f, opts, function)?;
191 }
192 WorldItem::FunctionExport(function) => {
193 if let Some(docs) = &function.docs {
194 docs.render(f, opts)?;
195 }
196 export(f, opts)?;
197 render_function(f, opts, function)?;
198 }
199 WorldItem::Include(include) => include.render(f, opts)?,
200 }
201 }
202 let opts = &opts.outdent();
203 write!(f, "{}}}\n", opts.spaces())?;
204 Ok(())
205 }
206}
207
208#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
209#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
210#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
211pub enum WorldItem {
212 InlineInterfaceImport(Interface),
214
215 InlineInterfaceExport(Interface),
217
218 NamedInterfaceImport(WorldNamedInterface),
220
221 NamedInterfaceExport(WorldNamedInterface),
223
224 FunctionImport(StandaloneFunc),
226
227 FunctionExport(StandaloneFunc),
229
230 Include(Include),
232}
233
234impl WorldItem {
235 pub fn inline_interface_import(value: Interface) -> Self {
236 Self::InlineInterfaceImport(value)
237 }
238 pub fn inline_interface_export(value: Interface) -> Self {
239 Self::InlineInterfaceExport(value)
240 }
241 pub fn named_interface_import(value: impl Into<WorldNamedInterface>) -> Self {
242 Self::NamedInterfaceImport(value.into())
243 }
244 pub fn named_interface_export(value: impl Into<WorldNamedInterface>) -> Self {
245 Self::NamedInterfaceExport(value.into())
246 }
247 pub fn function_import(value: StandaloneFunc) -> Self {
248 Self::FunctionImport(value)
249 }
250 pub fn function_export(value: StandaloneFunc) -> Self {
251 Self::FunctionExport(value)
252 }
253 pub fn include(value: impl Into<Ident>) -> Self {
254 Self::Include(Include::new(value))
255 }
256}
257
258#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
261pub struct WorldNamedInterface {
262 pub(crate) name: Ident,
264
265 pub(crate) docs: Option<Docs>,
267}
268
269impl<N> From<N> for WorldNamedInterface
270where
271 N: Into<Ident>,
272{
273 fn from(name: N) -> Self {
274 Self::new(name)
275 }
276}
277
278impl WorldNamedInterface {
279 pub fn new(name: impl Into<Ident>) -> Self {
280 Self {
281 name: name.into(),
282 docs: None,
283 }
284 }
285
286 pub fn set_name(&mut self, name: impl Into<Ident>) {
287 self.name = name.into();
288 }
289
290 pub fn name(&self) -> &Ident {
291 &self.name
292 }
293
294 pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
295 self.docs = docs.map(|d| d.into());
296 }
297
298 pub fn docs(&self) -> Option<&Docs> {
299 self.docs.as_ref()
300 }
301}