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