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