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