1use std::{borrow::Cow, 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 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 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 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 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 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 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 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 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 pub fn option(some: Self) -> Self {
120 Self(TypeEnum::Option(Arc::new(OptionType { some })))
121 }
122
123 pub fn result(ok: Option<Self>, err: Option<Self>) -> Self {
125 Self(TypeEnum::Result(Arc::new(ResultType { ok, err })))
126 }
127
128 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 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}