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