Skip to main content

rib/
wit_type.rs

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