1use std::{borrow::Cow, sync::Arc};
2
3use crate::wasm::{maybe_unwrap_type, WasmType, WasmTypeKind};
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 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 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 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 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 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 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 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 pub fn option(some: Self) -> Self {
110 Self(TypeEnum::Option(Arc::new(OptionType { some })))
111 }
112
113 pub fn result(ok: Option<Self>, err: Option<Self>) -> Self {
115 Self(TypeEnum::Result(Arc::new(ResultType { ok, err })))
116 }
117
118 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 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}