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