1use alloc::{borrow::Cow, boxed::Box, sync::Arc};
2
3use crate::wasm::{WasmType, WasmTypeKind, maybe_unwrap_type};
4
5#[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 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 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 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 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 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 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 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 pub fn option(some: Self) -> Self {
121 Self(TypeEnum::Option(Arc::new(OptionType { some })))
122 }
123
124 pub fn result(ok: Option<Self>, err: Option<Self>) -> Self {
126 Self(TypeEnum::Result(Arc::new(ResultType { ok, err })))
127 }
128
129 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 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 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}