Skip to main content

rib/
wit_type.rs

1use std::fmt::{Display, Formatter};
2
3#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
4#[serde(tag = "type")]
5pub enum WitExport {
6    Function(WitFunction),
7    Interface(WitInterface),
8}
9
10#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
11pub struct WitFunction {
12    pub name: String,
13    pub parameters: Vec<WitFunctionParameter>,
14    pub result: Option<WitFunctionResult>,
15}
16
17impl WitFunction {
18    pub fn is_constructor(&self) -> bool {
19        self.name.starts_with("[constructor]")
20            && self.result.is_some()
21            && matches!(
22                &self.result.as_ref().unwrap().typ,
23                WitType::Handle(TypeHandle {
24                    mode: AnalysedResourceMode::Owned,
25                    ..
26                })
27            )
28    }
29
30    pub fn is_method(&self) -> bool {
31        self.name.starts_with("[method]")
32            && !self.parameters.is_empty()
33            && matches!(
34                &self.parameters[0].typ,
35                WitType::Handle(TypeHandle {
36                    mode: AnalysedResourceMode::Borrowed,
37                    ..
38                })
39            )
40    }
41
42    pub fn is_static_method(&self) -> bool {
43        self.name.starts_with("[static]")
44    }
45}
46
47#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
48pub struct WitInterface {
49    pub name: String,
50    pub functions: Vec<WitFunction>,
51}
52
53#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
54pub struct TypeResult {
55    pub name: Option<String>,
56    pub owner: Option<String>,
57    pub ok: Option<Box<WitType>>,
58    pub err: Option<Box<WitType>>,
59}
60
61#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
62pub struct NameTypePair {
63    pub name: String,
64    pub typ: WitType,
65}
66
67#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
68pub struct NameOptionTypePair {
69    pub name: String,
70    pub typ: Option<WitType>,
71}
72
73#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
74pub struct TypeVariant {
75    pub name: Option<String>,
76    pub owner: Option<String>,
77    pub cases: Vec<NameOptionTypePair>,
78}
79
80#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
81pub struct TypeOption {
82    pub name: Option<String>,
83    pub owner: Option<String>,
84    pub inner: Box<WitType>,
85}
86
87#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
88pub struct TypeEnum {
89    pub name: Option<String>,
90    pub owner: Option<String>,
91    pub cases: Vec<String>,
92}
93
94#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
95pub struct TypeFlags {
96    pub name: Option<String>,
97    pub owner: Option<String>,
98    pub names: Vec<String>,
99}
100
101#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
102pub struct TypeRecord {
103    pub name: Option<String>,
104    pub owner: Option<String>,
105    pub fields: Vec<NameTypePair>,
106}
107
108#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
109pub struct TypeTuple {
110    pub name: Option<String>,
111    pub owner: Option<String>,
112    pub items: Vec<WitType>,
113}
114
115#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
116pub struct TypeList {
117    pub name: Option<String>,
118    pub owner: Option<String>,
119    pub inner: Box<WitType>,
120}
121
122#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
123pub struct TypeStr;
124
125#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
126pub struct TypeChr;
127
128#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
129pub struct TypeF64;
130
131#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
132pub struct TypeF32;
133
134#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
135pub struct TypeU64;
136
137#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
138pub struct TypeS64;
139
140#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
141pub struct TypeU32;
142
143#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
144pub struct TypeS32;
145
146#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
147pub struct TypeU16;
148
149#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
150pub struct TypeS16;
151
152#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
153pub struct TypeU8;
154
155#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
156pub struct TypeS8;
157
158#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
159pub struct TypeBool;
160
161#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
162pub struct TypeHandle {
163    pub name: Option<String>,
164    pub owner: Option<String>,
165    pub resource_id: AnalysedResourceId,
166    pub mode: AnalysedResourceMode,
167}
168
169#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
170#[serde(tag = "type")]
171pub enum WitType {
172    Variant(TypeVariant),
173    Result(TypeResult),
174    Option(TypeOption),
175    Enum(TypeEnum),
176    Flags(TypeFlags),
177    Record(TypeRecord),
178    Tuple(TypeTuple),
179    List(TypeList),
180    Str(TypeStr),
181    Chr(TypeChr),
182    F64(TypeF64),
183    F32(TypeF32),
184    U64(TypeU64),
185    S64(TypeS64),
186    U32(TypeU32),
187    S32(TypeS32),
188    U16(TypeU16),
189    S16(TypeS16),
190    U8(TypeU8),
191    S8(TypeS8),
192    Bool(TypeBool),
193    Handle(TypeHandle),
194}
195
196impl WitType {
197    pub fn name(&self) -> Option<&str> {
198        match self {
199            WitType::Variant(typ) => typ.name.as_deref(),
200            WitType::Result(typ) => typ.name.as_deref(),
201            WitType::Option(typ) => typ.name.as_deref(),
202            WitType::Enum(typ) => typ.name.as_deref(),
203            WitType::Flags(typ) => typ.name.as_deref(),
204            WitType::Record(typ) => typ.name.as_deref(),
205            WitType::Tuple(typ) => typ.name.as_deref(),
206            WitType::List(typ) => typ.name.as_deref(),
207            WitType::Handle(typ) => typ.name.as_deref(),
208            _ => None,
209        }
210    }
211
212    pub fn with_optional_name(self, name: Option<String>) -> Self {
213        match self {
214            WitType::Variant(mut typ) => {
215                typ.name = name;
216                WitType::Variant(typ)
217            }
218            WitType::Result(mut typ) => {
219                typ.name = name;
220                WitType::Result(typ)
221            }
222            WitType::Option(mut typ) => {
223                typ.name = name;
224                WitType::Option(typ)
225            }
226            WitType::Enum(mut typ) => {
227                typ.name = name;
228                WitType::Enum(typ)
229            }
230            WitType::Flags(mut typ) => {
231                typ.name = name;
232                WitType::Flags(typ)
233            }
234            WitType::Record(mut typ) => {
235                typ.name = name;
236                WitType::Record(typ)
237            }
238            WitType::Tuple(mut typ) => {
239                typ.name = name;
240                WitType::Tuple(typ)
241            }
242            WitType::List(mut typ) => {
243                typ.name = name;
244                WitType::List(typ)
245            }
246            WitType::Handle(mut typ) => {
247                typ.name = name;
248                WitType::Handle(typ)
249            }
250            _ => self,
251        }
252    }
253
254    pub fn named(self, name: impl AsRef<str>) -> Self {
255        self.with_optional_name(Some(name.as_ref().to_string()))
256    }
257
258    pub fn owner(&self) -> Option<&str> {
259        match self {
260            WitType::Variant(typ) => typ.owner.as_deref(),
261            WitType::Result(typ) => typ.owner.as_deref(),
262            WitType::Option(typ) => typ.owner.as_deref(),
263            WitType::Enum(typ) => typ.owner.as_deref(),
264            WitType::Flags(typ) => typ.owner.as_deref(),
265            WitType::Record(typ) => typ.owner.as_deref(),
266            WitType::Tuple(typ) => typ.owner.as_deref(),
267            WitType::List(typ) => typ.owner.as_deref(),
268            WitType::Handle(typ) => typ.owner.as_deref(),
269            _ => None,
270        }
271    }
272
273    pub fn with_optional_owner(self, owner: Option<String>) -> Self {
274        match self {
275            WitType::Variant(mut typ) => {
276                typ.owner = owner;
277                WitType::Variant(typ)
278            }
279            WitType::Result(mut typ) => {
280                typ.owner = owner;
281                WitType::Result(typ)
282            }
283            WitType::Option(mut typ) => {
284                typ.owner = owner;
285                WitType::Option(typ)
286            }
287            WitType::Enum(mut typ) => {
288                typ.owner = owner;
289                WitType::Enum(typ)
290            }
291            WitType::Flags(mut typ) => {
292                typ.owner = owner;
293                WitType::Flags(typ)
294            }
295            WitType::Record(mut typ) => {
296                typ.owner = owner;
297                WitType::Record(typ)
298            }
299            WitType::Tuple(mut typ) => {
300                typ.owner = owner;
301                WitType::Tuple(typ)
302            }
303            WitType::List(mut typ) => {
304                typ.owner = owner;
305                WitType::List(typ)
306            }
307            WitType::Handle(mut typ) => {
308                typ.owner = owner;
309                WitType::Handle(typ)
310            }
311            _ => self,
312        }
313    }
314
315    pub fn owned(self, owner: impl AsRef<str>) -> Self {
316        self.with_optional_owner(Some(owner.as_ref().to_string()))
317    }
318
319    pub fn contains_handle(&self) -> bool {
320        match self {
321            WitType::Handle(_) => true,
322            WitType::Variant(typ) => typ
323                .cases
324                .iter()
325                .any(|case| case.typ.as_ref().is_some_and(|t| t.contains_handle())),
326            WitType::Result(typ) => {
327                typ.ok.as_ref().is_some_and(|t| t.contains_handle())
328                    || typ.err.as_ref().is_some_and(|t| t.contains_handle())
329            }
330            WitType::Option(typ) => typ.inner.contains_handle(),
331            WitType::Record(typ) => typ.fields.iter().any(|f| f.typ.contains_handle()),
332            WitType::Tuple(typ) => typ.items.iter().any(|t| t.contains_handle()),
333            WitType::List(typ) => typ.inner.contains_handle(),
334            _ => false,
335        }
336    }
337}
338
339impl Display for WitType {
340    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
341        match self {
342            WitType::Variant(_) => write!(f, "Variant"),
343            WitType::Result(_) => write!(f, "Result"),
344            WitType::Option(_) => write!(f, "Option"),
345            WitType::Enum(_) => write!(f, "Enum"),
346            WitType::Flags(_) => write!(f, "Flags"),
347            WitType::Record(_) => write!(f, "Record"),
348            WitType::Tuple(_) => write!(f, "Tuple"),
349            WitType::List(_) => write!(f, "List"),
350            WitType::Str(_) => write!(f, "Str"),
351            WitType::Chr(_) => write!(f, "Chr"),
352            WitType::F64(_) => write!(f, "F64"),
353            WitType::F32(_) => write!(f, "F32"),
354            WitType::U64(_) => write!(f, "U64"),
355            WitType::S64(_) => write!(f, "S64"),
356            WitType::U32(_) => write!(f, "U32"),
357            WitType::S32(_) => write!(f, "S32"),
358            WitType::U16(_) => write!(f, "U16"),
359            WitType::S16(_) => write!(f, "S16"),
360            WitType::U8(_) => write!(f, "U8"),
361            WitType::S8(_) => write!(f, "S8"),
362            WitType::Bool(_) => write!(f, "Bool"),
363            WitType::Handle(_) => write!(f, "Handle"),
364        }
365    }
366}
367
368#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
369pub enum AnalysedResourceMode {
370    Owned,
371    Borrowed,
372}
373
374#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
375pub struct AnalysedResourceId(pub u64);
376
377#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
378pub struct WitFunctionParameter {
379    pub name: String,
380    pub typ: WitType,
381}
382
383#[derive(Debug, Clone, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
384pub struct WitFunctionResult {
385    pub typ: WitType,
386}
387
388/// Helper constructors for building `WitType` values in tests and metadata.
389pub mod builders {
390    use super::*;
391
392    pub fn field(name: &str, typ: WitType) -> NameTypePair {
393        NameTypePair {
394            name: name.to_string(),
395            typ,
396        }
397    }
398
399    pub fn case(name: &str, typ: WitType) -> NameOptionTypePair {
400        NameOptionTypePair {
401            name: name.to_string(),
402            typ: Some(typ),
403        }
404    }
405
406    pub fn opt_case(name: &str, typ: Option<WitType>) -> NameOptionTypePair {
407        NameOptionTypePair {
408            name: name.to_string(),
409            typ,
410        }
411    }
412
413    pub fn unit_case(name: &str) -> NameOptionTypePair {
414        NameOptionTypePair {
415            name: name.to_string(),
416            typ: None,
417        }
418    }
419
420    pub fn bool() -> WitType {
421        WitType::Bool(TypeBool)
422    }
423
424    pub fn s8() -> WitType {
425        WitType::S8(TypeS8)
426    }
427
428    pub fn s16() -> WitType {
429        WitType::S16(TypeS16)
430    }
431
432    pub fn s32() -> WitType {
433        WitType::S32(TypeS32)
434    }
435
436    pub fn s64() -> WitType {
437        WitType::S64(TypeS64)
438    }
439
440    pub fn u8() -> WitType {
441        WitType::U8(TypeU8)
442    }
443
444    pub fn u16() -> WitType {
445        WitType::U16(TypeU16)
446    }
447
448    pub fn u32() -> WitType {
449        WitType::U32(TypeU32)
450    }
451
452    pub fn u64() -> WitType {
453        WitType::U64(TypeU64)
454    }
455
456    pub fn f32() -> WitType {
457        WitType::F32(TypeF32)
458    }
459
460    pub fn f64() -> WitType {
461        WitType::F64(TypeF64)
462    }
463
464    pub fn chr() -> WitType {
465        WitType::Chr(TypeChr)
466    }
467
468    pub fn str() -> WitType {
469        WitType::Str(TypeStr)
470    }
471
472    pub fn list(inner: WitType) -> WitType {
473        WitType::List(TypeList {
474            name: None,
475            owner: None,
476            inner: Box::new(inner),
477        })
478    }
479
480    pub fn option(inner: WitType) -> WitType {
481        WitType::Option(TypeOption {
482            name: None,
483            owner: None,
484            inner: Box::new(inner),
485        })
486    }
487
488    pub fn flags(names: &[&str]) -> WitType {
489        WitType::Flags(TypeFlags {
490            name: None,
491            owner: None,
492            names: names.iter().map(|n| n.to_string()).collect(),
493        })
494    }
495
496    pub fn r#enum(cases: &[&str]) -> WitType {
497        WitType::Enum(TypeEnum {
498            name: None,
499            owner: None,
500            cases: cases.iter().map(|n| n.to_string()).collect(),
501        })
502    }
503
504    pub fn tuple(items: Vec<WitType>) -> WitType {
505        WitType::Tuple(TypeTuple {
506            name: None,
507            owner: None,
508            items,
509        })
510    }
511
512    pub fn result(ok: WitType, err: WitType) -> WitType {
513        WitType::Result(TypeResult {
514            name: None,
515            owner: None,
516            ok: Some(Box::new(ok)),
517            err: Some(Box::new(err)),
518        })
519    }
520
521    pub fn result_ok(ok: WitType) -> WitType {
522        WitType::Result(TypeResult {
523            name: None,
524            owner: None,
525            ok: Some(Box::new(ok)),
526            err: None,
527        })
528    }
529
530    pub fn result_err(err: WitType) -> WitType {
531        WitType::Result(TypeResult {
532            name: None,
533            owner: None,
534            ok: None,
535            err: Some(Box::new(err)),
536        })
537    }
538
539    pub fn unit_result() -> WitType {
540        WitType::Result(TypeResult {
541            name: None,
542            owner: None,
543            ok: None,
544            err: None,
545        })
546    }
547
548    pub fn record(fields: Vec<NameTypePair>) -> WitType {
549        WitType::Record(TypeRecord {
550            name: None,
551            owner: None,
552            fields,
553        })
554    }
555
556    pub fn variant(cases: Vec<NameOptionTypePair>) -> WitType {
557        WitType::Variant(TypeVariant {
558            name: None,
559            owner: None,
560            cases,
561        })
562    }
563
564    pub fn handle(resource_id: AnalysedResourceId, mode: AnalysedResourceMode) -> WitType {
565        WitType::Handle(TypeHandle {
566            name: None,
567            owner: None,
568            resource_id,
569            mode,
570        })
571    }
572}
573
574// Re-export helper constructors at module root for ergonomic imports like
575// `use crate::wit_type::{record, option, str, ...}`.
576pub use builders::*;