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 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 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 InlineInterfaceImport(Interface),
213
214 InlineInterfaceExport(Interface),
216
217 NamedInterfaceImport(WorldNamedInterface),
219
220 NamedInterfaceExport(WorldNamedInterface),
222
223 FunctionImport(StandaloneFunc),
225
226 FunctionExport(StandaloneFunc),
228
229 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 pub(crate) name: Ident,
263
264 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}