1use crate::{
2 value::ValueEnum,
3 wasm::{WasmType, WasmTypeKind},
4 WasmValue,
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 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15),
208 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)
209);
210
211#[cfg(test)]
212mod tests {
213 use crate::value::{Type, Value};
214
215 #[test]
216 fn type_conversion_round_trips() {
217 for ty in [
218 Type::BOOL,
219 Type::U8,
220 Type::F32,
221 Type::STRING,
222 Type::list(Type::BOOL),
223 Type::record([("a", Type::BOOL)]).unwrap(),
224 Type::tuple([Type::BOOL]).unwrap(),
225 Type::variant([("a", None), ("b", Some(Type::BOOL))]).unwrap(),
226 Type::enum_ty(["north", "south"]).unwrap(),
227 Type::option(Type::BOOL),
228 Type::result(Some(Type::BOOL), None),
229 Type::flags(["read", "write"]).unwrap(),
230 ] {
231 let got = Type::from_wasm_type(&ty).unwrap();
232 assert_eq!(got, ty);
233 }
234 }
235
236 #[test]
237 fn value_conversions() {
238 for (val, expect) in [
239 (1u8.into(), "1"),
240 ((-123i8).into(), "-123"),
241 (f32::NAN.into(), "nan"),
242 (f64::NEG_INFINITY.into(), "-inf"),
243 ('x'.into(), "'x'"),
244 ("str".into(), "\"str\""),
245 (vec![1, 2, 3].into(), "[1, 2, 3]"),
246 ([1, 2, 3].into(), "[1, 2, 3]"),
247 (['a'; 3].into(), "['a', 'a', 'a']"),
248 (Some(1).into(), "some(1)"),
249 (None::<u8>.into(), "none"),
250 (Ok::<u8, String>(1).into(), "ok(1)"),
251 (Err::<u8, String>("oops".into()).into(), "err(\"oops\")"),
252 ((1,).into(), "(1)"),
253 ((1, "str", [9; 2]).into(), "(1, \"str\", [9, 9])"),
254 ] {
255 let val: Value = val;
256 let got = crate::to_string(&val).unwrap();
257 assert_eq!(got, expect);
258 }
259 }
260}