1use crate::{
2 WasmValue,
3 value::ValueEnum,
4 wasm::{WasmType, WasmTypeKind},
5};
6
7use super::{Type, Value};
8
9pub fn from_wasm_type(ty: &impl WasmType) -> Option<Type> {
10 if let Some(ty) = Type::simple(ty.kind()) {
11 return Some(ty);
12 }
13 Some(match ty.kind() {
14 WasmTypeKind::List => Type::list(from_wasm_type(&ty.list_element_type()?)?),
15 WasmTypeKind::Record => Type::record(
16 ty.record_fields()
17 .map(|(name, ty)| Some((name, from_wasm_type(&ty)?)))
18 .collect::<Option<Vec<_>>>()?,
19 )?,
20 WasmTypeKind::Tuple => Type::tuple(
21 ty.tuple_element_types()
22 .map(|ty| from_wasm_type(&ty))
23 .collect::<Option<Vec<_>>>()?,
24 )?,
25 WasmTypeKind::Variant => Type::variant(
26 ty.variant_cases()
27 .map(|(name, payload)| Some((name, from_optional_wasm_type(payload)?)))
28 .collect::<Option<Vec<_>>>()?,
29 )?,
30 WasmTypeKind::Enum => Type::enum_ty(ty.enum_cases())?,
31 WasmTypeKind::Option => Type::option(from_wasm_type(&ty.option_some_type()?)?),
32 WasmTypeKind::Result => {
33 let (ok, err) = ty.result_types()?;
34 Type::result(from_optional_wasm_type(ok)?, from_optional_wasm_type(err)?)
35 }
36 WasmTypeKind::Flags => Type::flags(ty.flags_names())?,
37 _ => return None,
38 })
39}
40
41fn from_optional_wasm_type(ty: Option<impl WasmType>) -> Option<Option<Type>> {
42 Some(match ty {
43 Some(ty) => Some(from_wasm_type(&ty)?),
44 None => None,
45 })
46}
47
48trait ValueTyped {
49 fn value_type() -> Type;
50}
51
52macro_rules! impl_primitives {
53 ($Self:ty, $(($case:ident, $ty:ty)),*) => {
54 $(
55 impl ValueTyped for $ty {
56 fn value_type() -> Type {
57 Type::must_simple(WasmTypeKind::$case)
58 }
59 }
60
61 impl From<$ty> for $Self {
62 fn from(value: $ty) -> Self {
63 Self(ValueEnum::$case(value))
64 }
65 }
66 )*
67 };
68}
69
70impl_primitives!(
71 Value,
72 (Bool, bool),
73 (S8, i8),
74 (S16, i16),
75 (S32, i32),
76 (S64, i64),
77 (U8, u8),
78 (U16, u16),
79 (U32, u32),
80 (U64, u64),
81 (F32, f32),
82 (F64, f64),
83 (Char, char)
84);
85
86impl ValueTyped for String {
87 fn value_type() -> Type {
88 Type::STRING
89 }
90}
91
92impl From<String> for Value {
93 fn from(value: String) -> Self {
94 Self(ValueEnum::String(value.into()))
95 }
96}
97
98impl ValueTyped for &str {
99 fn value_type() -> Type {
100 String::value_type()
101 }
102}
103
104impl<'a> From<&'a str> for Value {
105 fn from(value: &'a str) -> Self {
106 value.to_string().into()
107 }
108}
109
110impl<const N: usize, T: ValueTyped> ValueTyped for [T; N] {
111 fn value_type() -> Type {
112 Type::list(T::value_type())
113 }
114}
115
116impl<const N: usize, T: ValueTyped + Into<Value>> From<[T; N]> for Value {
117 fn from(values: [T; N]) -> Self {
118 let ty = Vec::<T>::value_type();
119 let values = values.into_iter().map(Into::into);
120 Value::make_list(&ty, values).unwrap()
121 }
122}
123
124impl<T: ValueTyped> ValueTyped for Vec<T> {
125 fn value_type() -> Type {
126 Type::list(T::value_type())
127 }
128}
129
130impl<T: ValueTyped + Into<Value>> From<Vec<T>> for Value {
131 fn from(values: Vec<T>) -> Self {
132 let ty = Vec::<T>::value_type();
133 let values = values.into_iter().map(Into::into);
134 Value::make_list(&ty, values).unwrap()
135 }
136}
137
138impl<T: ValueTyped> ValueTyped for Option<T> {
139 fn value_type() -> Type {
140 Type::option(T::value_type())
141 }
142}
143
144impl<T: ValueTyped + Into<Value>> From<Option<T>> for Value {
145 fn from(value: Option<T>) -> Self {
146 let ty = Option::<T>::value_type();
147 Value::make_option(&ty, value.map(Into::into)).unwrap()
148 }
149}
150
151impl<T: ValueTyped, U: ValueTyped> ValueTyped for Result<T, U> {
152 fn value_type() -> Type {
153 Type::result(Some(T::value_type()), Some(U::value_type()))
154 }
155}
156
157impl<T: ValueTyped + Into<Value>, U: ValueTyped + Into<Value>> From<Result<T, U>> for Value {
158 fn from(value: Result<T, U>) -> Self {
159 let ty = Result::<T, U>::value_type();
160 let value = match value {
161 Ok(ok) => Ok(Some(ok.into())),
162 Err(err) => Err(Some(err.into())),
163 };
164 Value::make_result(&ty, value).unwrap()
165 }
166}
167
168macro_rules! impl_tuple {
169 ($(($($var:ident),*)),*) => {
170 $(
171 impl<$($var: ValueTyped),*> ValueTyped for ($($var),*,) {
172 fn value_type() -> Type {
173 Type::tuple(vec![$($var::value_type()),*]).unwrap()
174 }
175 }
176
177 #[allow(non_snake_case)]
178 impl<$($var: ValueTyped + Into<Value>),*> From<($($var),*,)> for Value {
179 fn from(($($var),*,): ($($var),*,)) -> Value {
180 let ty = <($($var),*,)>::value_type();
181 $(
182 let $var = $var.into();
183 )*
184 Value::make_tuple(&ty, vec![$($var),*]).unwrap()
185 }
186 }
187
188 )*
189 };
190}
191
192impl_tuple!(
193 (T1),
194 (T1, T2),
195 (T1, T2, T3),
196 (T1, T2, T3, T4),
197 (T1, T2, T3, T4, T5),
198 (T1, T2, T3, T4, T5, T6),
199 (T1, T2, T3, T4, T5, T6, T7),
200 (T1, T2, T3, T4, T5, T6, T7, T8),
201 (T1, T2, T3, T4, T5, T6, T7, T8, T9),
202 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
203 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
204 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
205 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13),
206 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14),
207 (
208 T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
209 ),
210 (
211 T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
212 )
213);
214
215#[cfg(test)]
216mod tests {
217 use crate::value::{Type, Value};
218
219 #[test]
220 fn type_conversion_round_trips() {
221 for ty in [
222 Type::BOOL,
223 Type::U8,
224 Type::F32,
225 Type::STRING,
226 Type::list(Type::BOOL),
227 Type::record([("a", Type::BOOL)]).unwrap(),
228 Type::tuple([Type::BOOL]).unwrap(),
229 Type::variant([("a", None), ("b", Some(Type::BOOL))]).unwrap(),
230 Type::enum_ty(["north", "south"]).unwrap(),
231 Type::option(Type::BOOL),
232 Type::result(Some(Type::BOOL), None),
233 Type::flags(["read", "write"]).unwrap(),
234 ] {
235 let got = Type::from_wasm_type(&ty).unwrap();
236 assert_eq!(got, ty);
237 }
238 }
239
240 #[test]
241 fn value_conversions() {
242 for (val, expect) in [
243 (1u8.into(), "1"),
244 ((-123i8).into(), "-123"),
245 (f32::NAN.into(), "nan"),
246 (f64::NEG_INFINITY.into(), "-inf"),
247 ('x'.into(), "'x'"),
248 ("str".into(), "\"str\""),
249 (vec![1, 2, 3].into(), "[1, 2, 3]"),
250 ([1, 2, 3].into(), "[1, 2, 3]"),
251 (['a'; 3].into(), "['a', 'a', 'a']"),
252 (Some(1).into(), "some(1)"),
253 (None::<u8>.into(), "none"),
254 (Ok::<u8, String>(1).into(), "ok(1)"),
255 (Err::<u8, String>("oops".into()).into(), "err(\"oops\")"),
256 ((1,).into(), "(1)"),
257 ((1, "str", [9; 2]).into(), "(1, \"str\", [9, 9])"),
258 ] {
259 let val: Value = val;
260 let got = crate::to_string(&val).unwrap();
261 assert_eq!(got, expect);
262 }
263 }
264}