wasm_wave/value/
ty.rs

1use std::{borrow::Cow, sync::Arc};
2
3use crate::wasm::{maybe_unwrap_type, WasmType, WasmTypeKind};
4
5/// The [`WasmType`] of a [`Value`](super::Value).
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Type(pub(super) TypeEnum);
8
9#[derive(Clone, Debug, PartialEq, Eq)]
10pub(super) enum TypeEnum {
11    Simple(SimpleType),
12    List(Arc<ListType>),
13    Record(Arc<RecordType>),
14    Tuple(Arc<TupleType>),
15    Variant(Arc<VariantType>),
16    Enum(Arc<EnumType>),
17    Option(Arc<OptionType>),
18    Result(Arc<ResultType>),
19    Flags(Arc<FlagsType>),
20}
21
22#[allow(missing_docs)]
23impl Type {
24    pub const BOOL: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::Bool)));
25    pub const S8: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::S8)));
26    pub const S16: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::S16)));
27    pub const S32: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::S32)));
28    pub const S64: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::S64)));
29    pub const U8: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::U8)));
30    pub const U16: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::U16)));
31    pub const U32: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::U32)));
32    pub const U64: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::U64)));
33    pub const F32: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::F32)));
34    pub const F64: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::F64)));
35    pub const CHAR: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::Char)));
36    pub const STRING: Self = Self(TypeEnum::Simple(SimpleType(WasmTypeKind::String)));
37
38    /// Returns the simple type of the given `kind`. Returns None if the kind
39    /// represents a parameterized type.
40    pub fn simple(kind: WasmTypeKind) -> Option<Self> {
41        is_simple(kind).then_some(Self(TypeEnum::Simple(SimpleType(kind))))
42    }
43
44    #[doc(hidden)]
45    pub const fn must_simple(kind: WasmTypeKind) -> Self {
46        if !is_simple(kind) {
47            panic!("kind is not simple");
48        }
49        Self(TypeEnum::Simple(SimpleType(kind)))
50    }
51
52    /// Returns a list type with the given element type.
53    pub fn list(element_type: impl Into<Self>) -> Self {
54        let element = element_type.into();
55        Self(TypeEnum::List(Arc::new(ListType { element })))
56    }
57
58    /// Returns a record type with the given field types. Returns None if
59    /// `fields` is empty.
60    pub fn record<T: Into<Box<str>>>(
61        field_types: impl IntoIterator<Item = (T, Self)>,
62    ) -> Option<Self> {
63        let fields = field_types
64            .into_iter()
65            .map(|(name, ty)| (name.into(), ty))
66            .collect::<Box<[_]>>();
67        if fields.is_empty() {
68            return None;
69        }
70        Some(Self(TypeEnum::Record(Arc::new(RecordType { fields }))))
71    }
72
73    /// Returns a tuple type with the given element types. Returns None if
74    /// `element_types` is empty.
75    pub fn tuple(element_types: impl Into<Box<[Self]>>) -> Option<Self> {
76        let elements = element_types.into();
77        if elements.is_empty() {
78            return None;
79        }
80        Some(Self(TypeEnum::Tuple(Arc::new(TupleType { elements }))))
81    }
82
83    /// Returns a variant type with the given case names and optional payloads.
84    /// Returns None if `cases` is empty.
85    pub fn variant<T: Into<Box<str>>>(
86        cases: impl IntoIterator<Item = (T, Option<Self>)>,
87    ) -> Option<Self> {
88        let cases = cases
89            .into_iter()
90            .map(|(name, ty)| (name.into(), ty))
91            .collect::<Box<[_]>>();
92        if cases.is_empty() {
93            return None;
94        }
95        Some(Self(TypeEnum::Variant(Arc::new(VariantType { cases }))))
96    }
97
98    /// Returns an enum type with the given case names. Returns None if `cases`
99    /// is empty.
100    pub fn enum_ty<T: Into<Box<str>>>(cases: impl IntoIterator<Item = T>) -> Option<Self> {
101        let cases = cases.into_iter().map(Into::into).collect::<Box<[_]>>();
102        if cases.is_empty() {
103            return None;
104        }
105        Some(Self(TypeEnum::Enum(Arc::new(EnumType { cases }))))
106    }
107
108    /// Returns an option type with the given "some" type.
109    pub fn option(some: Self) -> Self {
110        Self(TypeEnum::Option(Arc::new(OptionType { some })))
111    }
112
113    /// Returns a result type with the given optional "ok" and "err" payloads.
114    pub fn result(ok: Option<Self>, err: Option<Self>) -> Self {
115        Self(TypeEnum::Result(Arc::new(ResultType { ok, err })))
116    }
117
118    /// Returns a flags type with the given flag names. Returns None if `flags`
119    /// is empty.
120    pub fn flags<T: Into<Box<str>>>(flags: impl IntoIterator<Item = T>) -> Option<Self> {
121        let flags = flags.into_iter().map(Into::into).collect::<Box<[_]>>();
122        if flags.is_empty() {
123            return None;
124        }
125        Some(Self(TypeEnum::Flags(Arc::new(FlagsType { flags }))))
126    }
127
128    /// Returns a [`Type`] matching the given [`WasmType`]. Returns None if the
129    /// given type is unsupported or otherwise invalid.
130    pub fn from_wasm_type(ty: &impl WasmType) -> Option<Self> {
131        super::convert::from_wasm_type(ty)
132    }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub struct SimpleType(WasmTypeKind);
137
138const fn is_simple(kind: WasmTypeKind) -> bool {
139    use WasmTypeKind::*;
140    matches!(
141        kind,
142        Bool | S8 | S16 | S32 | S64 | U8 | U16 | U32 | U64 | F32 | F64 | Char | String
143    )
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct ListType {
148    pub(super) element: Type,
149}
150
151#[derive(Debug, PartialEq, Eq)]
152pub struct RecordType {
153    pub(super) fields: Box<[(Box<str>, Type)]>,
154}
155
156#[derive(Debug, PartialEq, Eq)]
157pub struct TupleType {
158    pub(super) elements: Box<[Type]>,
159}
160
161#[derive(Debug, PartialEq, Eq)]
162pub struct VariantType {
163    pub(super) cases: Box<[(Box<str>, Option<Type>)]>,
164}
165
166#[derive(Debug, PartialEq, Eq)]
167pub struct EnumType {
168    pub(super) cases: Box<[Box<str>]>,
169}
170
171#[derive(Debug, PartialEq, Eq)]
172pub struct OptionType {
173    pub(super) some: Type,
174}
175
176#[derive(Debug, PartialEq, Eq)]
177pub struct ResultType {
178    pub(super) ok: Option<Type>,
179    pub(super) err: Option<Type>,
180}
181
182#[derive(Debug, PartialEq, Eq)]
183pub struct FlagsType {
184    pub(super) flags: Box<[Box<str>]>,
185}
186
187impl WasmType for Type {
188    fn kind(&self) -> WasmTypeKind {
189        match self.0 {
190            TypeEnum::Simple(simple) => simple.0,
191            TypeEnum::List(_) => WasmTypeKind::List,
192            TypeEnum::Record(_) => WasmTypeKind::Record,
193            TypeEnum::Tuple(_) => WasmTypeKind::Tuple,
194            TypeEnum::Variant(_) => WasmTypeKind::Variant,
195            TypeEnum::Enum(_) => WasmTypeKind::Enum,
196            TypeEnum::Option(_) => WasmTypeKind::Option,
197            TypeEnum::Result(_) => WasmTypeKind::Result,
198            TypeEnum::Flags(_) => WasmTypeKind::Flags,
199        }
200    }
201
202    fn list_element_type(&self) -> Option<Self> {
203        let list = maybe_unwrap_type!(&self.0, TypeEnum::List)?;
204        Some(list.element.clone())
205    }
206
207    fn record_fields(&self) -> Box<dyn Iterator<Item = (Cow<str>, Self)> + '_> {
208        let TypeEnum::Record(record) = &self.0 else {
209            return Box::new(std::iter::empty());
210        };
211        Box::new(
212            record
213                .fields
214                .iter()
215                .map(|(name, ty)| (name.as_ref().into(), ty.clone())),
216        )
217    }
218
219    fn tuple_element_types(&self) -> Box<dyn Iterator<Item = Self> + '_> {
220        let TypeEnum::Tuple(tuple) = &self.0 else {
221            return Box::new(std::iter::empty());
222        };
223        Box::new(tuple.elements.iter().cloned())
224    }
225
226    fn variant_cases(&self) -> Box<dyn Iterator<Item = (Cow<str>, Option<Self>)> + '_> {
227        let TypeEnum::Variant(variant) = &self.0 else {
228            return Box::new(std::iter::empty());
229        };
230        Box::new(
231            variant
232                .cases
233                .iter()
234                .map(|(name, ty)| (name.as_ref().into(), ty.clone())),
235        )
236    }
237
238    fn enum_cases(&self) -> Box<dyn Iterator<Item = Cow<str>> + '_> {
239        let TypeEnum::Enum(enum_) = &self.0 else {
240            return Box::new(std::iter::empty());
241        };
242        Box::new(enum_.cases.iter().map(|name| name.as_ref().into()))
243    }
244
245    fn option_some_type(&self) -> Option<Self> {
246        let option = maybe_unwrap_type!(&self.0, TypeEnum::Option)?;
247        Some(option.some.clone())
248    }
249
250    fn result_types(&self) -> Option<(Option<Self>, Option<Self>)> {
251        let result = maybe_unwrap_type!(&self.0, TypeEnum::Result)?;
252        Some((result.ok.clone(), result.err.clone()))
253    }
254
255    fn flags_names(&self) -> Box<dyn Iterator<Item = Cow<str>> + '_> {
256        let TypeEnum::Flags(flags) = &self.0 else {
257            return Box::new(std::iter::empty());
258        };
259        Box::new(flags.flags.iter().map(|name| name.as_ref().into()))
260    }
261}
262
263impl std::fmt::Display for Type {
264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265        crate::wasm::DisplayType(self).fmt(f)
266    }
267}