wit_encoder/
ty.rs

1use std::fmt::{self, Display};
2
3use crate::{
4    Docs, Enum, EnumCase, Field, Flag, Flags, Record, Render, RenderOpts, Resource, ResourceFunc,
5    Result_, Tuple, Variant, ident::Ident,
6};
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
11pub enum Type {
12    Bool,
13    U8,
14    U16,
15    U32,
16    U64,
17    S8,
18    S16,
19    S32,
20    S64,
21    F32,
22    F64,
23    Char,
24    String,
25    Borrow(Ident),
26    Option(Box<Type>),
27    Result(Box<Result_>),
28    List(Box<Type>),
29    Map(Box<Type>, Box<Type>),
30    FixedSizeList(Box<Type>, u32),
31    Tuple(Tuple),
32    Future(Option<Box<Type>>),
33    Stream(Option<Box<Type>>),
34    ErrorContext,
35    Named(Ident),
36}
37
38impl Type {
39    pub fn borrow(name: impl Into<Ident>) -> Self {
40        Type::Borrow(name.into())
41    }
42    pub fn option(type_: Type) -> Self {
43        Type::Option(Box::new(type_))
44    }
45    pub fn result(result: Result_) -> Self {
46        Type::Result(Box::new(result))
47    }
48    pub fn result_ok(type_: Type) -> Self {
49        Type::Result(Box::new(Result_::ok(type_)))
50    }
51    pub fn result_err(type_: Type) -> Self {
52        Type::Result(Box::new(Result_::err(type_)))
53    }
54    pub fn result_both(ok: Type, err: Type) -> Self {
55        Type::Result(Box::new(Result_::both(ok, err)))
56    }
57    pub fn result_empty() -> Self {
58        Type::Result(Box::new(Result_::empty()))
59    }
60    pub fn list(type_: Type) -> Self {
61        Type::List(Box::new(type_))
62    }
63    pub fn map(key: Type, value: Type) -> Self {
64        Type::Map(Box::new(key), Box::new(value))
65    }
66    pub fn fixed_size_list(type_: Type, size: u32) -> Self {
67        Type::FixedSizeList(Box::new(type_), size)
68    }
69    pub fn tuple(types: impl IntoIterator<Item = Type>) -> Self {
70        Type::Tuple(Tuple {
71            types: types.into_iter().collect(),
72        })
73    }
74    pub fn future(type_: Option<Type>) -> Self {
75        Type::Future(type_.map(Box::new))
76    }
77    pub fn stream(type_: Option<Type>) -> Self {
78        Type::Stream(type_.map(Box::new))
79    }
80    pub fn named(name: impl Into<Ident>) -> Self {
81        Type::Named(name.into())
82    }
83}
84impl From<Result_> for Type {
85    fn from(value: Result_) -> Self {
86        Self::result(value)
87    }
88}
89impl From<Tuple> for Type {
90    fn from(value: Tuple) -> Self {
91        Type::Tuple(value)
92    }
93}
94impl From<Ident> for Type {
95    fn from(value: Ident) -> Self {
96        Self::named(value)
97    }
98}
99
100impl Display for Type {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            Type::Bool => write!(f, "bool"),
104            Type::U8 => write!(f, "u8"),
105            Type::U16 => write!(f, "u16"),
106            Type::U32 => write!(f, "u32"),
107            Type::U64 => write!(f, "u64"),
108            Type::S8 => write!(f, "s8"),
109            Type::S16 => write!(f, "s16"),
110            Type::S32 => write!(f, "s32"),
111            Type::S64 => write!(f, "s64"),
112            Type::F32 => write!(f, "f32"),
113            Type::F64 => write!(f, "f64"),
114            Type::Char => write!(f, "char"),
115            Type::String => write!(f, "string"),
116            Type::Named(name) => write!(f, "{name}"),
117            Type::Borrow(type_) => {
118                write!(f, "borrow<{type_}>")
119            }
120            Type::Option(type_) => {
121                write!(f, "option<{type_}>")
122            }
123            Type::Result(result) => result.fmt(f),
124            Type::List(type_) => {
125                write!(f, "list<{type_}>")
126            }
127            Type::Map(key, value) => {
128                write!(f, "map<{key}, {value}>")
129            }
130            Type::FixedSizeList(type_, size) => {
131                write!(f, "list<{type_}, {size}>")
132            }
133            Type::Tuple(tuple) => tuple.fmt(f),
134            Type::Future(None) => {
135                write!(f, "future")
136            }
137            Type::Future(Some(type_)) => {
138                write!(f, "future<{type_}>")
139            }
140            Type::Stream(None) => {
141                write!(f, "stream")
142            }
143            Type::Stream(Some(type_)) => {
144                write!(f, "stream<{type_}>")
145            }
146            Type::ErrorContext => write!(f, "error-context"),
147        }
148    }
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
152#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
153#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
154pub struct VariantCase {
155    name: Ident,
156    #[cfg_attr(feature = "serde", serde(rename = "type"))]
157    type_: Option<Type>,
158    docs: Option<Docs>,
159}
160
161impl VariantCase {
162    pub fn empty(name: impl Into<Ident>) -> Self {
163        Self {
164            name: name.into(),
165            type_: None,
166            docs: None,
167        }
168    }
169
170    pub fn value(name: impl Into<Ident>, ty: Type) -> Self {
171        Self {
172            name: name.into(),
173            type_: Some(ty),
174            docs: None,
175        }
176    }
177
178    pub fn set_name(&mut self, name: impl Into<Ident>) {
179        self.name = name.into();
180    }
181
182    pub fn name(&self) -> &Ident {
183        &self.name
184    }
185
186    pub fn name_mut(&mut self) -> &mut Ident {
187        &mut self.name
188    }
189
190    pub fn type_(&self) -> Option<&Type> {
191        self.type_.as_ref()
192    }
193
194    pub fn type_mut(&mut self) -> &mut Option<Type> {
195        &mut self.type_
196    }
197
198    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
199        self.docs = docs.map(|d| d.into());
200    }
201
202    pub fn docs(&self) -> &Option<Docs> {
203        &self.docs
204    }
205}
206
207impl<N> Into<VariantCase> for (N,)
208where
209    N: Into<Ident>,
210{
211    fn into(self) -> VariantCase {
212        VariantCase::empty(self.0)
213    }
214}
215
216impl<N> Into<VariantCase> for (N, Type)
217where
218    N: Into<Ident>,
219{
220    fn into(self) -> VariantCase {
221        VariantCase::value(self.0, self.1)
222    }
223}
224
225impl<N, D> Into<VariantCase> for (N, Type, D)
226where
227    N: Into<Ident>,
228    D: Into<Docs>,
229{
230    fn into(self) -> VariantCase {
231        let mut field = VariantCase::value(self.0, self.1);
232        field.set_docs(Some(self.2.into()));
233        field
234    }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
238#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
240pub struct TypeDef {
241    name: Ident,
242    kind: TypeDefKind,
243    docs: Option<Docs>,
244}
245
246impl TypeDef {
247    pub fn new(name: impl Into<Ident>, kind: TypeDefKind) -> Self {
248        TypeDef {
249            name: name.into(),
250            kind,
251            docs: None,
252        }
253    }
254
255    pub fn record(
256        name: impl Into<Ident>,
257        fields: impl IntoIterator<Item = impl Into<Field>>,
258    ) -> Self {
259        TypeDef {
260            name: name.into(),
261            kind: TypeDefKind::record(fields),
262            docs: None,
263        }
264    }
265
266    pub fn resource(
267        name: impl Into<Ident>,
268        funcs: impl IntoIterator<Item = impl Into<ResourceFunc>>,
269    ) -> Self {
270        TypeDef {
271            name: name.into(),
272            kind: TypeDefKind::resource(funcs),
273            docs: None,
274        }
275    }
276
277    pub fn flags(name: impl Into<Ident>, flags: impl IntoIterator<Item = impl Into<Flag>>) -> Self {
278        TypeDef {
279            name: name.into(),
280            kind: TypeDefKind::flags(flags),
281            docs: None,
282        }
283    }
284
285    pub fn variant(
286        name: impl Into<Ident>,
287        cases: impl IntoIterator<Item = impl Into<VariantCase>>,
288    ) -> Self {
289        TypeDef {
290            name: name.into(),
291            kind: TypeDefKind::variant(cases),
292            docs: None,
293        }
294    }
295
296    pub fn enum_(
297        name: impl Into<Ident>,
298        cases: impl IntoIterator<Item = impl Into<EnumCase>>,
299    ) -> Self {
300        TypeDef {
301            name: name.into(),
302            kind: TypeDefKind::enum_(cases),
303            docs: None,
304        }
305    }
306
307    pub fn type_(name: impl Into<Ident>, type_: Type) -> Self {
308        TypeDef {
309            name: name.into(),
310            kind: TypeDefKind::type_(type_),
311            docs: None,
312        }
313    }
314
315    pub fn name(&self) -> &Ident {
316        &self.name
317    }
318
319    pub fn name_mut(&mut self) -> &mut Ident {
320        &mut self.name
321    }
322
323    pub fn kind(&self) -> &TypeDefKind {
324        &self.kind
325    }
326
327    pub fn kind_mut(&mut self) -> &mut TypeDefKind {
328        &mut self.kind
329    }
330
331    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
332        self.docs = docs.map(|d| d.into());
333    }
334
335    pub fn docs(&self) -> &Option<Docs> {
336        &self.docs
337    }
338}
339
340#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
341#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
342#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
343pub enum TypeDefKind {
344    Record(Record),
345    Resource(Resource),
346    Flags(Flags),
347    Variant(Variant),
348    Enum(Enum),
349    Type(Type),
350}
351
352impl TypeDefKind {
353    pub fn record(fields: impl IntoIterator<Item = impl Into<Field>>) -> Self {
354        Self::Record(Record {
355            fields: fields.into_iter().map(|c| c.into()).collect(),
356        })
357    }
358
359    pub fn resource(funcs: impl IntoIterator<Item = impl Into<ResourceFunc>>) -> Self {
360        Self::Resource(Resource {
361            funcs: funcs.into_iter().map(|f| f.into()).collect(),
362        })
363    }
364
365    pub fn flags(flags: impl IntoIterator<Item = impl Into<Flag>>) -> Self {
366        Self::Flags(Flags {
367            flags: flags.into_iter().map(|f| f.into()).collect(),
368        })
369    }
370
371    pub fn variant(cases: impl IntoIterator<Item = impl Into<VariantCase>>) -> Self {
372        Self::Variant(Variant {
373            cases: cases.into_iter().map(|c| c.into()).collect(),
374        })
375    }
376
377    pub fn enum_(cases: impl IntoIterator<Item = impl Into<EnumCase>>) -> Self {
378        Self::Enum(Enum {
379            cases: cases.into_iter().map(|c| c.into()).collect(),
380        })
381    }
382
383    pub fn type_(type_: Type) -> Self {
384        Self::Type(type_)
385    }
386}
387
388impl Render for TypeDef {
389    fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
390        match &self.kind {
391            TypeDefKind::Record(record) => {
392                if let Some(docs) = &self.docs {
393                    docs.render(f, opts)?;
394                }
395                write!(f, "{}record {} {{", opts.spaces(), self.name)?;
396                for (index, field) in record.fields.iter().enumerate() {
397                    if index == 0 {
398                        write!(f, "\n")?;
399                    }
400                    let opts = opts.indent();
401                    if let Some(docs) = &field.docs {
402                        docs.render(f, &opts)?;
403                    }
404                    write!(f, "{}{}: {},\n", opts.spaces(), field.name, field.type_)?;
405                }
406                write!(f, "{}}}\n", opts.spaces())?;
407            }
408            TypeDefKind::Resource(resource) => {
409                if let Some(docs) = &self.docs {
410                    docs.render(f, opts)?;
411                }
412                write!(f, "{}resource {} {{\n", opts.spaces(), self.name)?;
413                for func in &resource.funcs {
414                    let opts = opts.indent();
415                    if let Some(docs) = &func.docs {
416                        docs.render(f, &opts)?;
417                    }
418                    match &func.kind {
419                        crate::ResourceFuncKind::Method(name, async_, result) => {
420                            let opt_async = if *async_ { "async " } else { "" };
421                            write!(
422                                f,
423                                "{}{name}: {opt_async}func({})",
424                                opts.spaces(),
425                                func.params
426                            )?;
427                            if let Some(ty) = result {
428                                write!(f, " -> {ty}")?;
429                            }
430                            write!(f, ";\n")?;
431                        }
432                        crate::ResourceFuncKind::Static(name, async_, result) => {
433                            let opt_async = if *async_ { "async " } else { "" };
434                            write!(
435                                f,
436                                "{}{name}: static {opt_async}func({})",
437                                opts.spaces(),
438                                func.params
439                            )?;
440                            if let Some(ty) = result {
441                                write!(f, " -> {ty}")?;
442                            }
443                            write!(f, ";\n")?;
444                        }
445                        crate::ResourceFuncKind::Constructor(result) => {
446                            write!(f, "{}constructor({})", opts.spaces(), func.params)?;
447                            if let Some(ty) = result {
448                                write!(f, " -> {ty}")?;
449                            }
450                            write!(f, ";\n")?;
451                        }
452                    }
453                }
454                write!(f, "{}}}\n", opts.spaces())?;
455            }
456            TypeDefKind::Flags(flags) => {
457                if let Some(docs) = &self.docs {
458                    docs.render(f, opts)?;
459                }
460                write!(f, "{}flags {} {{\n", opts.spaces(), self.name)?;
461                for flag in &flags.flags {
462                    let opts = opts.indent();
463                    if let Some(docs) = &flag.docs {
464                        docs.render(f, &opts)?;
465                    }
466                    write!(f, "{}{},\n", opts.spaces(), flag.name)?;
467                }
468                write!(f, "{}}}\n", opts.spaces())?;
469            }
470            TypeDefKind::Variant(variant) => {
471                if let Some(docs) = &self.docs {
472                    docs.render(f, opts)?;
473                }
474                write!(f, "{}variant {} {{\n", opts.spaces(), self.name)?;
475                for case in &variant.cases {
476                    let opts = opts.indent();
477                    if let Some(docs) = &case.docs {
478                        docs.render(f, &opts)?;
479                    }
480                    match &case.type_ {
481                        Some(type_) => {
482                            write!(f, "{}{}({}),\n", opts.spaces(), case.name, type_)?;
483                        }
484                        None => {
485                            write!(f, "{}{},\n", opts.spaces(), case.name)?;
486                        }
487                    }
488                }
489                write!(f, "{}}}\n", opts.spaces())?;
490            }
491            TypeDefKind::Enum(enum_) => {
492                if let Some(docs) = &self.docs {
493                    docs.render(f, opts)?;
494                }
495                write!(f, "{}enum {} {{\n", opts.spaces(), self.name)?;
496                for case in &enum_.cases {
497                    let opts = opts.indent();
498                    if let Some(docs) = &case.docs {
499                        docs.render(f, &opts)?;
500                    }
501                    write!(f, "{}{},\n", opts.spaces(), case.name)?;
502                }
503                write!(f, "{}}}\n", opts.spaces())?;
504            }
505            TypeDefKind::Type(type_) => {
506                if let Some(docs) = &self.docs {
507                    docs.render(f, opts)?;
508                }
509                write!(f, "{}type {} = {};\n", opts.spaces(), self.name, type_)?;
510            }
511        }
512        Ok(())
513    }
514}