Skip to main content

wasm_wave/value/
ty.rs

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