1mod convert;
4#[cfg(test)]
5mod tests;
6mod ty;
7
8mod func;
9#[cfg(feature = "wit")]
10mod wit;
11
12use alloc::{
13 borrow::{Cow, ToOwned},
14 boxed::Box,
15 collections::BTreeMap,
16 sync::Arc,
17 vec::Vec,
18};
19#[cfg(feature = "wit")]
20pub use wit::{resolve_wit_func_type, resolve_wit_type};
21
22use crate::{
23 canonicalize_nan32, canonicalize_nan64,
24 wasm::{
25 WasmType, WasmTypeKind, WasmValue, WasmValueError, ensure_type_kind, maybe_unwrap_type,
26 unwrap_val,
27 },
28};
29
30use self::ty::{
31 EnumType, FlagsType, ListType, OptionType, RecordType, ResultType, TupleType, TypeEnum,
32 VariantType,
33};
34
35pub use self::func::FuncType;
36pub use self::ty::Type;
37
38#[derive(Debug, Clone, PartialEq)]
40pub struct Value(ValueEnum);
41
42#[derive(Debug, Clone, PartialEq)]
43pub(super) enum ValueEnum {
44 Bool(bool),
45 S8(i8),
46 U8(u8),
47 S16(i16),
48 U16(u16),
49 S32(i32),
50 U32(u32),
51 S64(i64),
52 U64(u64),
53 F32(f32),
54 F64(f64),
55 Char(char),
56 String(Box<str>),
57 List(List),
58 Record(Record),
59 Tuple(Tuple),
60 Variant(Variant),
61 Enum(Enum),
62 Option(OptionValue),
63 Result(ResultValue),
64 Flags(Flags),
65}
66
67#[derive(Debug, Clone, PartialEq)]
68#[doc(hidden)]
69pub struct List {
70 ty: Arc<ListType>,
71 elements: Vec<Value>,
72}
73
74#[derive(Debug, Clone, PartialEq)]
75#[doc(hidden)]
76pub struct Record {
77 ty: Arc<RecordType>,
78 fields: Vec<Value>,
79}
80
81#[derive(Debug, Clone, PartialEq)]
82#[doc(hidden)]
83pub struct Tuple {
84 ty: Arc<TupleType>,
85 elements: Vec<Value>,
86}
87
88#[derive(Debug, Clone, PartialEq)]
89#[doc(hidden)]
90pub struct Variant {
91 ty: Arc<VariantType>,
92 case: usize,
93 payload: Option<Box<Value>>,
94}
95
96#[derive(Debug, Clone, PartialEq)]
97#[doc(hidden)]
98pub struct Enum {
99 ty: Arc<EnumType>,
100 case: usize,
101}
102
103#[derive(Debug, Clone, PartialEq)]
104#[doc(hidden)]
105pub struct OptionValue {
106 ty: Arc<OptionType>,
107 value: Option<Box<Value>>,
108}
109
110#[derive(Debug, Clone, PartialEq)]
111#[doc(hidden)]
112pub struct ResultValue {
113 ty: Arc<ResultType>,
114 value: Result<Option<Box<Value>>, Option<Box<Value>>>,
115}
116
117#[derive(Debug, Clone, PartialEq)]
118#[doc(hidden)]
119pub struct Flags {
120 ty: Arc<FlagsType>,
121 flags: Vec<usize>,
122}
123
124macro_rules! impl_primitives {
125 ($Self:ident, $(($case:ident, $ty:ty, $make:ident, $unwrap:ident)),*) => {
126 $(
127 fn $make(val: $ty) -> $Self {
128 $Self(ValueEnum::$case(val))
129 }
130
131 fn $unwrap(&self) -> $ty {
132 *unwrap_val!(&self.0, ValueEnum::$case, stringify!($case))
133 }
134 )*
135 };
136}
137
138impl WasmValue for Value {
139 type Type = Type;
140
141 fn kind(&self) -> WasmTypeKind {
142 match &self.0 {
143 ValueEnum::Bool(_) => WasmTypeKind::Bool,
144 ValueEnum::S8(_) => WasmTypeKind::S8,
145 ValueEnum::S16(_) => WasmTypeKind::S16,
146 ValueEnum::S32(_) => WasmTypeKind::S32,
147 ValueEnum::S64(_) => WasmTypeKind::S64,
148 ValueEnum::U8(_) => WasmTypeKind::U8,
149 ValueEnum::U16(_) => WasmTypeKind::U16,
150 ValueEnum::U32(_) => WasmTypeKind::U32,
151 ValueEnum::U64(_) => WasmTypeKind::U64,
152 ValueEnum::F32(_) => WasmTypeKind::F32,
153 ValueEnum::F64(_) => WasmTypeKind::F64,
154 ValueEnum::Char(_) => WasmTypeKind::Char,
155 ValueEnum::String(_) => WasmTypeKind::String,
156 ValueEnum::List(_) => WasmTypeKind::List,
157 ValueEnum::Record(_) => WasmTypeKind::Record,
158 ValueEnum::Tuple(_) => WasmTypeKind::Tuple,
159 ValueEnum::Variant(_) => WasmTypeKind::Variant,
160 ValueEnum::Enum(_) => WasmTypeKind::Enum,
161 ValueEnum::Option(_) => WasmTypeKind::Option,
162 ValueEnum::Result(_) => WasmTypeKind::Result,
163 ValueEnum::Flags(_) => WasmTypeKind::Flags,
164 }
165 }
166
167 impl_primitives!(
168 Self,
169 (Bool, bool, make_bool, unwrap_bool),
170 (S8, i8, make_s8, unwrap_s8),
171 (S16, i16, make_s16, unwrap_s16),
172 (S32, i32, make_s32, unwrap_s32),
173 (S64, i64, make_s64, unwrap_s64),
174 (U8, u8, make_u8, unwrap_u8),
175 (U16, u16, make_u16, unwrap_u16),
176 (U32, u32, make_u32, unwrap_u32),
177 (U64, u64, make_u64, unwrap_u64),
178 (Char, char, make_char, unwrap_char)
179 );
180
181 fn make_f32(val: f32) -> Self {
182 let val = canonicalize_nan32(val);
183 Self(ValueEnum::F32(val))
184 }
185
186 fn make_f64(val: f64) -> Self {
187 let val = canonicalize_nan64(val);
188 Self(ValueEnum::F64(val))
189 }
190
191 fn make_string(val: alloc::borrow::Cow<str>) -> Self {
192 Self(ValueEnum::String(val.into()))
193 }
194
195 fn make_list(
196 ty: &Self::Type,
197 vals: impl IntoIterator<Item = Self>,
198 ) -> Result<Self, WasmValueError> {
199 ensure_type_kind(ty, WasmTypeKind::List)?;
200 let element_type = ty.list_element_type().unwrap();
201 let elements = vals
202 .into_iter()
203 .map(|v| check_type(&element_type, v))
204 .collect::<Result<_, _>>()?;
205 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::List).unwrap().clone();
206 Ok(Self(ValueEnum::List(List { ty, elements })))
207 }
208
209 fn make_record<'a>(
210 ty: &Self::Type,
211 fields: impl IntoIterator<Item = (&'a str, Self)>,
212 ) -> Result<Self, WasmValueError> {
213 ensure_type_kind(ty, WasmTypeKind::Record)?;
214 let mut field_vals: BTreeMap<_, _> = fields.into_iter().collect();
215 let mut fields = Vec::with_capacity(field_vals.len());
216 for (name, ty) in ty.record_fields() {
217 let val = field_vals
218 .remove(&*name)
219 .ok_or_else(|| WasmValueError::MissingField(name.into()))?;
220 fields.push(check_type(&ty, val)?);
221 }
222 if let Some(unknown) = field_vals.into_keys().next() {
223 return Err(WasmValueError::UnknownField(unknown.into()));
224 }
225 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Record).unwrap().clone();
226 Ok(Self(ValueEnum::Record(Record { ty, fields })))
227 }
228
229 fn make_tuple(
230 ty: &Self::Type,
231 vals: impl IntoIterator<Item = Self>,
232 ) -> Result<Self, WasmValueError> {
233 ensure_type_kind(ty, WasmTypeKind::Tuple)?;
234 let types = ty.tuple_element_types().collect::<Vec<_>>();
235 let elements = Vec::from_iter(vals);
236 if types.len() != elements.len() {
237 return Err(WasmValueError::WrongNumberOfTupleValues {
238 want: types.len(),
239 got: elements.len(),
240 });
241 }
242 for (ty, val) in types.iter().zip(&elements) {
243 check_type2(ty, val)?;
244 }
245 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Tuple).unwrap().clone();
246 Ok(Self(ValueEnum::Tuple(Tuple { ty, elements })))
247 }
248
249 fn make_variant(
250 ty: &Self::Type,
251 case_name: &str,
252 val: Option<Self>,
253 ) -> Result<Self, WasmValueError> {
254 ensure_type_kind(ty, WasmTypeKind::Variant)?;
255 let (case, payload_type) = ty
256 .variant_cases()
257 .enumerate()
258 .find_map(|(idx, (name, ty))| (name == case_name).then_some((idx, ty)))
259 .ok_or_else(|| WasmValueError::UnknownCase(case_name.into()))?;
260 let payload = check_payload_type(case_name, &payload_type, val)?;
261 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Variant)
262 .unwrap()
263 .clone();
264 Ok(Self(ValueEnum::Variant(Variant { ty, case, payload })))
265 }
266
267 fn make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError> {
268 ensure_type_kind(ty, WasmTypeKind::Enum)?;
269 let case = ty
270 .enum_cases()
271 .position(|name| name == case)
272 .ok_or_else(|| WasmValueError::UnknownCase(case.into()))?;
273 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Enum).unwrap().clone();
274 Ok(Self(ValueEnum::Enum(Enum { ty, case })))
275 }
276
277 fn make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError> {
278 ensure_type_kind(ty, WasmTypeKind::Option)?;
279 let value = match val {
280 Some(val) => Some(Box::new(check_type(&ty.option_some_type().unwrap(), val)?)),
281 None => None,
282 };
283 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Option).unwrap().clone();
284 Ok(Self(ValueEnum::Option(OptionValue { ty, value })))
285 }
286
287 fn make_result(
288 ty: &Self::Type,
289 val: Result<Option<Self>, Option<Self>>,
290 ) -> Result<Self, WasmValueError> {
291 ensure_type_kind(ty, WasmTypeKind::Result)?;
292 let (ok_type, err_type) = ty.result_types().unwrap();
293 let value = match val {
294 Ok(ok) => Ok(check_payload_type("ok", &ok_type, ok)?),
295 Err(err) => Err(check_payload_type("err", &err_type, err)?),
296 };
297 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Result).unwrap().clone();
298 Ok(Self(ValueEnum::Result(ResultValue { ty, value })))
299 }
300
301 fn make_flags<'a>(
302 ty: &Self::Type,
303 names: impl IntoIterator<Item = &'a str>,
304 ) -> Result<Self, WasmValueError> {
305 ensure_type_kind(ty, WasmTypeKind::Flags)?;
306 let flag_names = ty.flags_names().collect::<Vec<_>>();
307 let mut flags = names
308 .into_iter()
309 .map(|name| {
310 flag_names
311 .iter()
312 .position(|flag| flag == name)
313 .ok_or_else(|| WasmValueError::UnknownCase(name.into()))
314 })
315 .collect::<Result<Vec<_>, WasmValueError>>()?;
316 flags.sort();
319 let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Flags).unwrap().clone();
320 Ok(Self(ValueEnum::Flags(Flags { ty, flags })))
321 }
322
323 fn unwrap_f32(&self) -> f32 {
324 let val = *unwrap_val!(&self.0, ValueEnum::F32, "f32");
325 canonicalize_nan32(val)
326 }
327
328 fn unwrap_f64(&self) -> f64 {
329 let val = *unwrap_val!(&self.0, ValueEnum::F64, "f64");
330 canonicalize_nan64(val)
331 }
332
333 fn unwrap_string(&self) -> alloc::borrow::Cow<'_, str> {
334 unwrap_val!(&self.0, ValueEnum::String, "string")
335 .as_ref()
336 .into()
337 }
338 fn unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
339 let list = unwrap_val!(&self.0, ValueEnum::List, "list");
340 Box::new(list.elements.iter().map(cow))
341 }
342 fn unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_> {
343 let record = unwrap_val!(&self.0, ValueEnum::Record, "record");
344 Box::new(
345 record
346 .ty
347 .fields
348 .iter()
349 .map(|(name, _)| cow(name.as_ref()))
350 .zip(record.fields.iter().map(cow)),
351 )
352 }
353 fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
354 let tuple = unwrap_val!(&self.0, ValueEnum::Tuple, "tuple");
355 Box::new(tuple.elements.iter().map(cow))
356 }
357 fn unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>) {
358 let variant = unwrap_val!(&self.0, ValueEnum::Variant, "variant");
359 let (ref name, _) = variant.ty.cases[variant.case];
360 (cow(name.as_ref()), variant.payload.as_deref().map(cow))
361 }
362 fn unwrap_enum(&self) -> Cow<'_, str> {
363 let enum_ = unwrap_val!(&self.0, ValueEnum::Enum, "enum");
364 cow(enum_.ty.cases[enum_.case].as_ref())
365 }
366 fn unwrap_option(&self) -> Option<Cow<'_, Self>> {
367 unwrap_val!(&self.0, ValueEnum::Option, "option")
368 .value
369 .as_ref()
370 .map(|v| cow(v.as_ref()))
371 }
372 fn unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>> {
373 match &unwrap_val!(&self.0, ValueEnum::Result, "result").value {
374 Ok(val) => Ok(val.as_deref().map(cow)),
375 Err(val) => Err(val.as_deref().map(cow)),
376 }
377 }
378 fn unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
379 let flags = unwrap_val!(&self.0, ValueEnum::Flags, "flags");
380 Box::new(
381 flags
382 .flags
383 .iter()
384 .map(|idx| cow(flags.ty.flags[*idx].as_ref())),
385 )
386 }
387}
388
389fn cow<T: ToOwned + ?Sized>(t: &T) -> Cow<'_, T> {
390 Cow::Borrowed(t)
391}
392
393fn check_type(expected: &Type, val: Value) -> Result<Value, WasmValueError> {
394 check_type2(expected, &val)?;
395 Ok(val)
396}
397
398fn check_type2(expected: &Type, val: &Value) -> Result<(), WasmValueError> {
399 let wrong_value_type =
400 || -> Result<(), WasmValueError> { Err(WasmValueError::wrong_value_type(expected, val)) };
401
402 match (&val.0, expected) {
403 (ValueEnum::Bool(_), &Type::BOOL) => {}
404 (ValueEnum::S8(_), &Type::S8) => {}
405 (ValueEnum::S16(_), &Type::S16) => {}
406 (ValueEnum::S32(_), &Type::S32) => {}
407 (ValueEnum::S64(_), &Type::S64) => {}
408 (ValueEnum::U8(_), &Type::U8) => {}
409 (ValueEnum::U16(_), &Type::U16) => {}
410 (ValueEnum::U32(_), &Type::U32) => {}
411 (ValueEnum::U64(_), &Type::U64) => {}
412 (ValueEnum::F32(_), &Type::F32) => {}
413 (ValueEnum::F64(_), &Type::F64) => {}
414 (ValueEnum::Char(_), &Type::CHAR) => {}
415 (ValueEnum::String(_), &Type::STRING) => {}
416 (ValueEnum::List(list), _) => {
417 if let TypeEnum::List(list_type) = &expected.0 {
418 let ty = &list_type.element;
419 if ty != &list.ty.element {
420 return wrong_value_type();
421 }
422 for v in &list.elements {
423 check_type2(ty, v)?;
424 }
425 } else {
426 return wrong_value_type();
427 }
428 }
429 (ValueEnum::Record(record), _) => {
430 if let TypeEnum::Record(record_type) = &expected.0 {
431 if record.ty.as_ref() != record_type.as_ref() {
432 return wrong_value_type();
433 }
434 let expected_element_types = &record_type.fields;
435 if expected_element_types != &record.ty.fields {
436 return wrong_value_type();
437 }
438 if expected_element_types.len() != record.fields.len() {
439 return wrong_value_type();
440 }
441
442 for (field_ty, val) in expected_element_types.as_ref().iter().zip(&record.fields) {
443 check_type2(&field_ty.1, val)?;
444 }
445 } else {
446 return wrong_value_type();
447 }
448 }
449 (ValueEnum::Tuple(tuple), _) => {
450 if let TypeEnum::Tuple(tuple_type) = &expected.0 {
451 let expected_element_types = &tuple_type.elements;
452 if expected_element_types != &tuple.ty.elements {
453 return wrong_value_type();
454 }
455 if expected_element_types.len() != tuple.elements.len() {
456 return wrong_value_type();
457 }
458
459 for (ty, val) in expected_element_types.as_ref().iter().zip(&tuple.elements) {
460 check_type2(ty, val)?;
461 }
462 } else {
463 return wrong_value_type();
464 }
465 }
466 (ValueEnum::Variant(variant), _) => {
467 if let TypeEnum::Variant(variant_type) = &expected.0 {
468 if variant.ty.cases != variant_type.cases {
469 return wrong_value_type();
470 }
471 if variant.case >= variant.ty.cases.len() {
472 return wrong_value_type();
473 }
474 match (&variant.ty.cases[variant.case].1, &variant.payload) {
475 (None, None) => {}
476 (Some(t), Some(v)) => check_type2(t, v)?,
477 _ => return wrong_value_type(),
478 }
479 } else {
480 return wrong_value_type();
481 }
482 }
483 (ValueEnum::Enum(enm), _) => {
484 if let TypeEnum::Enum(enum_type) = &expected.0 {
485 if enm.case >= enm.ty.cases.len() {
486 return wrong_value_type();
487 }
488 if enm.ty.cases != enum_type.cases {
489 return wrong_value_type();
490 }
491 } else {
492 return wrong_value_type();
493 }
494 }
495 (ValueEnum::Option(option), _) => {
496 if let TypeEnum::Option(option_type) = &expected.0 {
497 if option.ty.as_ref().some != option_type.some {
498 return wrong_value_type();
499 }
500 if let Some(v) = option.value.as_ref() {
501 check_type2(&option_type.some, v)?;
502 }
503 } else {
504 return wrong_value_type();
505 }
506 }
507 (ValueEnum::Result(result), _) => {
508 if let TypeEnum::Result(result_type) = &expected.0 {
509 if result.ty.as_ref() != result_type.as_ref() {
510 return wrong_value_type();
511 }
512 match &result.value {
513 Ok(o) => match (&o, &result_type.ok) {
514 (None, None) => {}
515 (Some(v), Some(t)) => check_type2(t, v)?,
516 _ => return wrong_value_type(),
517 },
518 Err(e) => match (&e, &result_type.err) {
519 (None, None) => {}
520 (Some(v), Some(t)) => check_type2(t, v)?,
521 _ => return wrong_value_type(),
522 },
523 }
524 } else {
525 return wrong_value_type();
526 }
527 }
528 (ValueEnum::Flags(flags), _) => {
529 if let TypeEnum::Flags(flags_type) = &expected.0 {
530 if flags.ty.as_ref() != flags_type.as_ref() {
531 return wrong_value_type();
532 }
533 for flag in &flags.flags {
534 if *flag >= flags.ty.as_ref().flags.len() {
535 return wrong_value_type();
536 }
537 }
538 } else {
539 return wrong_value_type();
540 }
541 }
542 (_, _) => return wrong_value_type(),
543 };
544 Ok(())
545}
546
547fn check_payload_type(
548 name: &str,
549 expected: &Option<Type>,
550 val: Option<Value>,
551) -> Result<Option<Box<Value>>, WasmValueError> {
552 match (expected, val) {
553 (Some(payload_type), Some(val)) => Ok(Some(Box::new(check_type(payload_type, val)?))),
554 (None, None) => Ok(None),
555 (Some(_), None) => Err(WasmValueError::MissingPayload(name.into())),
556 (None, Some(_)) => Err(WasmValueError::UnexpectedPayload(name.into())),
557 }
558}