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