1use crate::ValRaw;
2use crate::component::ResourceAny;
3use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc};
4use crate::prelude::*;
5use core::mem::MaybeUninit;
6use core::slice::{Iter, IterMut};
7use wasmtime_component_util::{DiscriminantSize, FlagsSize};
8use wasmtime_environ::component::{
9 CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeOption, TypeResult,
10 TypeVariant, VariantInfo,
11};
12
13#[derive(Debug, Clone)]
65#[allow(missing_docs)]
66pub enum Val {
67 Bool(bool),
68 S8(i8),
69 U8(u8),
70 S16(i16),
71 U16(u16),
72 S32(i32),
73 U32(u32),
74 S64(i64),
75 U64(u64),
76 Float32(f32),
77 Float64(f64),
78 Char(char),
79 String(String),
80 List(Vec<Val>),
81 Record(Vec<(String, Val)>),
82 Tuple(Vec<Val>),
83 Variant(String, Option<Box<Val>>),
84 Enum(String),
85 Option(Option<Box<Val>>),
86 Result(Result<Option<Box<Val>>, Option<Box<Val>>>),
87 Flags(Vec<String>),
88 Resource(ResourceAny),
89}
90
91impl Val {
92 pub(crate) fn lift(
94 cx: &mut LiftContext<'_>,
95 ty: InterfaceType,
96 src: &mut Iter<'_, ValRaw>,
97 ) -> Result<Val> {
98 Ok(match ty {
99 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_flat(cx, ty, next(src))?),
100 InterfaceType::S8 => Val::S8(i8::linear_lift_from_flat(cx, ty, next(src))?),
101 InterfaceType::U8 => Val::U8(u8::linear_lift_from_flat(cx, ty, next(src))?),
102 InterfaceType::S16 => Val::S16(i16::linear_lift_from_flat(cx, ty, next(src))?),
103 InterfaceType::U16 => Val::U16(u16::linear_lift_from_flat(cx, ty, next(src))?),
104 InterfaceType::S32 => Val::S32(i32::linear_lift_from_flat(cx, ty, next(src))?),
105 InterfaceType::U32 => Val::U32(u32::linear_lift_from_flat(cx, ty, next(src))?),
106 InterfaceType::S64 => Val::S64(i64::linear_lift_from_flat(cx, ty, next(src))?),
107 InterfaceType::U64 => Val::U64(u64::linear_lift_from_flat(cx, ty, next(src))?),
108 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_flat(cx, ty, next(src))?),
109 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_flat(cx, ty, next(src))?),
110 InterfaceType::Char => Val::Char(char::linear_lift_from_flat(cx, ty, next(src))?),
111 InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
112 Val::Resource(ResourceAny::linear_lift_from_flat(cx, ty, next(src))?)
113 }
114 InterfaceType::String => Val::String(<_>::linear_lift_from_flat(
115 cx,
116 ty,
117 &[*next(src), *next(src)],
118 )?),
119 InterfaceType::List(i) => {
120 let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
122 let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
123 load_list(cx, i, ptr, len)?
124 }
125 InterfaceType::Record(i) => Val::Record(
126 cx.types[i]
127 .fields
128 .iter()
129 .map(|field| {
130 let val = Self::lift(cx, field.ty, src)?;
131 Ok((field.name.to_string(), val))
132 })
133 .collect::<Result<_>>()?,
134 ),
135 InterfaceType::Tuple(i) => Val::Tuple(
136 cx.types[i]
137 .types
138 .iter()
139 .map(|ty| Self::lift(cx, *ty, src))
140 .collect::<Result<_>>()?,
141 ),
142 InterfaceType::Variant(i) => {
143 let vty = &cx.types[i];
144 let (discriminant, value) = lift_variant(
145 cx,
146 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
147 vty.cases.values().copied(),
148 src,
149 )?;
150
151 let (k, _) = vty.cases.get_index(discriminant as usize).unwrap();
152 Val::Variant(k.clone(), value)
153 }
154 InterfaceType::Enum(i) => {
155 let ety = &cx.types[i];
156 let (discriminant, _) = lift_variant(
157 cx,
158 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
159 ety.names.iter().map(|_| None),
160 src,
161 )?;
162
163 Val::Enum(ety.names[discriminant as usize].clone())
164 }
165 InterfaceType::Option(i) => {
166 let (_discriminant, value) = lift_variant(
167 cx,
168 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
169 [None, Some(cx.types[i].ty)].into_iter(),
170 src,
171 )?;
172
173 Val::Option(value)
174 }
175 InterfaceType::Result(i) => {
176 let result_ty = &cx.types[i];
177 let (discriminant, value) = lift_variant(
178 cx,
179 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
180 [result_ty.ok, result_ty.err].into_iter(),
181 src,
182 )?;
183
184 Val::Result(if discriminant == 0 {
185 Ok(value)
186 } else {
187 Err(value)
188 })
189 }
190 InterfaceType::Flags(i) => {
191 let u32_count = cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap();
192 let ty = &cx.types[i];
193 let mut flags = Vec::new();
194 for i in 0..u32::try_from(u32_count).unwrap() {
195 push_flags(
196 ty,
197 &mut flags,
198 i * 32,
199 u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))?,
200 );
201 }
202
203 Val::Flags(flags)
204 }
205 InterfaceType::Future(_)
206 | InterfaceType::Stream(_)
207 | InterfaceType::ErrorContext(_) => todo!(),
208 })
209 }
210
211 pub(crate) fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Val> {
213 Ok(match ty {
214 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_memory(cx, ty, bytes)?),
215 InterfaceType::S8 => Val::S8(i8::linear_lift_from_memory(cx, ty, bytes)?),
216 InterfaceType::U8 => Val::U8(u8::linear_lift_from_memory(cx, ty, bytes)?),
217 InterfaceType::S16 => Val::S16(i16::linear_lift_from_memory(cx, ty, bytes)?),
218 InterfaceType::U16 => Val::U16(u16::linear_lift_from_memory(cx, ty, bytes)?),
219 InterfaceType::S32 => Val::S32(i32::linear_lift_from_memory(cx, ty, bytes)?),
220 InterfaceType::U32 => Val::U32(u32::linear_lift_from_memory(cx, ty, bytes)?),
221 InterfaceType::S64 => Val::S64(i64::linear_lift_from_memory(cx, ty, bytes)?),
222 InterfaceType::U64 => Val::U64(u64::linear_lift_from_memory(cx, ty, bytes)?),
223 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_memory(cx, ty, bytes)?),
224 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_memory(cx, ty, bytes)?),
225 InterfaceType::Char => Val::Char(char::linear_lift_from_memory(cx, ty, bytes)?),
226 InterfaceType::String => Val::String(<_>::linear_lift_from_memory(cx, ty, bytes)?),
227 InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
228 Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?)
229 }
230 InterfaceType::List(i) => {
231 let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize;
233 let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize;
234 load_list(cx, i, ptr, len)?
235 }
236
237 InterfaceType::Record(i) => {
238 let mut offset = 0;
239 let fields = cx.types[i].fields.iter();
240 Val::Record(
241 fields
242 .map(|field| -> Result<(String, Val)> {
243 let abi = cx.types.canonical_abi(&field.ty);
244 let offset = abi.next_field32(&mut offset);
245 let offset = usize::try_from(offset).unwrap();
246 let size = usize::try_from(abi.size32).unwrap();
247 Ok((
248 field.name.to_string(),
249 Val::load(cx, field.ty, &bytes[offset..][..size])?,
250 ))
251 })
252 .collect::<Result<_>>()?,
253 )
254 }
255 InterfaceType::Tuple(i) => {
256 let types = cx.types[i].types.iter().copied();
257 let mut offset = 0;
258 Val::Tuple(
259 types
260 .map(|ty| {
261 let abi = cx.types.canonical_abi(&ty);
262 let offset = abi.next_field32(&mut offset);
263 let offset = usize::try_from(offset).unwrap();
264 let size = usize::try_from(abi.size32).unwrap();
265 Val::load(cx, ty, &bytes[offset..][..size])
266 })
267 .collect::<Result<_>>()?,
268 )
269 }
270 InterfaceType::Variant(i) => {
271 let ty = &cx.types[i];
272 let (discriminant, value) =
273 load_variant(cx, &ty.info, ty.cases.values().copied(), bytes)?;
274
275 let (k, _) = ty.cases.get_index(discriminant as usize).unwrap();
276 Val::Variant(k.clone(), value)
277 }
278 InterfaceType::Enum(i) => {
279 let ty = &cx.types[i];
280 let (discriminant, _) =
281 load_variant(cx, &ty.info, ty.names.iter().map(|_| None), bytes)?;
282
283 Val::Enum(ty.names[discriminant as usize].clone())
284 }
285 InterfaceType::Option(i) => {
286 let ty = &cx.types[i];
287 let (_discriminant, value) =
288 load_variant(cx, &ty.info, [None, Some(ty.ty)].into_iter(), bytes)?;
289
290 Val::Option(value)
291 }
292 InterfaceType::Result(i) => {
293 let ty = &cx.types[i];
294 let (discriminant, value) =
295 load_variant(cx, &ty.info, [ty.ok, ty.err].into_iter(), bytes)?;
296
297 Val::Result(if discriminant == 0 {
298 Ok(value)
299 } else {
300 Err(value)
301 })
302 }
303 InterfaceType::Flags(i) => {
304 let ty = &cx.types[i];
305 let mut flags = Vec::new();
306 match FlagsSize::from_count(ty.names.len()) {
307 FlagsSize::Size0 => {}
308 FlagsSize::Size1 => {
309 let bits = u8::linear_lift_from_memory(cx, InterfaceType::U8, bytes)?;
310 push_flags(ty, &mut flags, 0, u32::from(bits));
311 }
312 FlagsSize::Size2 => {
313 let bits = u16::linear_lift_from_memory(cx, InterfaceType::U16, bytes)?;
314 push_flags(ty, &mut flags, 0, u32::from(bits));
315 }
316 FlagsSize::Size4Plus(n) => {
317 for i in 0..n {
318 let bits = u32::linear_lift_from_memory(
319 cx,
320 InterfaceType::U32,
321 &bytes[usize::from(i) * 4..][..4],
322 )?;
323 push_flags(ty, &mut flags, u32::from(i) * 32, bits);
324 }
325 }
326 }
327 Val::Flags(flags)
328 }
329 InterfaceType::Future(_)
330 | InterfaceType::Stream(_)
331 | InterfaceType::ErrorContext(_) => todo!(),
332 })
333 }
334
335 pub(crate) fn lower<T>(
337 &self,
338 cx: &mut LowerContext<'_, T>,
339 ty: InterfaceType,
340 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
341 ) -> Result<()> {
342 match (ty, self) {
343 (InterfaceType::Bool, Val::Bool(value)) => {
344 value.linear_lower_to_flat(cx, ty, next_mut(dst))
345 }
346 (InterfaceType::Bool, _) => unexpected(ty, self),
347 (InterfaceType::S8, Val::S8(value)) => {
348 value.linear_lower_to_flat(cx, ty, next_mut(dst))
349 }
350 (InterfaceType::S8, _) => unexpected(ty, self),
351 (InterfaceType::U8, Val::U8(value)) => {
352 value.linear_lower_to_flat(cx, ty, next_mut(dst))
353 }
354 (InterfaceType::U8, _) => unexpected(ty, self),
355 (InterfaceType::S16, Val::S16(value)) => {
356 value.linear_lower_to_flat(cx, ty, next_mut(dst))
357 }
358 (InterfaceType::S16, _) => unexpected(ty, self),
359 (InterfaceType::U16, Val::U16(value)) => {
360 value.linear_lower_to_flat(cx, ty, next_mut(dst))
361 }
362 (InterfaceType::U16, _) => unexpected(ty, self),
363 (InterfaceType::S32, Val::S32(value)) => {
364 value.linear_lower_to_flat(cx, ty, next_mut(dst))
365 }
366 (InterfaceType::S32, _) => unexpected(ty, self),
367 (InterfaceType::U32, Val::U32(value)) => {
368 value.linear_lower_to_flat(cx, ty, next_mut(dst))
369 }
370 (InterfaceType::U32, _) => unexpected(ty, self),
371 (InterfaceType::S64, Val::S64(value)) => {
372 value.linear_lower_to_flat(cx, ty, next_mut(dst))
373 }
374 (InterfaceType::S64, _) => unexpected(ty, self),
375 (InterfaceType::U64, Val::U64(value)) => {
376 value.linear_lower_to_flat(cx, ty, next_mut(dst))
377 }
378 (InterfaceType::U64, _) => unexpected(ty, self),
379 (InterfaceType::Float32, Val::Float32(value)) => {
380 value.linear_lower_to_flat(cx, ty, next_mut(dst))
381 }
382 (InterfaceType::Float32, _) => unexpected(ty, self),
383 (InterfaceType::Float64, Val::Float64(value)) => {
384 value.linear_lower_to_flat(cx, ty, next_mut(dst))
385 }
386 (InterfaceType::Float64, _) => unexpected(ty, self),
387 (InterfaceType::Char, Val::Char(value)) => {
388 value.linear_lower_to_flat(cx, ty, next_mut(dst))
389 }
390 (InterfaceType::Char, _) => unexpected(ty, self),
391 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
394 value.linear_lower_to_flat(cx, ty, next_mut(dst))
395 }
396 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
397 (InterfaceType::String, Val::String(value)) => {
398 let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit();
399 value.linear_lower_to_flat(cx, ty, my_dst)?;
400 let my_dst = unsafe { my_dst.assume_init() };
401 next_mut(dst).write(my_dst[0]);
402 next_mut(dst).write(my_dst[1]);
403 Ok(())
404 }
405 (InterfaceType::String, _) => unexpected(ty, self),
406 (InterfaceType::List(ty), Val::List(values)) => {
407 let ty = &cx.types[ty];
408 let (ptr, len) = lower_list(cx, ty.element, values)?;
409 next_mut(dst).write(ValRaw::i64(ptr as i64));
410 next_mut(dst).write(ValRaw::i64(len as i64));
411 Ok(())
412 }
413 (InterfaceType::List(_), _) => unexpected(ty, self),
414 (InterfaceType::Record(ty), Val::Record(values)) => {
415 let ty = &cx.types[ty];
416 if ty.fields.len() != values.len() {
417 bail!("expected {} fields, got {}", ty.fields.len(), values.len());
418 }
419 for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
420 if *name != field.name {
421 bail!("expected field `{}`, got `{name}`", field.name);
422 }
423 value.lower(cx, field.ty, dst)?;
424 }
425 Ok(())
426 }
427 (InterfaceType::Record(_), _) => unexpected(ty, self),
428 (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
429 let ty = &cx.types[ty];
430 if ty.types.len() != values.len() {
431 bail!("expected {} types, got {}", ty.types.len(), values.len());
432 }
433 for (value, ty) in values.iter().zip(ty.types.iter()) {
434 value.lower(cx, *ty, dst)?;
435 }
436 Ok(())
437 }
438 (InterfaceType::Tuple(_), _) => unexpected(ty, self),
439 (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
440 GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst)
441 }
442 (InterfaceType::Variant(_), _) => unexpected(ty, self),
443 (InterfaceType::Option(ty), Val::Option(v)) => {
444 GenericVariant::option(&cx.types[ty], v).lower(cx, dst)
445 }
446 (InterfaceType::Option(_), _) => unexpected(ty, self),
447 (InterfaceType::Result(ty), Val::Result(v)) => {
448 GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst)
449 }
450 (InterfaceType::Result(_), _) => unexpected(ty, self),
451 (InterfaceType::Enum(ty), Val::Enum(discriminant)) => {
452 let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?;
453 next_mut(dst).write(ValRaw::u32(discriminant));
454 Ok(())
455 }
456 (InterfaceType::Enum(_), _) => unexpected(ty, self),
457 (InterfaceType::Flags(ty), Val::Flags(value)) => {
458 let ty = &cx.types[ty];
459 let storage = flags_to_storage(ty, value)?;
460 for value in storage {
461 next_mut(dst).write(ValRaw::u32(value));
462 }
463 Ok(())
464 }
465 (InterfaceType::Flags(_), _) => unexpected(ty, self),
466 (InterfaceType::Future(_), _)
467 | (InterfaceType::Stream(_), _)
468 | (InterfaceType::ErrorContext(_), _) => todo!(),
469 }
470 }
471
472 pub(crate) fn store<T>(
474 &self,
475 cx: &mut LowerContext<'_, T>,
476 ty: InterfaceType,
477 offset: usize,
478 ) -> Result<()> {
479 debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0);
480
481 match (ty, self) {
482 (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset),
483 (InterfaceType::Bool, _) => unexpected(ty, self),
484 (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset),
485 (InterfaceType::U8, _) => unexpected(ty, self),
486 (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset),
487 (InterfaceType::S8, _) => unexpected(ty, self),
488 (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset),
489 (InterfaceType::U16, _) => unexpected(ty, self),
490 (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset),
491 (InterfaceType::S16, _) => unexpected(ty, self),
492 (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset),
493 (InterfaceType::U32, _) => unexpected(ty, self),
494 (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset),
495 (InterfaceType::S32, _) => unexpected(ty, self),
496 (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset),
497 (InterfaceType::U64, _) => unexpected(ty, self),
498 (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset),
499 (InterfaceType::S64, _) => unexpected(ty, self),
500 (InterfaceType::Float32, Val::Float32(value)) => {
501 value.linear_lower_to_memory(cx, ty, offset)
502 }
503 (InterfaceType::Float32, _) => unexpected(ty, self),
504 (InterfaceType::Float64, Val::Float64(value)) => {
505 value.linear_lower_to_memory(cx, ty, offset)
506 }
507 (InterfaceType::Float64, _) => unexpected(ty, self),
508 (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset),
509 (InterfaceType::Char, _) => unexpected(ty, self),
510 (InterfaceType::String, Val::String(value)) => {
511 value.linear_lower_to_memory(cx, ty, offset)
512 }
513 (InterfaceType::String, _) => unexpected(ty, self),
514
515 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
517 value.linear_lower_to_memory(cx, ty, offset)
518 }
519 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
520 (InterfaceType::List(ty), Val::List(values)) => {
521 let ty = &cx.types[ty];
522 let (ptr, len) = lower_list(cx, ty.element, values)?;
523 *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
525 *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
526 Ok(())
527 }
528 (InterfaceType::List(_), _) => unexpected(ty, self),
529 (InterfaceType::Record(ty), Val::Record(values)) => {
530 let ty = &cx.types[ty];
531 if ty.fields.len() != values.len() {
532 bail!("expected {} fields, got {}", ty.fields.len(), values.len());
533 }
534 let mut offset = offset;
535 for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
536 if *name != field.name {
537 bail!("expected field `{}`, got `{name}`", field.name);
538 }
539 value.store(
540 cx,
541 field.ty,
542 cx.types
543 .canonical_abi(&field.ty)
544 .next_field32_size(&mut offset),
545 )?;
546 }
547 Ok(())
548 }
549 (InterfaceType::Record(_), _) => unexpected(ty, self),
550 (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
551 let ty = &cx.types[ty];
552 if ty.types.len() != values.len() {
553 bail!("expected {} types, got {}", ty.types.len(), values.len());
554 }
555 let mut offset = offset;
556 for (value, ty) in values.iter().zip(ty.types.iter()) {
557 value.store(
558 cx,
559 *ty,
560 cx.types.canonical_abi(ty).next_field32_size(&mut offset),
561 )?;
562 }
563 Ok(())
564 }
565 (InterfaceType::Tuple(_), _) => unexpected(ty, self),
566
567 (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
568 GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset)
569 }
570 (InterfaceType::Variant(_), _) => unexpected(ty, self),
571 (InterfaceType::Enum(ty), Val::Enum(v)) => {
572 GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset)
573 }
574 (InterfaceType::Enum(_), _) => unexpected(ty, self),
575 (InterfaceType::Option(ty), Val::Option(v)) => {
576 GenericVariant::option(&cx.types[ty], v).store(cx, offset)
577 }
578 (InterfaceType::Option(_), _) => unexpected(ty, self),
579 (InterfaceType::Result(ty), Val::Result(v)) => {
580 GenericVariant::result(&cx.types[ty], v)?.store(cx, offset)
581 }
582 (InterfaceType::Result(_), _) => unexpected(ty, self),
583
584 (InterfaceType::Flags(ty), Val::Flags(flags)) => {
585 let ty = &cx.types[ty];
586 let storage = flags_to_storage(ty, flags)?;
587 match FlagsSize::from_count(ty.names.len()) {
588 FlagsSize::Size0 => {}
589 FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory(
590 cx,
591 InterfaceType::U8,
592 offset,
593 )?,
594 FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory(
595 cx,
596 InterfaceType::U16,
597 offset,
598 )?,
599 FlagsSize::Size4Plus(_) => {
600 let mut offset = offset;
601 for value in storage {
602 value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?;
603 offset += 4;
604 }
605 }
606 }
607 Ok(())
608 }
609 (InterfaceType::Flags(_), _) => unexpected(ty, self),
610 (InterfaceType::Future(_), _)
611 | (InterfaceType::Stream(_), _)
612 | (InterfaceType::ErrorContext(_), _) => todo!(),
613 }
614 }
615
616 fn desc(&self) -> &'static str {
617 match self {
618 Val::Bool(_) => "bool",
619 Val::U8(_) => "u8",
620 Val::S8(_) => "s8",
621 Val::U16(_) => "u16",
622 Val::S16(_) => "s16",
623 Val::U32(_) => "u32",
624 Val::S32(_) => "s32",
625 Val::U64(_) => "u64",
626 Val::S64(_) => "s64",
627 Val::Float32(_) => "f32",
628 Val::Float64(_) => "f64",
629 Val::Char(_) => "char",
630 Val::List(_) => "list",
631 Val::String(_) => "string",
632 Val::Record(_) => "record",
633 Val::Enum(_) => "enum",
634 Val::Variant(..) => "variant",
635 Val::Tuple(_) => "tuple",
636 Val::Option(_) => "option",
637 Val::Result(_) => "result",
638 Val::Resource(_) => "resource",
639 Val::Flags(_) => "flags",
640 }
641 }
642
643 #[cfg(feature = "wave")]
646 pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> {
647 Ok(wasm_wave::from_str(ty, s)?)
648 }
649
650 #[cfg(feature = "wave")]
652 pub fn to_wave(&self) -> Result<String> {
653 Ok(wasm_wave::to_string(self)?)
654 }
655}
656
657impl PartialEq for Val {
658 fn eq(&self, other: &Self) -> bool {
659 match (self, other) {
660 (Self::Float32(l), Self::Float32(r)) => {
666 (*l != 0.0 && l == r)
667 || (*l == 0.0 && l.to_bits() == r.to_bits())
668 || (l.is_nan() && r.is_nan())
669 }
670 (Self::Float32(_), _) => false,
671 (Self::Float64(l), Self::Float64(r)) => {
672 (*l != 0.0 && l == r)
673 || (*l == 0.0 && l.to_bits() == r.to_bits())
674 || (l.is_nan() && r.is_nan())
675 }
676 (Self::Float64(_), _) => false,
677
678 (Self::Bool(l), Self::Bool(r)) => l == r,
679 (Self::Bool(_), _) => false,
680 (Self::S8(l), Self::S8(r)) => l == r,
681 (Self::S8(_), _) => false,
682 (Self::U8(l), Self::U8(r)) => l == r,
683 (Self::U8(_), _) => false,
684 (Self::S16(l), Self::S16(r)) => l == r,
685 (Self::S16(_), _) => false,
686 (Self::U16(l), Self::U16(r)) => l == r,
687 (Self::U16(_), _) => false,
688 (Self::S32(l), Self::S32(r)) => l == r,
689 (Self::S32(_), _) => false,
690 (Self::U32(l), Self::U32(r)) => l == r,
691 (Self::U32(_), _) => false,
692 (Self::S64(l), Self::S64(r)) => l == r,
693 (Self::S64(_), _) => false,
694 (Self::U64(l), Self::U64(r)) => l == r,
695 (Self::U64(_), _) => false,
696 (Self::Char(l), Self::Char(r)) => l == r,
697 (Self::Char(_), _) => false,
698 (Self::String(l), Self::String(r)) => l == r,
699 (Self::String(_), _) => false,
700 (Self::List(l), Self::List(r)) => l == r,
701 (Self::List(_), _) => false,
702 (Self::Record(l), Self::Record(r)) => l == r,
703 (Self::Record(_), _) => false,
704 (Self::Tuple(l), Self::Tuple(r)) => l == r,
705 (Self::Tuple(_), _) => false,
706 (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv,
707 (Self::Variant(..), _) => false,
708 (Self::Enum(l), Self::Enum(r)) => l == r,
709 (Self::Enum(_), _) => false,
710 (Self::Option(l), Self::Option(r)) => l == r,
711 (Self::Option(_), _) => false,
712 (Self::Result(l), Self::Result(r)) => l == r,
713 (Self::Result(_), _) => false,
714 (Self::Flags(l), Self::Flags(r)) => l == r,
715 (Self::Flags(_), _) => false,
716 (Self::Resource(l), Self::Resource(r)) => l == r,
717 (Self::Resource(_), _) => false,
718 }
719 }
720}
721
722impl Eq for Val {}
723
724struct GenericVariant<'a> {
725 discriminant: u32,
726 payload: Option<(&'a Val, InterfaceType)>,
727 abi: &'a CanonicalAbiInfo,
728 info: &'a VariantInfo,
729}
730
731impl GenericVariant<'_> {
732 fn result<'a>(
733 ty: &'a TypeResult,
734 r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>,
735 ) -> Result<GenericVariant<'a>> {
736 let (discriminant, payload) = match r {
737 Ok(val) => {
738 let payload = match (val, ty.ok) {
739 (Some(val), Some(ty)) => Some((&**val, ty)),
740 (None, None) => None,
741 (Some(_), None) => {
742 bail!("payload provided to `ok` but not expected");
743 }
744 (None, Some(_)) => {
745 bail!("payload expected to `ok` but not provided");
746 }
747 };
748 (0, payload)
749 }
750 Err(val) => {
751 let payload = match (val, ty.err) {
752 (Some(val), Some(ty)) => Some((&**val, ty)),
753 (None, None) => None,
754 (Some(_), None) => {
755 bail!("payload provided to `err` but not expected");
756 }
757 (None, Some(_)) => {
758 bail!("payload expected to `err` but not provided");
759 }
760 };
761 (1, payload)
762 }
763 };
764 Ok(GenericVariant {
765 discriminant,
766 payload,
767 abi: &ty.abi,
768 info: &ty.info,
769 })
770 }
771
772 fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> {
773 let (discriminant, payload) = match r {
774 None => (0, None),
775 Some(val) => (1, Some((&**val, ty.ty))),
776 };
777 GenericVariant {
778 discriminant,
779 payload,
780 abi: &ty.abi,
781 info: &ty.info,
782 }
783 }
784
785 fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> {
786 let discriminant = get_enum_discriminant(ty, discriminant)?;
787
788 Ok(GenericVariant {
789 discriminant,
790 payload: None,
791 abi: &ty.abi,
792 info: &ty.info,
793 })
794 }
795
796 fn variant<'a>(
797 ty: &'a TypeVariant,
798 discriminant_name: &str,
799 payload: &'a Option<Box<Val>>,
800 ) -> Result<GenericVariant<'a>> {
801 let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?;
802
803 let payload = match (payload, payload_ty) {
804 (Some(val), Some(ty)) => Some((&**val, *ty)),
805 (None, None) => None,
806 (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"),
807 (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"),
808 };
809
810 Ok(GenericVariant {
811 discriminant,
812 payload,
813 abi: &ty.abi,
814 info: &ty.info,
815 })
816 }
817
818 fn lower<T>(
819 &self,
820 cx: &mut LowerContext<'_, T>,
821 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
822 ) -> Result<()> {
823 next_mut(dst).write(ValRaw::u32(self.discriminant));
824
825 let value_flat = match self.payload {
829 Some((value, ty)) => {
830 value.lower(cx, ty, dst)?;
831 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap()
832 }
833 None => 0,
834 };
835 let variant_flat = self.abi.flat_count(usize::MAX).unwrap();
836 for _ in (1 + value_flat)..variant_flat {
837 next_mut(dst).write(ValRaw::u64(0));
838 }
839 Ok(())
840 }
841
842 fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> {
843 match self.info.size {
844 DiscriminantSize::Size1 => u8::try_from(self.discriminant)
845 .unwrap()
846 .linear_lower_to_memory(cx, InterfaceType::U8, offset)?,
847 DiscriminantSize::Size2 => u16::try_from(self.discriminant)
848 .unwrap()
849 .linear_lower_to_memory(cx, InterfaceType::U16, offset)?,
850 DiscriminantSize::Size4 => {
851 self.discriminant
852 .linear_lower_to_memory(cx, InterfaceType::U32, offset)?
853 }
854 }
855
856 if let Some((value, ty)) = self.payload {
857 let offset = offset + usize::try_from(self.info.payload_offset32).unwrap();
858 value.store(cx, ty, offset)?;
859 }
860
861 Ok(())
862 }
863}
864
865fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> {
866 let elem = cx.types[ty].element;
867 let abi = cx.types.canonical_abi(&elem);
868 let element_size = usize::try_from(abi.size32).unwrap();
869 let element_alignment = abi.align32;
870
871 match len
872 .checked_mul(element_size)
873 .and_then(|len| ptr.checked_add(len))
874 {
875 Some(n) if n <= cx.memory().len() => {}
876 _ => bail!("list pointer/length out of bounds of memory"),
877 }
878 if ptr % usize::try_from(element_alignment)? != 0 {
879 bail!("list pointer is not aligned")
880 }
881
882 Ok(Val::List(
883 (0..len)
884 .map(|index| {
885 Val::load(
886 cx,
887 elem,
888 &cx.memory()[ptr + (index * element_size)..][..element_size],
889 )
890 })
891 .collect::<Result<_>>()?,
892 ))
893}
894
895fn load_variant(
896 cx: &mut LiftContext<'_>,
897 info: &VariantInfo,
898 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
899 bytes: &[u8],
900) -> Result<(u32, Option<Box<Val>>)> {
901 let discriminant = match info.size {
902 DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory(
903 cx,
904 InterfaceType::U8,
905 &bytes[..1],
906 )?),
907 DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory(
908 cx,
909 InterfaceType::U16,
910 &bytes[..2],
911 )?),
912 DiscriminantSize::Size4 => {
913 u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])?
914 }
915 };
916 let case_ty = types.nth(discriminant as usize).ok_or_else(|| {
917 anyhow!(
918 "discriminant {} out of range [0..{})",
919 discriminant,
920 types.len()
921 )
922 })?;
923 let value = match case_ty {
924 Some(case_ty) => {
925 let payload_offset = usize::try_from(info.payload_offset32).unwrap();
926 let case_abi = cx.types.canonical_abi(&case_ty);
927 let case_size = usize::try_from(case_abi.size32).unwrap();
928 Some(Box::new(Val::load(
929 cx,
930 case_ty,
931 &bytes[payload_offset..][..case_size],
932 )?))
933 }
934 None => None,
935 };
936 Ok((discriminant, value))
937}
938
939fn lift_variant(
940 cx: &mut LiftContext<'_>,
941 flatten_count: usize,
942 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
943 src: &mut Iter<'_, ValRaw>,
944) -> Result<(u32, Option<Box<Val>>)> {
945 let len = types.len();
946 let discriminant = next(src).get_u32();
947 let ty = types
948 .nth(discriminant as usize)
949 .ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?;
950 let (value, value_flat) = match ty {
951 Some(ty) => (
952 Some(Box::new(Val::lift(cx, ty, src)?)),
953 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
954 ),
955 None => (None, 0),
956 };
957 for _ in (1 + value_flat)..flatten_count {
958 next(src);
959 }
960 Ok((discriminant, value))
961}
962
963fn lower_list<T>(
965 cx: &mut LowerContext<'_, T>,
966 element_type: InterfaceType,
967 items: &[Val],
968) -> Result<(usize, usize)> {
969 let abi = cx.types.canonical_abi(&element_type);
970 let elt_size = usize::try_from(abi.size32)?;
971 let elt_align = abi.align32;
972 let size = items
973 .len()
974 .checked_mul(elt_size)
975 .ok_or_else(|| anyhow::anyhow!("size overflow copying a list"))?;
976 let ptr = cx.realloc(0, 0, elt_align, size)?;
977 let mut element_ptr = ptr;
978 for item in items {
979 item.store(cx, element_type, element_ptr)?;
980 element_ptr += elt_size;
981 }
982 Ok((ptr, items.len()))
983}
984
985fn push_flags(ty: &TypeFlags, flags: &mut Vec<String>, mut offset: u32, mut bits: u32) {
986 while bits > 0 {
987 if bits & 1 != 0 {
988 flags.push(ty.names[offset as usize].clone());
989 }
990 bits >>= 1;
991 offset += 1;
992 }
993}
994
995fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> {
996 let mut storage = match FlagsSize::from_count(ty.names.len()) {
997 FlagsSize::Size0 => Vec::new(),
998 FlagsSize::Size1 | FlagsSize::Size2 => vec![0],
999 FlagsSize::Size4Plus(n) => vec![0; n.into()],
1000 };
1001
1002 for flag in flags {
1003 let bit = ty
1004 .names
1005 .get_index_of(flag)
1006 .ok_or_else(|| anyhow::anyhow!("unknown flag: `{flag}`"))?;
1007 storage[bit / 32] |= 1 << (bit % 32);
1008 }
1009 Ok(storage)
1010}
1011
1012fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> {
1013 ty.names
1014 .get_index_of(n)
1015 .ok_or_else(|| anyhow::anyhow!("enum variant name `{n}` is not valid"))
1016 .map(|i| i.try_into().unwrap())
1017}
1018
1019fn get_variant_discriminant<'a>(
1020 ty: &'a TypeVariant,
1021 name: &str,
1022) -> Result<(u32, &'a Option<InterfaceType>)> {
1023 let (i, _, ty) = ty
1024 .cases
1025 .get_full(name)
1026 .ok_or_else(|| anyhow::anyhow!("unknown variant case: `{name}`"))?;
1027 Ok((i.try_into().unwrap(), ty))
1028}
1029
1030fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw {
1031 src.next().unwrap()
1032}
1033
1034fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> {
1035 dst.next().unwrap()
1036}
1037
1038#[cold]
1039fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> {
1040 bail!(
1041 "type mismatch: expected {}, found {}",
1042 desc(&ty),
1043 val.desc()
1044 )
1045}