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.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 InlineInterfaceImport(Interface),
215
216 InlineInterfaceExport(Interface),
218
219 NamedInterfaceImport(WorldNamedInterface),
221
222 NamedInterfaceExport(WorldNamedInterface),
224
225 FunctionImport(StandaloneFunc),
227
228 FunctionExport(StandaloneFunc),
230
231 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 pub(crate) name: Ident,
265
266 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}