wasm_wave/value/
ty.rs

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