1use crate::component::Instance;
2use crate::component::func::{Func, LiftContext, LowerContext};
3use crate::component::matching::InstanceType;
4use crate::component::storage::{storage_as_slice, storage_as_slice_mut};
5use crate::hash_map::HashMap;
6use crate::prelude::*;
7use crate::{AsContextMut, StoreContext, StoreContextMut, ValRaw};
8use alloc::borrow::Cow;
9use core::fmt;
10use core::hash::Hash;
11use core::iter;
12use core::marker;
13use core::mem::{self, MaybeUninit};
14use core::str;
15use wasmtime_core::array::array_try_from_fn;
16use wasmtime_environ::component::{
17 CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
18 OptionsIndex, StringEncoding, TypeMap, VariantInfo,
19};
20
21pub struct TypedFunc<Params, Return> {
36 func: Func,
37
38 _marker: marker::PhantomData<(Params, Return)>,
58}
59
60impl<Params, Return> Copy for TypedFunc<Params, Return> {}
61
62impl<Params, Return> Clone for TypedFunc<Params, Return> {
63 fn clone(&self) -> TypedFunc<Params, Return> {
64 *self
65 }
66}
67
68impl<Params, Return> TypedFunc<Params, Return>
69where
70 Params: ComponentNamedList + Lower,
71 Return: ComponentNamedList + Lift,
72{
73 pub unsafe fn new_unchecked(func: Func) -> TypedFunc<Params, Return> {
84 TypedFunc {
85 _marker: marker::PhantomData,
86 func,
87 }
88 }
89
90 pub fn func(&self) -> &Func {
93 &self.func
94 }
95
96 pub fn call(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
152 let mut store = store.as_context_mut();
153 store.0.validate_sync_call()?;
154 self.call_impl(store.as_context_mut(), params)
155 }
156
157 #[cfg(feature = "async")]
170 pub async fn call_async(
171 &self,
172 mut store: impl AsContextMut<Data: Send>,
173 params: Params,
174 ) -> Result<Return>
175 where
176 Return: 'static,
177 {
178 let mut store = store.as_context_mut();
179
180 #[cfg(feature = "component-model-async")]
181 if store.0.concurrency_support() {
182 return self.call_async_concurrent(store, params).await;
183 }
184
185 store
186 .on_fiber(|store| self.call_impl(store, params))
187 .await?
188 }
189
190 pub(crate) fn lower_args<T>(
191 cx: &mut LowerContext<T>,
192 ty: InterfaceType,
193 dst: &mut [MaybeUninit<ValRaw>],
194 params: &Params,
195 ) -> Result<()> {
196 use crate::component::storage::slice_to_storage_mut;
197
198 if Params::flatten_count() <= MAX_FLAT_PARAMS {
199 let dst: &mut MaybeUninit<Params::Lower> = unsafe { slice_to_storage_mut(dst) };
204 Self::lower_stack_args(cx, ¶ms, ty, dst)
205 } else {
206 Self::lower_heap_args(cx, ¶ms, ty, &mut dst[0])
207 }
208 }
209
210 fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
211 let mut store = store.as_context_mut();
212
213 if self.func.abi_async(store.0) {
214 bail!(
215 "cannot synchronously call an async-lifted export; \
216 use `call_async` or `call_concurrent` instead"
217 );
218 }
219
220 let result = unsafe {
238 #[derive(Copy, Clone)]
245 union Union<T: Copy, U: Copy> {
246 _a: T,
247 _b: U,
248 }
249
250 if Return::flatten_count() <= MAX_FLAT_RESULTS {
251 self.func.call_raw(
252 store.as_context_mut(),
253 |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
254 let dst = storage_as_slice_mut(dst);
255 Self::lower_args(cx, ty, dst, ¶ms)
256 },
257 Self::lift_stack_result,
258 )
259 } else {
260 self.func.call_raw(
261 store.as_context_mut(),
262 |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
263 let dst = storage_as_slice_mut(dst);
264 Self::lower_args(cx, ty, dst, ¶ms)
265 },
266 Self::lift_heap_result,
267 )
268 }
269 };
270
271 if result.is_err() {
272 store.0.set_trapped();
273 }
274
275 result
276 }
277
278 fn lower_stack_args<T>(
285 cx: &mut LowerContext<'_, T>,
286 params: &Params,
287 ty: InterfaceType,
288 dst: &mut MaybeUninit<Params::Lower>,
289 ) -> Result<()> {
290 assert!(Params::flatten_count() <= MAX_FLAT_PARAMS);
291 params.linear_lower_to_flat(cx, ty, dst)?;
292 Ok(())
293 }
294
295 fn lower_heap_args<T>(
302 cx: &mut LowerContext<'_, T>,
303 params: &Params,
304 ty: InterfaceType,
305 dst: &mut MaybeUninit<ValRaw>,
306 ) -> Result<()> {
307 let ptr = cx.realloc(0, 0, Params::ALIGN32, Params::SIZE32)?;
315 params.linear_lower_to_memory(cx, ty, ptr)?;
316
317 dst.write(ValRaw::i64(ptr as i64));
328
329 Ok(())
330 }
331
332 pub(crate) fn lift_stack_result(
337 cx: &mut LiftContext<'_>,
338 ty: InterfaceType,
339 dst: &Return::Lower,
340 ) -> Result<Return> {
341 Return::linear_lift_from_flat(cx, ty, dst)
342 }
343
344 pub(crate) fn lift_heap_result(
347 cx: &mut LiftContext<'_>,
348 ty: InterfaceType,
349 dst: &ValRaw,
350 ) -> Result<Return> {
351 assert!(Return::flatten_count() > MAX_FLAT_RESULTS);
352 let ptr = usize::try_from(dst.get_u32())?;
354 if ptr % usize::try_from(Return::ALIGN32)? != 0 {
355 bail!("return pointer not aligned");
356 }
357
358 let bytes = cx
359 .memory()
360 .get(ptr..)
361 .and_then(|b| b.get(..Return::SIZE32))
362 .ok_or_else(|| crate::format_err!("pointer out of bounds of memory"))?;
363 Return::linear_lift_from_memory(cx, ty, bytes)
364 }
365
366 #[doc(hidden)]
367 #[deprecated(note = "no longer needs to be called; this function has no effect")]
368 pub fn post_return(&self, _store: impl AsContextMut) -> Result<()> {
369 Ok(())
370 }
371
372 #[doc(hidden)]
373 #[deprecated(note = "no longer needs to be called; this function has no effect")]
374 #[cfg(feature = "async")]
375 pub async fn post_return_async<T: Send>(
376 &self,
377 _store: impl AsContextMut<Data = T>,
378 ) -> Result<()> {
379 Ok(())
380 }
381}
382
383pub unsafe trait ComponentNamedList: ComponentType {}
400
401pub unsafe trait ComponentType: Send + Sync {
505 #[doc(hidden)]
513 type Lower: Copy;
514
515 #[doc(hidden)]
517 const ABI: CanonicalAbiInfo;
518
519 #[doc(hidden)]
520 const SIZE32: usize = Self::ABI.size32 as usize;
521 #[doc(hidden)]
522 const ALIGN32: u32 = Self::ABI.align32;
523
524 #[doc(hidden)]
525 const IS_RUST_UNIT_TYPE: bool = false;
526
527 #[doc(hidden)]
535 const MAY_REQUIRE_REALLOC: bool = true;
536
537 #[doc(hidden)]
542 fn flatten_count() -> usize {
543 assert!(mem::size_of::<Self::Lower>() % mem::size_of::<ValRaw>() == 0);
544 assert!(mem::align_of::<Self::Lower>() == mem::align_of::<ValRaw>());
545 mem::size_of::<Self::Lower>() / mem::size_of::<ValRaw>()
546 }
547
548 #[doc(hidden)]
551 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()>;
552}
553
554#[doc(hidden)]
555pub unsafe trait ComponentVariant: ComponentType {
556 const CASES: &'static [Option<CanonicalAbiInfo>];
557 const INFO: VariantInfo = VariantInfo::new_static(Self::CASES);
558 const PAYLOAD_OFFSET32: usize = Self::INFO.payload_offset32 as usize;
559}
560
561pub unsafe trait Lower: ComponentType {
580 #[doc(hidden)]
599 fn linear_lower_to_flat<T>(
600 &self,
601 cx: &mut LowerContext<'_, T>,
602 ty: InterfaceType,
603 dst: &mut MaybeUninit<Self::Lower>,
604 ) -> Result<()>;
605
606 #[doc(hidden)]
625 fn linear_lower_to_memory<T>(
626 &self,
627 cx: &mut LowerContext<'_, T>,
628 ty: InterfaceType,
629 offset: usize,
630 ) -> Result<()>;
631
632 #[doc(hidden)]
641 fn linear_store_list_to_memory<T>(
642 cx: &mut LowerContext<'_, T>,
643 ty: InterfaceType,
644 mut offset: usize,
645 items: &[Self],
646 ) -> Result<()>
647 where
648 Self: Sized,
649 {
650 for item in items {
651 item.linear_lower_to_memory(cx, ty, offset)?;
652 offset += Self::SIZE32;
653 }
654 Ok(())
655 }
656}
657
658pub unsafe trait Lift: Sized + ComponentType {
675 #[doc(hidden)]
692 fn linear_lift_from_flat(
693 cx: &mut LiftContext<'_>,
694 ty: InterfaceType,
695 src: &Self::Lower,
696 ) -> Result<Self>;
697
698 #[doc(hidden)]
713 fn linear_lift_from_memory(
714 cx: &mut LiftContext<'_>,
715 ty: InterfaceType,
716 bytes: &[u8],
717 ) -> Result<Self>;
718
719 #[doc(hidden)]
721 fn linear_lift_list_from_memory(
722 cx: &mut LiftContext<'_>,
723 list: &WasmList<Self>,
724 ) -> Result<Vec<Self>>
725 where
726 Self: Sized,
727 {
728 let mut dst = Vec::with_capacity(list.len);
729 Self::linear_lift_into_from_memory(cx, list, &mut dst)?;
730 Ok(dst)
731 }
732
733 #[doc(hidden)]
739 fn linear_lift_into_from_memory(
740 cx: &mut LiftContext<'_>,
741 list: &WasmList<Self>,
742 dst: &mut impl Extend<Self>,
743 ) -> Result<()>
744 where
745 Self: Sized,
746 {
747 for i in 0..list.len {
748 dst.extend(Some(list.get_from_store(cx, i).unwrap()?));
749 }
750 Ok(())
751 }
752}
753
754macro_rules! forward_type_impls {
759 ($(
760 $(#[$attr:meta])*
761 ($($generics:tt)*) $a:ty => $b:ty,
762 )*) => ($(
763 $(#[$attr])*
764 unsafe impl <$($generics)*> ComponentType for $a {
765 type Lower = <$b as ComponentType>::Lower;
766
767 const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
768 const MAY_REQUIRE_REALLOC: bool = <$b as ComponentType>::MAY_REQUIRE_REALLOC;
769
770 #[inline]
771 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
772 <$b as ComponentType>::typecheck(ty, types)
773 }
774 }
775 )*)
776}
777
778forward_type_impls! {
779 (T: ComponentType + ?Sized) &'_ T => T,
780 (T: ComponentType + ?Sized) Box<T> => T,
781 (T: ComponentType + ?Sized) alloc::sync::Arc<T> => T,
782 () String => str,
783 (T: ComponentType) Vec<T> => [T],
784 #[cfg(feature = "component-model-bytes")]
785 () bytes::Bytes => [u8],
786 #[cfg(feature = "component-model-bytes")]
787 () bytes::BytesMut => [u8],
788}
789
790macro_rules! forward_lowers {
791 ($(
792 $(#[$attr:meta])*
793 ($($generics:tt)*) $a:ty => $b:ty,
794 )*) => ($(
795 $(#[$attr])*
796 unsafe impl <$($generics)*> Lower for $a {
797 fn linear_lower_to_flat<U>(
798 &self,
799 cx: &mut LowerContext<'_, U>,
800 ty: InterfaceType,
801 dst: &mut MaybeUninit<Self::Lower>,
802 ) -> Result<()> {
803 <$b as Lower>::linear_lower_to_flat(self, cx, ty, dst)
804 }
805
806 fn linear_lower_to_memory<U>(
807 &self,
808 cx: &mut LowerContext<'_, U>,
809 ty: InterfaceType,
810 offset: usize,
811 ) -> Result<()> {
812 <$b as Lower>::linear_lower_to_memory(self, cx, ty, offset)
813 }
814 }
815 )*)
816}
817
818forward_lowers! {
819 (T: Lower + ?Sized) &'_ T => T,
820 (T: Lower + ?Sized) Box<T> => T,
821 (T: Lower + ?Sized) alloc::sync::Arc<T> => T,
822 () String => str,
823 (T: Lower) Vec<T> => [T],
824 #[cfg(feature = "component-model-bytes")]
825 () bytes::Bytes => [u8],
826 #[cfg(feature = "component-model-bytes")]
827 () bytes::BytesMut => [u8],
828}
829
830macro_rules! forward_string_lifts {
831 ($($a:ty,)*) => ($(
832 unsafe impl Lift for $a {
833 #[inline]
834 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
835 let s = <WasmStr as Lift>::linear_lift_from_flat(cx, ty, src)?;
836 let encoding = cx.options().string_encoding;
837 Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
838 }
839
840 #[inline]
841 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
842 let s = <WasmStr as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
843 let encoding = cx.options().string_encoding;
844 Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
845 }
846 }
847 )*)
848}
849
850forward_string_lifts! {
851 Box<str>,
852 alloc::sync::Arc<str>,
853 String,
854}
855
856macro_rules! forward_list_lifts {
857 ($(
858 $(#[$attr:meta])*
859 ($($generics:tt)*) $a:ty => WasmList<$b:ty> $(( $via:ident $c:ty ))?,
860 )*) => ($(
861 $(#[$attr])*
862 unsafe impl <$($generics)*> Lift for $a {
863 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
864 let list = <WasmList::<$b> as Lift>::linear_lift_from_flat(cx, ty, src)?;
865 let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
866 $(let vec = <$c>::from(vec);)?
867 Ok(Self::from(vec))
868 }
869
870 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
871 let list = <WasmList::<$b> as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
872 let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
873 $(let vec = <$c>::from(vec);)?
874 Ok(Self::from(vec))
875 }
876 }
877 )*)
878}
879
880forward_list_lifts! {
881 (T: Lift) Box<[T]> => WasmList<T>,
882 (T: Lift) alloc::sync::Arc<[T]> => WasmList<T>,
883 (T: Lift) Vec<T> => WasmList<T>,
884 #[cfg(feature = "component-model-bytes")]
885 () bytes::Bytes => WasmList<u8>,
886 #[cfg(feature = "component-model-bytes")]
889 () bytes::BytesMut => WasmList<u8> (via bytes::Bytes),
890}
891
892macro_rules! integers {
895 ($($primitive:ident = $ty:ident in $field:ident/$get:ident with abi:$abi:ident,)*) => ($(
896 unsafe impl ComponentType for $primitive {
897 type Lower = ValRaw;
898
899 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
900
901 const MAY_REQUIRE_REALLOC: bool = false;
902
903 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
904 match ty {
905 InterfaceType::$ty => Ok(()),
906 other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
907 }
908 }
909 }
910
911 unsafe impl Lower for $primitive {
912 #[inline]
913 #[allow(trivial_numeric_casts, reason = "macro-generated code")]
914 fn linear_lower_to_flat<T>(
915 &self,
916 _cx: &mut LowerContext<'_, T>,
917 ty: InterfaceType,
918 dst: &mut MaybeUninit<Self::Lower>,
919 ) -> Result<()> {
920 debug_assert!(matches!(ty, InterfaceType::$ty));
921 dst.write(ValRaw::$field(*self as $field));
922 Ok(())
923 }
924
925 #[inline]
926 fn linear_lower_to_memory<T>(
927 &self,
928 cx: &mut LowerContext<'_, T>,
929 ty: InterfaceType,
930 offset: usize,
931 ) -> Result<()> {
932 debug_assert!(matches!(ty, InterfaceType::$ty));
933 debug_assert!(offset % Self::SIZE32 == 0);
934 *cx.get(offset) = self.to_le_bytes();
935 Ok(())
936 }
937
938 fn linear_store_list_to_memory<T>(
939 cx: &mut LowerContext<'_, T>,
940 ty: InterfaceType,
941 offset: usize,
942 items: &[Self],
943 ) -> Result<()> {
944 debug_assert!(matches!(ty, InterfaceType::$ty));
945
946 assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
950
951 let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
961 let (before, middle, end) = unsafe { dst.align_to_mut::<Self>() };
962 assert!(before.is_empty() && end.is_empty());
963 assert_eq!(middle.len(), items.len());
964
965 for (dst, src) in middle.iter_mut().zip(items) {
970 *dst = src.to_le();
971 }
972 Ok(())
973 }
974 }
975
976 unsafe impl Lift for $primitive {
977 #[inline]
978 #[allow(
979 trivial_numeric_casts,
980 clippy::cast_possible_truncation,
981 reason = "macro-generated code"
982 )]
983 fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
984 debug_assert!(matches!(ty, InterfaceType::$ty));
985 Ok(src.$get() as $primitive)
986 }
987
988 #[inline]
989 fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
990 debug_assert!(matches!(ty, InterfaceType::$ty));
991 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
992 Ok($primitive::from_le_bytes(*bytes.as_array().unwrap()))
993 }
994
995 fn linear_lift_into_from_memory(
996 cx: &mut LiftContext<'_>,
997 list: &WasmList<Self>,
998 dst: &mut impl Extend<Self>,
999 ) -> Result<()>
1000 where
1001 Self: Sized,
1002 {
1003 dst.extend(list._as_le_slice(cx.memory())
1004 .iter()
1005 .map(|i| Self::from_le(*i)));
1006 Ok(())
1007 }
1008 }
1009 )*)
1010}
1011
1012integers! {
1013 i8 = S8 in i32/get_i32 with abi:SCALAR1,
1014 u8 = U8 in u32/get_u32 with abi:SCALAR1,
1015 i16 = S16 in i32/get_i32 with abi:SCALAR2,
1016 u16 = U16 in u32/get_u32 with abi:SCALAR2,
1017 i32 = S32 in i32/get_i32 with abi:SCALAR4,
1018 u32 = U32 in u32/get_u32 with abi:SCALAR4,
1019 i64 = S64 in i64/get_i64 with abi:SCALAR8,
1020 u64 = U64 in u64/get_u64 with abi:SCALAR8,
1021}
1022
1023macro_rules! floats {
1024 ($($float:ident/$get_float:ident = $ty:ident with abi:$abi:ident)*) => ($(const _: () = {
1025 unsafe impl ComponentType for $float {
1026 type Lower = ValRaw;
1027
1028 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
1029 const MAY_REQUIRE_REALLOC: bool = false;
1030
1031 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1032 match ty {
1033 InterfaceType::$ty => Ok(()),
1034 other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
1035 }
1036 }
1037 }
1038
1039 unsafe impl Lower for $float {
1040 #[inline]
1041 fn linear_lower_to_flat<T>(
1042 &self,
1043 _cx: &mut LowerContext<'_, T>,
1044 ty: InterfaceType,
1045 dst: &mut MaybeUninit<Self::Lower>,
1046 ) -> Result<()> {
1047 debug_assert!(matches!(ty, InterfaceType::$ty));
1048 dst.write(ValRaw::$float(self.to_bits()));
1049 Ok(())
1050 }
1051
1052 #[inline]
1053 fn linear_lower_to_memory<T>(
1054 &self,
1055 cx: &mut LowerContext<'_, T>,
1056 ty: InterfaceType,
1057 offset: usize,
1058 ) -> Result<()> {
1059 debug_assert!(matches!(ty, InterfaceType::$ty));
1060 debug_assert!(offset % Self::SIZE32 == 0);
1061 let ptr = cx.get(offset);
1062 *ptr = self.to_bits().to_le_bytes();
1063 Ok(())
1064 }
1065
1066 fn linear_store_list_to_memory<T>(
1067 cx: &mut LowerContext<'_, T>,
1068 ty: InterfaceType,
1069 offset: usize,
1070 items: &[Self],
1071 ) -> Result<()> {
1072 debug_assert!(matches!(ty, InterfaceType::$ty));
1073
1074 assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
1078
1079 let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
1084 assert!(dst.as_ptr().cast::<Self>().is_aligned());
1085
1086 let (dst, rest) = dst.as_chunks_mut::<{Self::SIZE32}>();
1091 debug_assert!(rest.is_empty());
1092 for (dst, src) in iter::zip(dst, items) {
1093 *dst = src.to_le_bytes();
1094 }
1095 Ok(())
1096 }
1097 }
1098
1099 unsafe impl Lift for $float {
1100 #[inline]
1101 fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1102 debug_assert!(matches!(ty, InterfaceType::$ty));
1103 Ok($float::from_bits(src.$get_float()))
1104 }
1105
1106 #[inline]
1107 fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1108 debug_assert!(matches!(ty, InterfaceType::$ty));
1109 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1110 Ok($float::from_le_bytes(*bytes.as_array().unwrap()))
1111 }
1112
1113 fn linear_lift_list_from_memory(cx: &mut LiftContext<'_>, list: &WasmList<Self>) -> Result<Vec<Self>> where Self: Sized {
1114 let byte_size = list.len * mem::size_of::<Self>();
1116 let bytes = &cx.memory()[list.ptr..][..byte_size];
1117
1118 assert!(bytes.as_ptr().cast::<Self>().is_aligned());
1121
1122 let (src, rest) = bytes.as_chunks::<{Self::SIZE32}>();
1125 debug_assert!(rest.is_empty());
1126 Ok(
1127 src
1128 .iter()
1129 .map(|i| $float::from_le_bytes(*i))
1130 .collect()
1131 )
1132 }
1133 }
1134 };)*)
1135}
1136
1137floats! {
1138 f32/get_f32 = Float32 with abi:SCALAR4
1139 f64/get_f64 = Float64 with abi:SCALAR8
1140}
1141
1142unsafe impl ComponentType for bool {
1143 type Lower = ValRaw;
1144
1145 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR1;
1146 const MAY_REQUIRE_REALLOC: bool = false;
1147
1148 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1149 match ty {
1150 InterfaceType::Bool => Ok(()),
1151 other => bail!("expected `bool` found `{}`", desc(other)),
1152 }
1153 }
1154}
1155
1156unsafe impl Lower for bool {
1157 fn linear_lower_to_flat<T>(
1158 &self,
1159 _cx: &mut LowerContext<'_, T>,
1160 ty: InterfaceType,
1161 dst: &mut MaybeUninit<Self::Lower>,
1162 ) -> Result<()> {
1163 debug_assert!(matches!(ty, InterfaceType::Bool));
1164 dst.write(ValRaw::i32(*self as i32));
1165 Ok(())
1166 }
1167
1168 fn linear_lower_to_memory<T>(
1169 &self,
1170 cx: &mut LowerContext<'_, T>,
1171 ty: InterfaceType,
1172 offset: usize,
1173 ) -> Result<()> {
1174 debug_assert!(matches!(ty, InterfaceType::Bool));
1175 debug_assert!(offset % Self::SIZE32 == 0);
1176 cx.get::<1>(offset)[0] = *self as u8;
1177 Ok(())
1178 }
1179}
1180
1181unsafe impl Lift for bool {
1182 #[inline]
1183 fn linear_lift_from_flat(
1184 _cx: &mut LiftContext<'_>,
1185 ty: InterfaceType,
1186 src: &Self::Lower,
1187 ) -> Result<Self> {
1188 debug_assert!(matches!(ty, InterfaceType::Bool));
1189 match src.get_i32() {
1190 0 => Ok(false),
1191 _ => Ok(true),
1192 }
1193 }
1194
1195 #[inline]
1196 fn linear_lift_from_memory(
1197 _cx: &mut LiftContext<'_>,
1198 ty: InterfaceType,
1199 bytes: &[u8],
1200 ) -> Result<Self> {
1201 debug_assert!(matches!(ty, InterfaceType::Bool));
1202 match bytes[0] {
1203 0 => Ok(false),
1204 _ => Ok(true),
1205 }
1206 }
1207}
1208
1209unsafe impl ComponentType for char {
1210 type Lower = ValRaw;
1211
1212 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1213 const MAY_REQUIRE_REALLOC: bool = false;
1214
1215 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1216 match ty {
1217 InterfaceType::Char => Ok(()),
1218 other => bail!("expected `char` found `{}`", desc(other)),
1219 }
1220 }
1221}
1222
1223unsafe impl Lower for char {
1224 #[inline]
1225 fn linear_lower_to_flat<T>(
1226 &self,
1227 _cx: &mut LowerContext<'_, T>,
1228 ty: InterfaceType,
1229 dst: &mut MaybeUninit<Self::Lower>,
1230 ) -> Result<()> {
1231 debug_assert!(matches!(ty, InterfaceType::Char));
1232 dst.write(ValRaw::u32(u32::from(*self)));
1233 Ok(())
1234 }
1235
1236 #[inline]
1237 fn linear_lower_to_memory<T>(
1238 &self,
1239 cx: &mut LowerContext<'_, T>,
1240 ty: InterfaceType,
1241 offset: usize,
1242 ) -> Result<()> {
1243 debug_assert!(matches!(ty, InterfaceType::Char));
1244 debug_assert!(offset % Self::SIZE32 == 0);
1245 *cx.get::<4>(offset) = u32::from(*self).to_le_bytes();
1246 Ok(())
1247 }
1248}
1249
1250unsafe impl Lift for char {
1251 #[inline]
1252 fn linear_lift_from_flat(
1253 _cx: &mut LiftContext<'_>,
1254 ty: InterfaceType,
1255 src: &Self::Lower,
1256 ) -> Result<Self> {
1257 debug_assert!(matches!(ty, InterfaceType::Char));
1258 Ok(char::try_from(src.get_u32())?)
1259 }
1260
1261 #[inline]
1262 fn linear_lift_from_memory(
1263 _cx: &mut LiftContext<'_>,
1264 ty: InterfaceType,
1265 bytes: &[u8],
1266 ) -> Result<Self> {
1267 debug_assert!(matches!(ty, InterfaceType::Char));
1268 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1269 let bits = u32::from_le_bytes(*bytes.as_array().unwrap());
1270 Ok(char::try_from(bits)?)
1271 }
1272}
1273
1274fn lift_pointer_pair_from_flat(
1275 cx: &mut LiftContext<'_>,
1276 src: &[ValRaw; 2],
1277) -> Result<(usize, usize)> {
1278 let _ = cx; let ptr = src[0].get_u32();
1281 let len = src[1].get_u32();
1282 Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1283}
1284
1285fn lift_pointer_pair_from_memory(cx: &mut LiftContext<'_>, bytes: &[u8]) -> Result<(usize, usize)> {
1286 let _ = cx; let ptr = u32::from_le_bytes(*bytes[..4].as_array().unwrap());
1289 let len = u32::from_le_bytes(*bytes[4..].as_array().unwrap());
1290 Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1291}
1292
1293fn lower_pointer_pair_to_flat<T>(
1294 cx: &mut LowerContext<T>,
1295 dst: &mut MaybeUninit<[ValRaw; 2]>,
1296 ptr: usize,
1297 len: usize,
1298) {
1299 let _ = cx; map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64));
1303 map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64));
1304}
1305
1306fn lower_pointer_pair_to_memory<T>(
1307 cx: &mut LowerContext<T>,
1308 offset: usize,
1309 ptr: usize,
1310 len: usize,
1311) {
1312 *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
1314 *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
1315}
1316
1317const UTF16_TAG: usize = 1 << 31;
1319const MAX_STRING_BYTE_LENGTH: usize = (1 << 31) - 1;
1320
1321unsafe impl ComponentType for str {
1324 type Lower = [ValRaw; 2];
1325
1326 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1327
1328 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1329 match ty {
1330 InterfaceType::String => Ok(()),
1331 other => bail!("expected `string` found `{}`", desc(other)),
1332 }
1333 }
1334}
1335
1336unsafe impl Lower for str {
1337 fn linear_lower_to_flat<T>(
1338 &self,
1339 cx: &mut LowerContext<'_, T>,
1340 ty: InterfaceType,
1341 dst: &mut MaybeUninit<[ValRaw; 2]>,
1342 ) -> Result<()> {
1343 debug_assert!(matches!(ty, InterfaceType::String));
1344 let (ptr, len) = lower_string(cx, self)?;
1345 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1346 Ok(())
1347 }
1348
1349 fn linear_lower_to_memory<T>(
1350 &self,
1351 cx: &mut LowerContext<'_, T>,
1352 ty: InterfaceType,
1353 offset: usize,
1354 ) -> Result<()> {
1355 debug_assert!(matches!(ty, InterfaceType::String));
1356 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1357 let (ptr, len) = lower_string(cx, self)?;
1358 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1359 Ok(())
1360 }
1361}
1362
1363fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize, usize)> {
1364 match cx.options().string_encoding {
1380 StringEncoding::Utf8 => {
1385 if string.len() > MAX_STRING_BYTE_LENGTH {
1386 bail!(
1387 "string length of {} too large to copy into wasm",
1388 string.len()
1389 );
1390 }
1391 let ptr = cx.realloc(0, 0, 1, string.len())?;
1392 cx.as_slice_mut()[ptr..][..string.len()].copy_from_slice(string.as_bytes());
1393 Ok((ptr, string.len()))
1394 }
1395
1396 StringEncoding::Utf16 => {
1400 let size = string.len() * 2;
1401 if size > MAX_STRING_BYTE_LENGTH {
1402 bail!(
1403 "string length of {} too large to copy into wasm",
1404 string.len()
1405 );
1406 }
1407 let mut ptr = cx.realloc(0, 0, 2, size)?;
1408 let mut copied = 0;
1409 let bytes = &mut cx.as_slice_mut()[ptr..][..size];
1410 for (u, bytes) in string.encode_utf16().zip(bytes.chunks_mut(2)) {
1411 let u_bytes = u.to_le_bytes();
1412 bytes[0] = u_bytes[0];
1413 bytes[1] = u_bytes[1];
1414 copied += 1;
1415 }
1416 if (copied * 2) < size {
1417 ptr = cx.realloc(ptr, size, 2, copied * 2)?;
1418 }
1419 Ok((ptr, copied))
1420 }
1421
1422 StringEncoding::CompactUtf16 => {
1423 let bytes = string.as_bytes();
1425 let mut iter = string.char_indices();
1426 let mut ptr = cx.realloc(0, 0, 2, bytes.len())?;
1427 let mut dst = &mut cx.as_slice_mut()[ptr..][..bytes.len()];
1428 let mut result = 0;
1429 while let Some((i, ch)) = iter.next() {
1430 if let Ok(byte) = u8::try_from(u32::from(ch)) {
1432 dst[result] = byte;
1433 result += 1;
1434 continue;
1435 }
1436
1437 let worst_case = bytes
1440 .len()
1441 .checked_mul(2)
1442 .ok_or_else(|| format_err!("byte length overflow"))?;
1443 if worst_case > MAX_STRING_BYTE_LENGTH {
1444 bail!("byte length too large");
1445 }
1446 ptr = cx.realloc(ptr, bytes.len(), 2, worst_case)?;
1447 dst = &mut cx.as_slice_mut()[ptr..][..worst_case];
1448
1449 for i in (0..result).rev() {
1452 dst[2 * i] = dst[i];
1453 dst[2 * i + 1] = 0;
1454 }
1455
1456 for (u, bytes) in string[i..]
1458 .encode_utf16()
1459 .zip(dst[2 * result..].chunks_mut(2))
1460 {
1461 let u_bytes = u.to_le_bytes();
1462 bytes[0] = u_bytes[0];
1463 bytes[1] = u_bytes[1];
1464 result += 1;
1465 }
1466 if worst_case > 2 * result {
1467 ptr = cx.realloc(ptr, worst_case, 2, 2 * result)?;
1468 }
1469 return Ok((ptr, result | UTF16_TAG));
1470 }
1471 if result < bytes.len() {
1472 ptr = cx.realloc(ptr, bytes.len(), 2, result)?;
1473 }
1474 Ok((ptr, result))
1475 }
1476 }
1477}
1478
1479pub struct WasmStr {
1510 ptr: usize,
1511 len: usize,
1512 options: OptionsIndex,
1513 instance: Instance,
1514}
1515
1516impl WasmStr {
1517 pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1518 let (byte_len, align) = match cx.options().string_encoding {
1519 StringEncoding::Utf8 => (Some(len), 1_usize),
1520 StringEncoding::Utf16 => (len.checked_mul(2), 2),
1521 StringEncoding::CompactUtf16 => {
1522 if len & UTF16_TAG == 0 {
1523 (Some(len), 2)
1524 } else {
1525 ((len ^ UTF16_TAG).checked_mul(2), 2)
1526 }
1527 }
1528 };
1529 debug_assert!(align.is_power_of_two());
1530 if ptr & (align - 1) != 0 {
1531 bail!("string pointer not aligned to {align}");
1532 }
1533 match byte_len.and_then(|len| ptr.checked_add(len)) {
1534 Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?,
1535 _ => bail!("string pointer/length out of bounds of memory"),
1536 }
1537 Ok(WasmStr {
1538 ptr,
1539 len,
1540 options: cx.options_index(),
1541 instance: cx.instance_handle(),
1542 })
1543 }
1544
1545 pub fn to_str<'a, T: 'static>(
1567 &self,
1568 store: impl Into<StoreContext<'a, T>>,
1569 ) -> Result<Cow<'a, str>> {
1570 let store = store.into().0;
1571 let memory = self.instance.options_memory(store, self.options);
1572 let encoding = self.instance.options(store, self.options).string_encoding;
1573 self.to_str_from_memory(encoding, memory)
1574 }
1575
1576 pub(crate) fn to_str_from_memory<'a>(
1577 &self,
1578 encoding: StringEncoding,
1579 memory: &'a [u8],
1580 ) -> Result<Cow<'a, str>> {
1581 match encoding {
1582 StringEncoding::Utf8 => self.decode_utf8(memory),
1583 StringEncoding::Utf16 => self.decode_utf16(memory, self.len),
1584 StringEncoding::CompactUtf16 => {
1585 if self.len & UTF16_TAG == 0 {
1586 self.decode_latin1(memory)
1587 } else {
1588 self.decode_utf16(memory, self.len ^ UTF16_TAG)
1589 }
1590 }
1591 }
1592 }
1593
1594 fn decode_utf8<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1595 Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into())
1599 }
1600
1601 fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result<Cow<'a, str>> {
1602 let (chunks, rest) = &memory[self.ptr..][..len * 2].as_chunks::<2>();
1604 debug_assert!(rest.is_empty());
1605 Ok(
1606 core::char::decode_utf16(chunks.iter().map(|chunk| u16::from_le_bytes(*chunk)))
1607 .collect::<Result<String, _>>()?
1608 .into(),
1609 )
1610 }
1611
1612 fn decode_latin1<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1613 Ok(encoding_rs::mem::decode_latin1(
1615 &memory[self.ptr..][..self.len],
1616 ))
1617 }
1618}
1619
1620unsafe impl ComponentType for WasmStr {
1623 type Lower = <str as ComponentType>::Lower;
1624
1625 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1626
1627 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1628 match ty {
1629 InterfaceType::String => Ok(()),
1630 other => bail!("expected `string` found `{}`", desc(other)),
1631 }
1632 }
1633}
1634
1635unsafe impl Lift for WasmStr {
1636 #[inline]
1637 fn linear_lift_from_flat(
1638 cx: &mut LiftContext<'_>,
1639 ty: InterfaceType,
1640 src: &Self::Lower,
1641 ) -> Result<Self> {
1642 debug_assert!(matches!(ty, InterfaceType::String));
1643 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1644 WasmStr::new(ptr, len, cx)
1645 }
1646
1647 #[inline]
1648 fn linear_lift_from_memory(
1649 cx: &mut LiftContext<'_>,
1650 ty: InterfaceType,
1651 bytes: &[u8],
1652 ) -> Result<Self> {
1653 debug_assert!(matches!(ty, InterfaceType::String));
1654 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1655 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1656 WasmStr::new(ptr, len, cx)
1657 }
1658}
1659
1660unsafe impl<T> ComponentType for [T]
1661where
1662 T: ComponentType,
1663{
1664 type Lower = [ValRaw; 2];
1665
1666 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1667
1668 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1669 match ty {
1670 InterfaceType::List(t) => T::typecheck(&types.types[*t].element, types),
1671 other => bail!("expected `list` found `{}`", desc(other)),
1672 }
1673 }
1674}
1675
1676unsafe impl<T> Lower for [T]
1677where
1678 T: Lower,
1679{
1680 fn linear_lower_to_flat<U>(
1681 &self,
1682 cx: &mut LowerContext<'_, U>,
1683 ty: InterfaceType,
1684 dst: &mut MaybeUninit<[ValRaw; 2]>,
1685 ) -> Result<()> {
1686 let elem = match ty {
1687 InterfaceType::List(i) => cx.types[i].element,
1688 _ => bad_type_info(),
1689 };
1690 let (ptr, len) = lower_list(cx, elem, self)?;
1691 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1692 Ok(())
1693 }
1694
1695 fn linear_lower_to_memory<U>(
1696 &self,
1697 cx: &mut LowerContext<'_, U>,
1698 ty: InterfaceType,
1699 offset: usize,
1700 ) -> Result<()> {
1701 let elem = match ty {
1702 InterfaceType::List(i) => cx.types[i].element,
1703 _ => bad_type_info(),
1704 };
1705 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1706 let (ptr, len) = lower_list(cx, elem, self)?;
1707 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1708 Ok(())
1709 }
1710}
1711
1712fn lower_list<T, U>(
1728 cx: &mut LowerContext<'_, U>,
1729 ty: InterfaceType,
1730 list: &[T],
1731) -> Result<(usize, usize)>
1732where
1733 T: Lower,
1734{
1735 let elem_size = T::SIZE32;
1736 let size = list
1737 .len()
1738 .checked_mul(elem_size)
1739 .ok_or_else(|| format_err!("size overflow copying a list"))?;
1740 let ptr = cx.realloc(0, 0, T::ALIGN32, size)?;
1741 T::linear_store_list_to_memory(cx, ty, ptr, list)?;
1742 Ok((ptr, list.len()))
1743}
1744
1745pub struct WasmList<T> {
1762 ptr: usize,
1763 len: usize,
1764 options: OptionsIndex,
1765 elem: InterfaceType,
1766 instance: Instance,
1767 _marker: marker::PhantomData<T>,
1768}
1769
1770impl<T: Lift> WasmList<T> {
1771 pub(crate) fn new(
1772 ptr: usize,
1773 len: usize,
1774 cx: &mut LiftContext<'_>,
1775 elem: InterfaceType,
1776 ) -> Result<WasmList<T>> {
1777 match len
1778 .checked_mul(T::SIZE32)
1779 .and_then(|len| ptr.checked_add(len))
1780 {
1781 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<T>())?,
1782 _ => bail!("list pointer/length out of bounds of memory"),
1783 }
1784 if ptr % usize::try_from(T::ALIGN32)? != 0 {
1785 bail!("list pointer is not aligned")
1786 }
1787 Ok(WasmList {
1788 ptr,
1789 len,
1790 options: cx.options_index(),
1791 elem,
1792 instance: cx.instance_handle(),
1793 _marker: marker::PhantomData,
1794 })
1795 }
1796
1797 #[inline]
1799 pub fn len(&self) -> usize {
1800 self.len
1801 }
1802
1803 pub fn get(&self, mut store: impl AsContextMut, index: usize) -> Option<Result<T>> {
1818 let store = store.as_context_mut().0;
1819 let mut cx = match LiftContext::new(store, self.options, self.instance) {
1820 Ok(cx) => cx,
1821 Err(e) => return Some(Err(e)),
1822 };
1823 self.get_from_store(&mut cx, index)
1824 }
1825
1826 fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1827 if index >= self.len {
1828 return None;
1829 }
1830 let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1837 Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1838 }
1839
1840 pub fn iter<'a, U: 'static>(
1845 &'a self,
1846 store: impl Into<StoreContextMut<'a, U>>,
1847 ) -> Result<impl ExactSizeIterator<Item = Result<T>> + 'a> {
1848 let store = store.into().0;
1849 let mut cx = LiftContext::new(store, self.options, self.instance)?;
1850 Ok((0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap()))
1851 }
1852}
1853
1854macro_rules! raw_wasm_list_accessors {
1855 ($($i:ident)*) => ($(
1856 impl WasmList<$i> {
1857 pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1875 let memory = self.instance.options_memory(store.into().0, self.options);
1876 self._as_le_slice(memory)
1877 }
1878
1879 fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1880 let byte_size = self.len * mem::size_of::<$i>();
1882 let bytes = &all_of_memory[self.ptr..][..byte_size];
1883
1884 unsafe {
1896 let (head, body, tail) = bytes.align_to::<$i>();
1897 assert!(head.is_empty() && tail.is_empty());
1898 body
1899 }
1900 }
1901 }
1902 )*)
1903}
1904
1905raw_wasm_list_accessors! {
1906 i8 i16 i32 i64
1907 u8 u16 u32 u64
1908}
1909
1910unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
1913 type Lower = <[T] as ComponentType>::Lower;
1914
1915 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1916
1917 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1918 <[T] as ComponentType>::typecheck(ty, types)
1919 }
1920}
1921
1922unsafe impl<T: Lift> Lift for WasmList<T> {
1923 fn linear_lift_from_flat(
1924 cx: &mut LiftContext<'_>,
1925 ty: InterfaceType,
1926 src: &Self::Lower,
1927 ) -> Result<Self> {
1928 let elem = match ty {
1929 InterfaceType::List(i) => cx.types[i].element,
1930 _ => bad_type_info(),
1931 };
1932 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1933 WasmList::new(ptr, len, cx, elem)
1934 }
1935
1936 fn linear_lift_from_memory(
1937 cx: &mut LiftContext<'_>,
1938 ty: InterfaceType,
1939 bytes: &[u8],
1940 ) -> Result<Self> {
1941 let elem = match ty {
1942 InterfaceType::List(i) => cx.types[i].element,
1943 _ => bad_type_info(),
1944 };
1945 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1946 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1947 WasmList::new(ptr, len, cx, elem)
1948 }
1949}
1950
1951fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap {
1958 match ty {
1959 InterfaceType::Map(i) => &types[i],
1960 _ => bad_type_info(),
1961 }
1962}
1963
1964unsafe impl<K, V> ComponentType for HashMap<K, V>
1965where
1966 K: ComponentType,
1967 V: ComponentType,
1968{
1969 type Lower = [ValRaw; 2];
1970
1971 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1972
1973 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1974 TryHashMap::<K, V>::typecheck(ty, types)
1975 }
1976}
1977
1978unsafe impl<K, V> Lower for HashMap<K, V>
1979where
1980 K: Lower,
1981 V: Lower,
1982{
1983 fn linear_lower_to_flat<U>(
1984 &self,
1985 cx: &mut LowerContext<'_, U>,
1986 ty: InterfaceType,
1987 dst: &mut MaybeUninit<[ValRaw; 2]>,
1988 ) -> Result<()> {
1989 let map = map_abi(ty, &cx.types);
1990 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
1991 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1992 Ok(())
1993 }
1994
1995 fn linear_lower_to_memory<U>(
1996 &self,
1997 cx: &mut LowerContext<'_, U>,
1998 ty: InterfaceType,
1999 offset: usize,
2000 ) -> Result<()> {
2001 let map = map_abi(ty, &cx.types);
2002 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2003 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2004 lower_pointer_pair_to_memory(cx, offset, ptr, len);
2005 Ok(())
2006 }
2007}
2008
2009unsafe impl<K, V> Lift for HashMap<K, V>
2010where
2011 K: Lift + Eq + Hash,
2012 V: Lift,
2013{
2014 fn linear_lift_from_flat(
2015 cx: &mut LiftContext<'_>,
2016 ty: InterfaceType,
2017 src: &Self::Lower,
2018 ) -> Result<Self> {
2019 Ok(TryHashMap::<K, V>::linear_lift_from_flat(cx, ty, src)?.into())
2020 }
2021
2022 fn linear_lift_from_memory(
2023 cx: &mut LiftContext<'_>,
2024 ty: InterfaceType,
2025 bytes: &[u8],
2026 ) -> Result<Self> {
2027 Ok(TryHashMap::<K, V>::linear_lift_from_memory(cx, ty, bytes)?.into())
2028 }
2029}
2030
2031fn lower_map_iter<'a, K, V, U>(
2032 cx: &mut LowerContext<'_, U>,
2033 map: &TypeMap,
2034 len: usize,
2035 iter: impl Iterator<Item = (&'a K, &'a V)>,
2036) -> Result<(usize, usize)>
2037where
2038 K: Lower + 'a,
2039 V: Lower + 'a,
2040{
2041 let size = len
2042 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2043 .ok_or_else(|| format_err!("size overflow copying a map"))?;
2044 let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?;
2045
2046 let mut entry_offset = ptr;
2047 for (key, value) in iter {
2048 <K as Lower>::linear_lower_to_memory(key, cx, map.key, entry_offset)?;
2050 <V as Lower>::linear_lower_to_memory(
2052 value,
2053 cx,
2054 map.value,
2055 entry_offset + usize::try_from(map.value_offset32)?,
2056 )?;
2057 entry_offset += usize::try_from(map.entry_abi.size32)?;
2058 }
2059
2060 Ok((ptr, len))
2061}
2062
2063unsafe impl<K, V> ComponentType for TryHashMap<K, V>
2064where
2065 K: ComponentType,
2066 V: ComponentType,
2067{
2068 type Lower = [ValRaw; 2];
2069
2070 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
2071
2072 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2073 match ty {
2074 InterfaceType::Map(t) => {
2075 let map_ty = &types.types[*t];
2076 K::typecheck(&map_ty.key, types)?;
2077 V::typecheck(&map_ty.value, types)?;
2078 Ok(())
2079 }
2080 other => bail!("expected `map` found `{}`", desc(other)),
2081 }
2082 }
2083}
2084
2085unsafe impl<K, V> Lower for TryHashMap<K, V>
2086where
2087 K: Lower,
2088 V: Lower,
2089{
2090 fn linear_lower_to_flat<U>(
2091 &self,
2092 cx: &mut LowerContext<'_, U>,
2093 ty: InterfaceType,
2094 dst: &mut MaybeUninit<[ValRaw; 2]>,
2095 ) -> Result<()> {
2096 let map = map_abi(ty, &cx.types);
2097 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2098 lower_pointer_pair_to_flat(cx, dst, ptr, len);
2099 Ok(())
2100 }
2101
2102 fn linear_lower_to_memory<U>(
2103 &self,
2104 cx: &mut LowerContext<'_, U>,
2105 ty: InterfaceType,
2106 offset: usize,
2107 ) -> Result<()> {
2108 let map = map_abi(ty, &cx.types);
2109 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2110 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2111 lower_pointer_pair_to_memory(cx, offset, ptr, len);
2112 Ok(())
2113 }
2114}
2115
2116unsafe impl<K, V> Lift for TryHashMap<K, V>
2117where
2118 K: Lift + Eq + Hash,
2119 V: Lift,
2120{
2121 fn linear_lift_from_flat(
2122 cx: &mut LiftContext<'_>,
2123 ty: InterfaceType,
2124 src: &Self::Lower,
2125 ) -> Result<Self> {
2126 let map = map_abi(ty, &cx.types);
2127 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
2128 lift_try_map(cx, map, ptr, len)
2129 }
2130
2131 fn linear_lift_from_memory(
2132 cx: &mut LiftContext<'_>,
2133 ty: InterfaceType,
2134 bytes: &[u8],
2135 ) -> Result<Self> {
2136 let map = map_abi(ty, &cx.types);
2137 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2138 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
2139 lift_try_map(cx, map, ptr, len)
2140 }
2141}
2142
2143fn lift_try_map<K, V>(
2144 cx: &mut LiftContext<'_>,
2145 map: &TypeMap,
2146 ptr: usize,
2147 len: usize,
2148) -> Result<TryHashMap<K, V>>
2149where
2150 K: Lift + Eq + Hash,
2151 V: Lift,
2152{
2153 let mut result = TryHashMap::with_capacity(len)?;
2154
2155 match len
2156 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2157 .and_then(|total| ptr.checked_add(total))
2158 {
2159 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(K, V)>())?,
2160 _ => bail!("map pointer/length out of bounds of memory"),
2161 }
2162 if ptr % (map.entry_abi.align32 as usize) != 0 {
2163 bail!("map pointer is not aligned");
2164 }
2165
2166 for i in 0..len {
2167 let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?);
2168
2169 let key_bytes = &cx.memory()[entry_base..][..K::SIZE32];
2170 let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?;
2171
2172 let value_bytes =
2173 &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32];
2174 let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?;
2175
2176 result.insert(key, value)?;
2177 }
2178
2179 Ok(result)
2180}
2181
2182fn typecheck_tuple(
2184 ty: &InterfaceType,
2185 types: &InstanceType<'_>,
2186 expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2187) -> Result<()> {
2188 match ty {
2189 InterfaceType::Tuple(t) => {
2190 let tuple = &types.types[*t];
2191 if tuple.types.len() != expected.len() {
2192 bail!(
2193 "expected {}-tuple, found {}-tuple",
2194 expected.len(),
2195 tuple.types.len()
2196 );
2197 }
2198 for (ty, check) in tuple.types.iter().zip(expected) {
2199 check(ty, types)?;
2200 }
2201 Ok(())
2202 }
2203 other => bail!("expected `tuple` found `{}`", desc(other)),
2204 }
2205}
2206
2207pub fn typecheck_record(
2210 ty: &InterfaceType,
2211 types: &InstanceType<'_>,
2212 expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2213) -> Result<()> {
2214 match ty {
2215 InterfaceType::Record(index) => {
2216 let fields = &types.types[*index].fields;
2217
2218 if fields.len() != expected.len() {
2219 bail!(
2220 "expected record of {} fields, found {} fields",
2221 expected.len(),
2222 fields.len()
2223 );
2224 }
2225
2226 for (field, &(name, check)) in fields.iter().zip(expected) {
2227 check(&field.ty, types)
2228 .with_context(|| format!("type mismatch for field {name}"))?;
2229
2230 if field.name != name {
2231 bail!("expected record field named {}, found {}", name, field.name);
2232 }
2233 }
2234
2235 Ok(())
2236 }
2237 other => bail!("expected `record` found `{}`", desc(other)),
2238 }
2239}
2240
2241pub fn typecheck_variant(
2244 ty: &InterfaceType,
2245 types: &InstanceType<'_>,
2246 expected: &[(
2247 &str,
2248 Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2249 )],
2250) -> Result<()> {
2251 match ty {
2252 InterfaceType::Variant(index) => {
2253 let cases = &types.types[*index].cases;
2254
2255 if cases.len() != expected.len() {
2256 bail!(
2257 "expected variant of {} cases, found {} cases",
2258 expected.len(),
2259 cases.len()
2260 );
2261 }
2262
2263 for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2264 if *case_name != name {
2265 bail!("expected variant case named {name}, found {case_name}");
2266 }
2267
2268 match (check, case_ty) {
2269 (Some(check), Some(ty)) => check(ty, types)
2270 .with_context(|| format!("type mismatch for case {name}"))?,
2271 (None, None) => {}
2272 (Some(_), None) => {
2273 bail!("case `{name}` has no type but one was expected")
2274 }
2275 (None, Some(_)) => {
2276 bail!("case `{name}` has a type but none was expected")
2277 }
2278 }
2279 }
2280
2281 Ok(())
2282 }
2283 other => bail!("expected `variant` found `{}`", desc(other)),
2284 }
2285}
2286
2287pub fn typecheck_enum(
2290 ty: &InterfaceType,
2291 types: &InstanceType<'_>,
2292 expected: &[&str],
2293) -> Result<()> {
2294 match ty {
2295 InterfaceType::Enum(index) => {
2296 let names = &types.types[*index].names;
2297
2298 if names.len() != expected.len() {
2299 bail!(
2300 "expected enum of {} names, found {} names",
2301 expected.len(),
2302 names.len()
2303 );
2304 }
2305
2306 for (name, expected) in names.iter().zip(expected) {
2307 if name != expected {
2308 bail!("expected enum case named {expected}, found {name}");
2309 }
2310 }
2311
2312 Ok(())
2313 }
2314 other => bail!("expected `enum` found `{}`", desc(other)),
2315 }
2316}
2317
2318pub fn typecheck_flags(
2321 ty: &InterfaceType,
2322 types: &InstanceType<'_>,
2323 expected: &[&str],
2324) -> Result<()> {
2325 match ty {
2326 InterfaceType::Flags(index) => {
2327 let names = &types.types[*index].names;
2328
2329 if names.len() != expected.len() {
2330 bail!(
2331 "expected flags type with {} names, found {} names",
2332 expected.len(),
2333 names.len()
2334 );
2335 }
2336
2337 for (name, expected) in names.iter().zip(expected) {
2338 if name != expected {
2339 bail!("expected flag named {expected}, found {name}");
2340 }
2341 }
2342
2343 Ok(())
2344 }
2345 other => bail!("expected `flags` found `{}`", desc(other)),
2346 }
2347}
2348
2349pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2351 f.write_str("(")?;
2352 let mut wrote = false;
2353 for (index, name) in names.iter().enumerate() {
2354 if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2355 if wrote {
2356 f.write_str("|")?;
2357 } else {
2358 wrote = true;
2359 }
2360
2361 f.write_str(name)?;
2362 }
2363 }
2364 f.write_str(")")
2365}
2366
2367unsafe impl<T> ComponentType for Option<T>
2368where
2369 T: ComponentType,
2370{
2371 type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2372
2373 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2374 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC;
2375
2376 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2377 match ty {
2378 InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2379 other => bail!("expected `option` found `{}`", desc(other)),
2380 }
2381 }
2382}
2383
2384unsafe impl<T> ComponentVariant for Option<T>
2385where
2386 T: ComponentType,
2387{
2388 const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2389}
2390
2391unsafe impl<T> Lower for Option<T>
2392where
2393 T: Lower,
2394{
2395 fn linear_lower_to_flat<U>(
2396 &self,
2397 cx: &mut LowerContext<'_, U>,
2398 ty: InterfaceType,
2399 dst: &mut MaybeUninit<Self::Lower>,
2400 ) -> Result<()> {
2401 let payload = match ty {
2402 InterfaceType::Option(ty) => cx.types[ty].ty,
2403 _ => bad_type_info(),
2404 };
2405 match self {
2406 None => {
2407 map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2408 unsafe {
2415 map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2416 }
2417 }
2418 Some(val) => {
2419 map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2420 val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2421 }
2422 }
2423 Ok(())
2424 }
2425
2426 fn linear_lower_to_memory<U>(
2427 &self,
2428 cx: &mut LowerContext<'_, U>,
2429 ty: InterfaceType,
2430 offset: usize,
2431 ) -> Result<()> {
2432 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2433 let payload = match ty {
2434 InterfaceType::Option(ty) => cx.types[ty].ty,
2435 _ => bad_type_info(),
2436 };
2437 match self {
2438 None => {
2439 cx.get::<1>(offset)[0] = 0;
2440 }
2441 Some(val) => {
2442 cx.get::<1>(offset)[0] = 1;
2443 val.linear_lower_to_memory(
2444 cx,
2445 payload,
2446 offset + (Self::INFO.payload_offset32 as usize),
2447 )?;
2448 }
2449 }
2450 Ok(())
2451 }
2452}
2453
2454unsafe impl<T> Lift for Option<T>
2455where
2456 T: Lift,
2457{
2458 fn linear_lift_from_flat(
2459 cx: &mut LiftContext<'_>,
2460 ty: InterfaceType,
2461 src: &Self::Lower,
2462 ) -> Result<Self> {
2463 let payload = match ty {
2464 InterfaceType::Option(ty) => cx.types[ty].ty,
2465 _ => bad_type_info(),
2466 };
2467 Ok(match src.A1.get_i32() {
2468 0 => None,
2469 1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2470 _ => bail!("invalid option discriminant"),
2471 })
2472 }
2473
2474 fn linear_lift_from_memory(
2475 cx: &mut LiftContext<'_>,
2476 ty: InterfaceType,
2477 bytes: &[u8],
2478 ) -> Result<Self> {
2479 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2480 let payload_ty = match ty {
2481 InterfaceType::Option(ty) => cx.types[ty].ty,
2482 _ => bad_type_info(),
2483 };
2484 let discrim = bytes[0];
2485 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2486 match discrim {
2487 0 => Ok(None),
2488 1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2489 _ => bail!("invalid option discriminant"),
2490 }
2491 }
2492}
2493
2494#[derive(Clone, Copy)]
2495#[repr(C)]
2496pub struct ResultLower<T: Copy, E: Copy> {
2497 tag: ValRaw,
2498 payload: ResultLowerPayload<T, E>,
2499}
2500
2501#[derive(Clone, Copy)]
2502#[repr(C)]
2503union ResultLowerPayload<T: Copy, E: Copy> {
2504 ok: T,
2505 err: E,
2506}
2507
2508unsafe impl<T, E> ComponentType for Result<T, E>
2509where
2510 T: ComponentType,
2511 E: ComponentType,
2512{
2513 type Lower = ResultLower<T::Lower, E::Lower>;
2514
2515 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2516 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC || E::MAY_REQUIRE_REALLOC;
2517
2518 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2519 match ty {
2520 InterfaceType::Result(r) => {
2521 let result = &types.types[*r];
2522 match &result.ok {
2523 Some(ty) => T::typecheck(ty, types)?,
2524 None if T::IS_RUST_UNIT_TYPE => {}
2525 None => bail!("expected no `ok` type"),
2526 }
2527 match &result.err {
2528 Some(ty) => E::typecheck(ty, types)?,
2529 None if E::IS_RUST_UNIT_TYPE => {}
2530 None => bail!("expected no `err` type"),
2531 }
2532 Ok(())
2533 }
2534 other => bail!("expected `result` found `{}`", desc(other)),
2535 }
2536 }
2537}
2538
2539pub unsafe fn lower_payload<P, T>(
2552 payload: &mut MaybeUninit<P>,
2553 typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2554 lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2555) -> Result<()> {
2556 let typed = typed_payload(payload);
2557 lower(typed)?;
2558
2559 let typed_len = unsafe { storage_as_slice(typed).len() };
2560 let payload = unsafe { storage_as_slice_mut(payload) };
2561 for slot in payload[typed_len..].iter_mut() {
2562 slot.write(ValRaw::u64(0));
2563 }
2564 Ok(())
2565}
2566
2567unsafe impl<T, E> ComponentVariant for Result<T, E>
2568where
2569 T: ComponentType,
2570 E: ComponentType,
2571{
2572 const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2573}
2574
2575unsafe impl<T, E> Lower for Result<T, E>
2576where
2577 T: Lower,
2578 E: Lower,
2579{
2580 fn linear_lower_to_flat<U>(
2581 &self,
2582 cx: &mut LowerContext<'_, U>,
2583 ty: InterfaceType,
2584 dst: &mut MaybeUninit<Self::Lower>,
2585 ) -> Result<()> {
2586 let (ok, err) = match ty {
2587 InterfaceType::Result(ty) => {
2588 let ty = &cx.types[ty];
2589 (ty.ok, ty.err)
2590 }
2591 _ => bad_type_info(),
2592 };
2593
2594 match self {
2656 Ok(e) => {
2657 map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2658 unsafe {
2659 lower_payload(
2660 map_maybe_uninit!(dst.payload),
2661 |payload| map_maybe_uninit!(payload.ok),
2662 |dst| match ok {
2663 Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2664 None => Ok(()),
2665 },
2666 )
2667 }
2668 }
2669 Err(e) => {
2670 map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2671 unsafe {
2672 lower_payload(
2673 map_maybe_uninit!(dst.payload),
2674 |payload| map_maybe_uninit!(payload.err),
2675 |dst| match err {
2676 Some(err) => e.linear_lower_to_flat(cx, err, dst),
2677 None => Ok(()),
2678 },
2679 )
2680 }
2681 }
2682 }
2683 }
2684
2685 fn linear_lower_to_memory<U>(
2686 &self,
2687 cx: &mut LowerContext<'_, U>,
2688 ty: InterfaceType,
2689 offset: usize,
2690 ) -> Result<()> {
2691 let (ok, err) = match ty {
2692 InterfaceType::Result(ty) => {
2693 let ty = &cx.types[ty];
2694 (ty.ok, ty.err)
2695 }
2696 _ => bad_type_info(),
2697 };
2698 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2699 let payload_offset = Self::INFO.payload_offset32 as usize;
2700 match self {
2701 Ok(e) => {
2702 cx.get::<1>(offset)[0] = 0;
2703 if let Some(ok) = ok {
2704 e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2705 }
2706 }
2707 Err(e) => {
2708 cx.get::<1>(offset)[0] = 1;
2709 if let Some(err) = err {
2710 e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2711 }
2712 }
2713 }
2714 Ok(())
2715 }
2716}
2717
2718unsafe impl<T, E> Lift for Result<T, E>
2719where
2720 T: Lift,
2721 E: Lift,
2722{
2723 #[inline]
2724 fn linear_lift_from_flat(
2725 cx: &mut LiftContext<'_>,
2726 ty: InterfaceType,
2727 src: &Self::Lower,
2728 ) -> Result<Self> {
2729 let (ok, err) = match ty {
2730 InterfaceType::Result(ty) => {
2731 let ty = &cx.types[ty];
2732 (ty.ok, ty.err)
2733 }
2734 _ => bad_type_info(),
2735 };
2736 Ok(match src.tag.get_i32() {
2756 0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2757 1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2758 _ => bail!("invalid expected discriminant"),
2759 })
2760 }
2761
2762 #[inline]
2763 fn linear_lift_from_memory(
2764 cx: &mut LiftContext<'_>,
2765 ty: InterfaceType,
2766 bytes: &[u8],
2767 ) -> Result<Self> {
2768 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2769 let discrim = bytes[0];
2770 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2771 let (ok, err) = match ty {
2772 InterfaceType::Result(ty) => {
2773 let ty = &cx.types[ty];
2774 (ty.ok, ty.err)
2775 }
2776 _ => bad_type_info(),
2777 };
2778 match discrim {
2779 0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2780 1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2781 _ => bail!("invalid expected discriminant"),
2782 }
2783 }
2784}
2785
2786fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2787where
2788 T: Lift,
2789{
2790 match ty {
2791 Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2792 None => Ok(empty_lift()),
2793 }
2794}
2795
2796fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2797where
2798 T: Lift,
2799{
2800 match ty {
2801 Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2802 None => Ok(empty_lift()),
2803 }
2804}
2805
2806fn empty_lift<T>() -> T
2807where
2808 T: Lift,
2809{
2810 assert!(T::IS_RUST_UNIT_TYPE);
2811 assert_eq!(mem::size_of::<T>(), 0);
2812 unsafe { MaybeUninit::uninit().assume_init() }
2813}
2814
2815#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2820#[doc(hidden)]
2821#[derive(Clone, Copy)]
2822#[repr(C)]
2823pub struct TupleLower<
2824 T1 = (),
2825 T2 = (),
2826 T3 = (),
2827 T4 = (),
2828 T5 = (),
2829 T6 = (),
2830 T7 = (),
2831 T8 = (),
2832 T9 = (),
2833 T10 = (),
2834 T11 = (),
2835 T12 = (),
2836 T13 = (),
2837 T14 = (),
2838 T15 = (),
2839 T16 = (),
2840 T17 = (),
2841> {
2842 A1: T1,
2844 A2: T2,
2845 A3: T3,
2846 A4: T4,
2847 A5: T5,
2848 A6: T6,
2849 A7: T7,
2850 A8: T8,
2851 A9: T9,
2852 A10: T10,
2853 A11: T11,
2854 A12: T12,
2855 A13: T13,
2856 A14: T14,
2857 A15: T15,
2858 A16: T16,
2859 A17: T17,
2860 _align_tuple_lower0_correctly: [ValRaw; 0],
2861}
2862
2863macro_rules! impl_component_ty_for_tuples {
2864 ($n:tt $($t:ident)*) => {
2865 #[allow(non_snake_case, reason = "macro-generated code")]
2866 unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2867 where $($t: ComponentType),*
2868 {
2869 type Lower = TupleLower<$($t::Lower),*>;
2870
2871 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2872 $($t::ABI),*
2873 ]);
2874 const MAY_REQUIRE_REALLOC: bool = false $(|| $t::MAY_REQUIRE_REALLOC)*;
2875
2876 const IS_RUST_UNIT_TYPE: bool = {
2877 let mut _is_unit = true;
2878 $(
2879 let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2880 _is_unit = false;
2881 )*
2882 _is_unit
2883 };
2884
2885 fn typecheck(
2886 ty: &InterfaceType,
2887 types: &InstanceType<'_>,
2888 ) -> Result<()> {
2889 typecheck_tuple(ty, types, &[$($t::typecheck),*])
2890 }
2891 }
2892
2893 #[allow(non_snake_case, reason = "macro-generated code")]
2894 unsafe impl<$($t,)*> Lower for ($($t,)*)
2895 where $($t: Lower),*
2896 {
2897 fn linear_lower_to_flat<U>(
2898 &self,
2899 cx: &mut LowerContext<'_, U>,
2900 ty: InterfaceType,
2901 _dst: &mut MaybeUninit<Self::Lower>,
2902 ) -> Result<()> {
2903 let types = match ty {
2904 InterfaceType::Tuple(t) => &cx.types[t].types,
2905 _ => bad_type_info(),
2906 };
2907 let ($($t,)*) = self;
2908 let mut _types = types.iter();
2909 $(
2910 let ty = *_types.next().unwrap_or_else(bad_type_info);
2911 $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2912 )*
2913 Ok(())
2914 }
2915
2916 fn linear_lower_to_memory<U>(
2917 &self,
2918 cx: &mut LowerContext<'_, U>,
2919 ty: InterfaceType,
2920 mut _offset: usize,
2921 ) -> Result<()> {
2922 debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2923 let types = match ty {
2924 InterfaceType::Tuple(t) => &cx.types[t].types,
2925 _ => bad_type_info(),
2926 };
2927 let ($($t,)*) = self;
2928 let mut _types = types.iter();
2929 $(
2930 let ty = *_types.next().unwrap_or_else(bad_type_info);
2931 $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2932 )*
2933 Ok(())
2934 }
2935 }
2936
2937 #[allow(non_snake_case, reason = "macro-generated code")]
2938 unsafe impl<$($t,)*> Lift for ($($t,)*)
2939 where $($t: Lift),*
2940 {
2941 #[inline]
2942 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
2943 let types = match ty {
2944 InterfaceType::Tuple(t) => &cx.types[t].types,
2945 _ => bad_type_info(),
2946 };
2947 let mut _types = types.iter();
2948 Ok(($(
2949 $t::linear_lift_from_flat(
2950 cx,
2951 *_types.next().unwrap_or_else(bad_type_info),
2952 &_src.$t,
2953 )?,
2954 )*))
2955 }
2956
2957 #[inline]
2958 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
2959 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2960 let types = match ty {
2961 InterfaceType::Tuple(t) => &cx.types[t].types,
2962 _ => bad_type_info(),
2963 };
2964 let mut _types = types.iter();
2965 let mut _offset = 0;
2966 $(
2967 let ty = *_types.next().unwrap_or_else(bad_type_info);
2968 let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
2969 )*
2970 Ok(($($t,)*))
2971 }
2972 }
2973
2974 #[allow(non_snake_case, reason = "macro-generated code")]
2975 unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
2976 where $($t: ComponentType),*
2977 {}
2978 };
2979}
2980
2981for_each_function_signature!(impl_component_ty_for_tuples);
2982
2983unsafe impl<T, const N: usize> ComponentType for [T; N]
2984where
2985 T: ComponentType,
2986{
2987 type Lower = [T::Lower; N];
2988
2989 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_length_list_static(&T::ABI, N);
2990
2991 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2992 match ty {
2993 InterfaceType::FixedLengthList(t) => {
2994 let list = &types.types[*t];
2995 match usize::try_from(list.size) {
2996 Ok(n) if n == N => {}
2997 _ => bail!("expected `list<_, {}>` found `list<_, {N}>`", list.size),
2998 }
2999 T::typecheck(&list.element, types)
3000 }
3001 other => bail!("expected `list<_, {N}>` found `{}`", desc(other)),
3002 }
3003 }
3004}
3005
3006unsafe impl<T, const N: usize> Lower for [T; N]
3007where
3008 T: Lower,
3009{
3010 fn linear_lower_to_flat<U>(
3011 &self,
3012 cx: &mut LowerContext<'_, U>,
3013 ty: InterfaceType,
3014 dst: &mut MaybeUninit<Self::Lower>,
3015 ) -> Result<()> {
3016 let element = match ty {
3017 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3018 _ => bad_type_info(),
3019 };
3020 for (i, val) in self.iter().enumerate() {
3021 val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
3022 }
3023 Ok(())
3024 }
3025
3026 fn linear_lower_to_memory<U>(
3027 &self,
3028 cx: &mut LowerContext<'_, U>,
3029 ty: InterfaceType,
3030 offset: usize,
3031 ) -> Result<()> {
3032 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
3033 let element = match ty {
3034 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3035 _ => bad_type_info(),
3036 };
3037 for (i, val) in self.iter().enumerate() {
3038 val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
3039 }
3040 Ok(())
3041 }
3042}
3043
3044unsafe impl<T, const N: usize> Lift for [T; N]
3045where
3046 T: Lift + Sized,
3047{
3048 fn linear_lift_from_flat(
3049 cx: &mut LiftContext<'_>,
3050 ty: InterfaceType,
3051 src: &Self::Lower,
3052 ) -> Result<Self> {
3053 let element = match ty {
3054 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3055 _ => bad_type_info(),
3056 };
3057 array_try_from_fn(|n| T::linear_lift_from_flat(cx, element, &src[n]))
3058 }
3059
3060 fn linear_lift_from_memory(
3061 cx: &mut LiftContext<'_>,
3062 ty: InterfaceType,
3063 bytes: &[u8],
3064 ) -> Result<Self> {
3065 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3066 let element = match ty {
3067 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3068 _ => bad_type_info(),
3069 };
3070 let mut offset = 0;
3071 array_try_from_fn(|_n| {
3072 let res = T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]);
3073 offset += T::SIZE32;
3074 res
3075 })
3076 }
3077}
3078
3079pub fn desc(ty: &InterfaceType) -> &'static str {
3080 match ty {
3081 InterfaceType::U8 => "u8",
3082 InterfaceType::S8 => "s8",
3083 InterfaceType::U16 => "u16",
3084 InterfaceType::S16 => "s16",
3085 InterfaceType::U32 => "u32",
3086 InterfaceType::S32 => "s32",
3087 InterfaceType::U64 => "u64",
3088 InterfaceType::S64 => "s64",
3089 InterfaceType::Float32 => "f32",
3090 InterfaceType::Float64 => "f64",
3091 InterfaceType::Bool => "bool",
3092 InterfaceType::Char => "char",
3093 InterfaceType::String => "string",
3094 InterfaceType::List(_) => "list",
3095 InterfaceType::Tuple(_) => "tuple",
3096 InterfaceType::Option(_) => "option",
3097 InterfaceType::Result(_) => "result",
3098
3099 InterfaceType::Record(_) => "record",
3100 InterfaceType::Variant(_) => "variant",
3101 InterfaceType::Flags(_) => "flags",
3102 InterfaceType::Enum(_) => "enum",
3103 InterfaceType::Own(_) => "owned resource",
3104 InterfaceType::Borrow(_) => "borrowed resource",
3105 InterfaceType::Future(_) => "future",
3106 InterfaceType::Stream(_) => "stream",
3107 InterfaceType::ErrorContext(_) => "error-context",
3108 InterfaceType::Map(_) => "map",
3109 InterfaceType::FixedLengthList(_) => "list<_, N>",
3110 }
3111}
3112
3113#[cold]
3114#[doc(hidden)]
3115pub fn bad_type_info<T>() -> T {
3116 panic!("bad type information detected");
3120}