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 alloc::collections::BTreeMap;
10use core::fmt;
11use core::hash::{BuildHasher, Hash};
12use core::iter;
13use core::marker;
14use core::mem::{self, MaybeUninit};
15use core::str;
16use indexmap::IndexMap;
17use wasmtime_core::array::array_try_from_fn;
18use wasmtime_environ::component::{
19 CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
20 OptionsIndex, StringEncoding, TypeMap, VariantInfo,
21};
22
23pub struct TypedFunc<Params, Return> {
38 func: Func,
39
40 _marker: marker::PhantomData<(Params, Return)>,
60}
61
62impl<Params, Return> Copy for TypedFunc<Params, Return> {}
63
64impl<Params, Return> Clone for TypedFunc<Params, Return> {
65 fn clone(&self) -> TypedFunc<Params, Return> {
66 *self
67 }
68}
69
70impl<Params, Return> TypedFunc<Params, Return>
71where
72 Params: ComponentNamedList + Lower,
73 Return: ComponentNamedList + Lift,
74{
75 pub unsafe fn new_unchecked(func: Func) -> TypedFunc<Params, Return> {
86 TypedFunc {
87 _marker: marker::PhantomData,
88 func,
89 }
90 }
91
92 pub fn func(&self) -> &Func {
95 &self.func
96 }
97
98 pub fn call(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
154 let mut store = store.as_context_mut();
155 store.0.validate_sync_call()?;
156 self.call_impl(store.as_context_mut(), params)
157 }
158
159 #[cfg(feature = "async")]
172 pub async fn call_async(
173 &self,
174 mut store: impl AsContextMut<Data: Send>,
175 params: Params,
176 ) -> Result<Return>
177 where
178 Return: 'static,
179 {
180 let mut store = store.as_context_mut();
181
182 #[cfg(feature = "component-model-async")]
183 if store.0.concurrency_support() {
184 return self.call_async_concurrent(store, params).await;
185 }
186
187 store
188 .on_fiber(|store| self.call_impl(store, params))
189 .await?
190 }
191
192 pub(crate) fn lower_args<T>(
193 cx: &mut LowerContext<T>,
194 ty: InterfaceType,
195 dst: &mut [MaybeUninit<ValRaw>],
196 params: &Params,
197 ) -> Result<()> {
198 use crate::component::storage::slice_to_storage_mut;
199
200 if Params::flatten_count() <= MAX_FLAT_PARAMS {
201 let dst: &mut MaybeUninit<Params::Lower> = unsafe { slice_to_storage_mut(dst) };
206 Self::lower_stack_args(cx, ¶ms, ty, dst)
207 } else {
208 Self::lower_heap_args(cx, ¶ms, ty, &mut dst[0])
209 }
210 }
211
212 fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
213 let mut store = store.as_context_mut();
214
215 if self.func.is_async(store.0) {
216 bail!(
217 "cannot synchronously call an async function; \
218 use `call_async` or `call_concurrent` instead"
219 );
220 }
221
222 let result = unsafe {
240 #[derive(Copy, Clone)]
247 union Union<T: Copy, U: Copy> {
248 _a: T,
249 _b: U,
250 }
251
252 if Return::flatten_count() <= MAX_FLAT_RESULTS {
253 self.func.call_raw(
254 store.as_context_mut(),
255 |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
256 let dst = storage_as_slice_mut(dst);
257 Self::lower_args(cx, ty, dst, ¶ms)
258 },
259 Self::lift_stack_result,
260 )
261 } else {
262 self.func.call_raw(
263 store.as_context_mut(),
264 |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
265 let dst = storage_as_slice_mut(dst);
266 Self::lower_args(cx, ty, dst, ¶ms)
267 },
268 Self::lift_heap_result,
269 )
270 }
271 };
272
273 if result.is_err() {
274 store.0.set_trapped();
275 }
276
277 result
278 }
279
280 fn lower_stack_args<T>(
287 cx: &mut LowerContext<'_, T>,
288 params: &Params,
289 ty: InterfaceType,
290 dst: &mut MaybeUninit<Params::Lower>,
291 ) -> Result<()> {
292 assert!(Params::flatten_count() <= MAX_FLAT_PARAMS);
293 params.linear_lower_to_flat(cx, ty, dst)?;
294 Ok(())
295 }
296
297 fn lower_heap_args<T>(
304 cx: &mut LowerContext<'_, T>,
305 params: &Params,
306 ty: InterfaceType,
307 dst: &mut MaybeUninit<ValRaw>,
308 ) -> Result<()> {
309 let ptr = cx.realloc(0, 0, Params::ALIGN32, Params::SIZE32)?;
317 params.linear_lower_to_memory(cx, ty, ptr)?;
318
319 dst.write(ValRaw::i64(ptr as i64));
330
331 Ok(())
332 }
333
334 pub(crate) fn lift_stack_result(
339 cx: &mut LiftContext<'_>,
340 ty: InterfaceType,
341 dst: &Return::Lower,
342 ) -> Result<Return> {
343 Return::linear_lift_from_flat(cx, ty, dst)
344 }
345
346 pub(crate) fn lift_heap_result(
349 cx: &mut LiftContext<'_>,
350 ty: InterfaceType,
351 dst: &ValRaw,
352 ) -> Result<Return> {
353 assert!(Return::flatten_count() > MAX_FLAT_RESULTS);
354 let ptr = usize::try_from(dst.get_u32())?;
356 if ptr % usize::try_from(Return::ALIGN32)? != 0 {
357 bail!("return pointer not aligned");
358 }
359
360 let bytes = cx
361 .memory()
362 .get(ptr..)
363 .and_then(|b| b.get(..Return::SIZE32))
364 .ok_or_else(|| crate::format_err!("pointer out of bounds of memory"))?;
365 Return::linear_lift_from_memory(cx, ty, bytes)
366 }
367
368 #[doc(hidden)]
369 #[deprecated(note = "no longer needs to be called; this function has no effect")]
370 pub fn post_return(&self, _store: impl AsContextMut) -> Result<()> {
371 Ok(())
372 }
373
374 #[doc(hidden)]
375 #[deprecated(note = "no longer needs to be called; this function has no effect")]
376 #[cfg(feature = "async")]
377 pub async fn post_return_async<T: Send>(
378 &self,
379 _store: impl AsContextMut<Data = T>,
380 ) -> Result<()> {
381 Ok(())
382 }
383}
384
385pub unsafe trait ComponentNamedList: ComponentType {}
402
403pub unsafe trait ComponentType: Send + Sync {
511 #[doc(hidden)]
519 type Lower: Copy;
520
521 #[doc(hidden)]
523 const ABI: CanonicalAbiInfo;
524
525 #[doc(hidden)]
526 const SIZE32: usize = Self::ABI.size32 as usize;
527 #[doc(hidden)]
528 const ALIGN32: u32 = Self::ABI.align32;
529
530 #[doc(hidden)]
531 const IS_RUST_UNIT_TYPE: bool = false;
532
533 #[doc(hidden)]
541 const MAY_REQUIRE_REALLOC: bool = true;
542
543 #[doc(hidden)]
548 fn flatten_count() -> usize {
549 assert!(mem::size_of::<Self::Lower>() % mem::size_of::<ValRaw>() == 0);
550 assert!(mem::align_of::<Self::Lower>() == mem::align_of::<ValRaw>());
551 mem::size_of::<Self::Lower>() / mem::size_of::<ValRaw>()
552 }
553
554 #[doc(hidden)]
557 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()>;
558}
559
560#[doc(hidden)]
561pub unsafe trait ComponentVariant: ComponentType {
562 const CASES: &'static [Option<CanonicalAbiInfo>];
563 const INFO: VariantInfo = VariantInfo::new_static(Self::CASES);
564 const PAYLOAD_OFFSET32: usize = Self::INFO.payload_offset32 as usize;
565}
566
567pub unsafe trait Lower: ComponentType {
586 #[doc(hidden)]
605 fn linear_lower_to_flat<T>(
606 &self,
607 cx: &mut LowerContext<'_, T>,
608 ty: InterfaceType,
609 dst: &mut MaybeUninit<Self::Lower>,
610 ) -> Result<()>;
611
612 #[doc(hidden)]
631 fn linear_lower_to_memory<T>(
632 &self,
633 cx: &mut LowerContext<'_, T>,
634 ty: InterfaceType,
635 offset: usize,
636 ) -> Result<()>;
637
638 #[doc(hidden)]
647 fn linear_store_list_to_memory<T>(
648 cx: &mut LowerContext<'_, T>,
649 ty: InterfaceType,
650 mut offset: usize,
651 items: &[Self],
652 ) -> Result<()>
653 where
654 Self: Sized,
655 {
656 for item in items {
657 item.linear_lower_to_memory(cx, ty, offset)?;
658 offset += Self::SIZE32;
659 }
660 Ok(())
661 }
662}
663
664pub unsafe trait Lift: Sized + ComponentType {
681 #[doc(hidden)]
698 fn linear_lift_from_flat(
699 cx: &mut LiftContext<'_>,
700 ty: InterfaceType,
701 src: &Self::Lower,
702 ) -> Result<Self>;
703
704 #[doc(hidden)]
719 fn linear_lift_from_memory(
720 cx: &mut LiftContext<'_>,
721 ty: InterfaceType,
722 bytes: &[u8],
723 ) -> Result<Self>;
724
725 #[doc(hidden)]
727 fn linear_lift_list_from_memory(
728 cx: &mut LiftContext<'_>,
729 list: &WasmList<Self>,
730 ) -> Result<Vec<Self>>
731 where
732 Self: Sized,
733 {
734 let mut dst = Vec::with_capacity(list.len);
735 Self::linear_lift_into_from_memory(cx, list, &mut dst)?;
736 Ok(dst)
737 }
738
739 #[doc(hidden)]
745 fn linear_lift_into_from_memory(
746 cx: &mut LiftContext<'_>,
747 list: &WasmList<Self>,
748 dst: &mut impl Extend<Self>,
749 ) -> Result<()>
750 where
751 Self: Sized,
752 {
753 for i in 0..list.len {
754 dst.extend(Some(list.get_from_store(cx, i).unwrap()?));
755 }
756 Ok(())
757 }
758}
759
760macro_rules! forward_type_impls {
765 ($(
766 $(#[$attr:meta])*
767 ($($generics:tt)*) $a:ty => $b:ty,
768 )*) => ($(
769 $(#[$attr])*
770 unsafe impl <$($generics)*> ComponentType for $a {
771 type Lower = <$b as ComponentType>::Lower;
772
773 const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
774 const MAY_REQUIRE_REALLOC: bool = <$b as ComponentType>::MAY_REQUIRE_REALLOC;
775
776 #[inline]
777 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
778 <$b as ComponentType>::typecheck(ty, types)
779 }
780 }
781 )*)
782}
783
784forward_type_impls! {
785 (T: ComponentType + ?Sized) &'_ T => T,
786 (T: ComponentType + ?Sized) Box<T> => T,
787 (T: ComponentType + ?Sized) alloc::sync::Arc<T> => T,
788 () String => str,
789 (T: ComponentType) Vec<T> => [T],
790 #[cfg(feature = "component-model-bytes")]
791 () bytes::Bytes => [u8],
792 #[cfg(feature = "component-model-bytes")]
793 () bytes::BytesMut => [u8],
794}
795
796macro_rules! forward_lowers {
797 ($(
798 $(#[$attr:meta])*
799 ($($generics:tt)*) $a:ty => $b:ty,
800 )*) => ($(
801 $(#[$attr])*
802 unsafe impl <$($generics)*> Lower for $a {
803 fn linear_lower_to_flat<U>(
804 &self,
805 cx: &mut LowerContext<'_, U>,
806 ty: InterfaceType,
807 dst: &mut MaybeUninit<Self::Lower>,
808 ) -> Result<()> {
809 <$b as Lower>::linear_lower_to_flat(self, cx, ty, dst)
810 }
811
812 fn linear_lower_to_memory<U>(
813 &self,
814 cx: &mut LowerContext<'_, U>,
815 ty: InterfaceType,
816 offset: usize,
817 ) -> Result<()> {
818 <$b as Lower>::linear_lower_to_memory(self, cx, ty, offset)
819 }
820 }
821 )*)
822}
823
824forward_lowers! {
825 (T: Lower + ?Sized) &'_ T => T,
826 (T: Lower + ?Sized) Box<T> => T,
827 (T: Lower + ?Sized) alloc::sync::Arc<T> => T,
828 () String => str,
829 (T: Lower) Vec<T> => [T],
830 #[cfg(feature = "component-model-bytes")]
831 () bytes::Bytes => [u8],
832 #[cfg(feature = "component-model-bytes")]
833 () bytes::BytesMut => [u8],
834}
835
836macro_rules! forward_string_lifts {
837 ($($a:ty,)*) => ($(
838 unsafe impl Lift for $a {
839 #[inline]
840 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
841 let s = <WasmStr as Lift>::linear_lift_from_flat(cx, ty, src)?;
842 let encoding = cx.options().string_encoding;
843 Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
844 }
845
846 #[inline]
847 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
848 let s = <WasmStr as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
849 let encoding = cx.options().string_encoding;
850 Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
851 }
852 }
853 )*)
854}
855
856forward_string_lifts! {
857 Box<str>,
858 alloc::sync::Arc<str>,
859 String,
860}
861
862macro_rules! forward_list_lifts {
863 ($(
864 $(#[$attr:meta])*
865 ($($generics:tt)*) $a:ty => WasmList<$b:ty> $(( $via:ident $c:ty ))?,
866 )*) => ($(
867 $(#[$attr])*
868 unsafe impl <$($generics)*> Lift for $a {
869 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
870 let list = <WasmList::<$b> as Lift>::linear_lift_from_flat(cx, ty, src)?;
871 let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
872 $(let vec = <$c>::from(vec);)?
873 Ok(Self::from(vec))
874 }
875
876 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
877 let list = <WasmList::<$b> as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
878 let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
879 $(let vec = <$c>::from(vec);)?
880 Ok(Self::from(vec))
881 }
882 }
883 )*)
884}
885
886forward_list_lifts! {
887 (T: Lift) Box<[T]> => WasmList<T>,
888 (T: Lift) alloc::sync::Arc<[T]> => WasmList<T>,
889 (T: Lift) Vec<T> => WasmList<T>,
890 #[cfg(feature = "component-model-bytes")]
891 () bytes::Bytes => WasmList<u8>,
892 #[cfg(feature = "component-model-bytes")]
895 () bytes::BytesMut => WasmList<u8> (via bytes::Bytes),
896}
897
898macro_rules! integers {
901 ($($primitive:ident = $ty:ident in $field:ident/$get:ident with abi:$abi:ident,)*) => ($(
902 unsafe impl ComponentType for $primitive {
903 type Lower = ValRaw;
904
905 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
906
907 const MAY_REQUIRE_REALLOC: bool = false;
908
909 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
910 match ty {
911 InterfaceType::$ty => Ok(()),
912 other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
913 }
914 }
915 }
916
917 unsafe impl Lower for $primitive {
918 #[inline]
919 #[allow(trivial_numeric_casts, reason = "macro-generated code")]
920 fn linear_lower_to_flat<T>(
921 &self,
922 _cx: &mut LowerContext<'_, T>,
923 ty: InterfaceType,
924 dst: &mut MaybeUninit<Self::Lower>,
925 ) -> Result<()> {
926 debug_assert!(matches!(ty, InterfaceType::$ty));
927 dst.write(ValRaw::$field(*self as $field));
928 Ok(())
929 }
930
931 #[inline]
932 fn linear_lower_to_memory<T>(
933 &self,
934 cx: &mut LowerContext<'_, T>,
935 ty: InterfaceType,
936 offset: usize,
937 ) -> Result<()> {
938 debug_assert!(matches!(ty, InterfaceType::$ty));
939 debug_assert!(offset % Self::SIZE32 == 0);
940 *cx.get(offset) = self.to_le_bytes();
941 Ok(())
942 }
943
944 fn linear_store_list_to_memory<T>(
945 cx: &mut LowerContext<'_, T>,
946 ty: InterfaceType,
947 offset: usize,
948 items: &[Self],
949 ) -> Result<()> {
950 debug_assert!(matches!(ty, InterfaceType::$ty));
951
952 assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
956
957 let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
967 let (before, middle, end) = unsafe { dst.align_to_mut::<Self>() };
968 assert!(before.is_empty() && end.is_empty());
969 assert_eq!(middle.len(), items.len());
970
971 for (dst, src) in middle.iter_mut().zip(items) {
976 *dst = src.to_le();
977 }
978 Ok(())
979 }
980 }
981
982 unsafe impl Lift for $primitive {
983 #[inline]
984 #[allow(
985 trivial_numeric_casts,
986 clippy::cast_possible_truncation,
987 reason = "macro-generated code"
988 )]
989 fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
990 debug_assert!(matches!(ty, InterfaceType::$ty));
991 Ok(src.$get() as $primitive)
992 }
993
994 #[inline]
995 fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
996 debug_assert!(matches!(ty, InterfaceType::$ty));
997 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
998 Ok($primitive::from_le_bytes(*bytes.as_array().unwrap()))
999 }
1000
1001 fn linear_lift_into_from_memory(
1002 cx: &mut LiftContext<'_>,
1003 list: &WasmList<Self>,
1004 dst: &mut impl Extend<Self>,
1005 ) -> Result<()>
1006 where
1007 Self: Sized,
1008 {
1009 dst.extend(list._as_le_slice(cx.memory())
1010 .iter()
1011 .map(|i| Self::from_le(*i)));
1012 Ok(())
1013 }
1014 }
1015 )*)
1016}
1017
1018integers! {
1019 i8 = S8 in i32/get_i32 with abi:SCALAR1,
1020 u8 = U8 in u32/get_u32 with abi:SCALAR1,
1021 i16 = S16 in i32/get_i32 with abi:SCALAR2,
1022 u16 = U16 in u32/get_u32 with abi:SCALAR2,
1023 i32 = S32 in i32/get_i32 with abi:SCALAR4,
1024 u32 = U32 in u32/get_u32 with abi:SCALAR4,
1025 i64 = S64 in i64/get_i64 with abi:SCALAR8,
1026 u64 = U64 in u64/get_u64 with abi:SCALAR8,
1027}
1028
1029macro_rules! floats {
1030 ($($float:ident/$get_float:ident = $ty:ident with abi:$abi:ident)*) => ($(const _: () = {
1031 unsafe impl ComponentType for $float {
1032 type Lower = ValRaw;
1033
1034 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
1035 const MAY_REQUIRE_REALLOC: bool = false;
1036
1037 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1038 match ty {
1039 InterfaceType::$ty => Ok(()),
1040 other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
1041 }
1042 }
1043 }
1044
1045 unsafe impl Lower for $float {
1046 #[inline]
1047 fn linear_lower_to_flat<T>(
1048 &self,
1049 _cx: &mut LowerContext<'_, T>,
1050 ty: InterfaceType,
1051 dst: &mut MaybeUninit<Self::Lower>,
1052 ) -> Result<()> {
1053 debug_assert!(matches!(ty, InterfaceType::$ty));
1054 dst.write(ValRaw::$float(self.to_bits()));
1055 Ok(())
1056 }
1057
1058 #[inline]
1059 fn linear_lower_to_memory<T>(
1060 &self,
1061 cx: &mut LowerContext<'_, T>,
1062 ty: InterfaceType,
1063 offset: usize,
1064 ) -> Result<()> {
1065 debug_assert!(matches!(ty, InterfaceType::$ty));
1066 debug_assert!(offset % Self::SIZE32 == 0);
1067 let ptr = cx.get(offset);
1068 *ptr = self.to_bits().to_le_bytes();
1069 Ok(())
1070 }
1071
1072 fn linear_store_list_to_memory<T>(
1073 cx: &mut LowerContext<'_, T>,
1074 ty: InterfaceType,
1075 offset: usize,
1076 items: &[Self],
1077 ) -> Result<()> {
1078 debug_assert!(matches!(ty, InterfaceType::$ty));
1079
1080 assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
1084
1085 let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
1090 assert!(dst.as_ptr().cast::<Self>().is_aligned());
1091
1092 let (dst, rest) = dst.as_chunks_mut::<{Self::SIZE32}>();
1097 debug_assert!(rest.is_empty());
1098 for (dst, src) in iter::zip(dst, items) {
1099 *dst = src.to_le_bytes();
1100 }
1101 Ok(())
1102 }
1103 }
1104
1105 unsafe impl Lift for $float {
1106 #[inline]
1107 fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1108 debug_assert!(matches!(ty, InterfaceType::$ty));
1109 Ok($float::from_bits(src.$get_float()))
1110 }
1111
1112 #[inline]
1113 fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1114 debug_assert!(matches!(ty, InterfaceType::$ty));
1115 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1116 Ok($float::from_le_bytes(*bytes.as_array().unwrap()))
1117 }
1118
1119 fn linear_lift_list_from_memory(cx: &mut LiftContext<'_>, list: &WasmList<Self>) -> Result<Vec<Self>> where Self: Sized {
1120 let byte_size = list.len * mem::size_of::<Self>();
1122 let bytes = &cx.memory()[list.ptr..][..byte_size];
1123
1124 assert!(bytes.as_ptr().cast::<Self>().is_aligned());
1127
1128 let (src, rest) = bytes.as_chunks::<{Self::SIZE32}>();
1131 debug_assert!(rest.is_empty());
1132 Ok(
1133 src
1134 .iter()
1135 .map(|i| $float::from_le_bytes(*i))
1136 .collect()
1137 )
1138 }
1139 }
1140 };)*)
1141}
1142
1143floats! {
1144 f32/get_f32 = Float32 with abi:SCALAR4
1145 f64/get_f64 = Float64 with abi:SCALAR8
1146}
1147
1148unsafe impl ComponentType for bool {
1149 type Lower = ValRaw;
1150
1151 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR1;
1152 const MAY_REQUIRE_REALLOC: bool = false;
1153
1154 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1155 match ty {
1156 InterfaceType::Bool => Ok(()),
1157 other => bail!("expected `bool` found `{}`", desc(other)),
1158 }
1159 }
1160}
1161
1162unsafe impl Lower for bool {
1163 fn linear_lower_to_flat<T>(
1164 &self,
1165 _cx: &mut LowerContext<'_, T>,
1166 ty: InterfaceType,
1167 dst: &mut MaybeUninit<Self::Lower>,
1168 ) -> Result<()> {
1169 debug_assert!(matches!(ty, InterfaceType::Bool));
1170 dst.write(ValRaw::i32(*self as i32));
1171 Ok(())
1172 }
1173
1174 fn linear_lower_to_memory<T>(
1175 &self,
1176 cx: &mut LowerContext<'_, T>,
1177 ty: InterfaceType,
1178 offset: usize,
1179 ) -> Result<()> {
1180 debug_assert!(matches!(ty, InterfaceType::Bool));
1181 debug_assert!(offset % Self::SIZE32 == 0);
1182 cx.get::<1>(offset)[0] = *self as u8;
1183 Ok(())
1184 }
1185}
1186
1187unsafe impl Lift for bool {
1188 #[inline]
1189 fn linear_lift_from_flat(
1190 _cx: &mut LiftContext<'_>,
1191 ty: InterfaceType,
1192 src: &Self::Lower,
1193 ) -> Result<Self> {
1194 debug_assert!(matches!(ty, InterfaceType::Bool));
1195 match src.get_i32() {
1196 0 => Ok(false),
1197 _ => Ok(true),
1198 }
1199 }
1200
1201 #[inline]
1202 fn linear_lift_from_memory(
1203 _cx: &mut LiftContext<'_>,
1204 ty: InterfaceType,
1205 bytes: &[u8],
1206 ) -> Result<Self> {
1207 debug_assert!(matches!(ty, InterfaceType::Bool));
1208 match bytes[0] {
1209 0 => Ok(false),
1210 _ => Ok(true),
1211 }
1212 }
1213}
1214
1215unsafe impl ComponentType for char {
1216 type Lower = ValRaw;
1217
1218 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1219 const MAY_REQUIRE_REALLOC: bool = false;
1220
1221 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1222 match ty {
1223 InterfaceType::Char => Ok(()),
1224 other => bail!("expected `char` found `{}`", desc(other)),
1225 }
1226 }
1227}
1228
1229unsafe impl Lower for char {
1230 #[inline]
1231 fn linear_lower_to_flat<T>(
1232 &self,
1233 _cx: &mut LowerContext<'_, T>,
1234 ty: InterfaceType,
1235 dst: &mut MaybeUninit<Self::Lower>,
1236 ) -> Result<()> {
1237 debug_assert!(matches!(ty, InterfaceType::Char));
1238 dst.write(ValRaw::u32(u32::from(*self)));
1239 Ok(())
1240 }
1241
1242 #[inline]
1243 fn linear_lower_to_memory<T>(
1244 &self,
1245 cx: &mut LowerContext<'_, T>,
1246 ty: InterfaceType,
1247 offset: usize,
1248 ) -> Result<()> {
1249 debug_assert!(matches!(ty, InterfaceType::Char));
1250 debug_assert!(offset % Self::SIZE32 == 0);
1251 *cx.get::<4>(offset) = u32::from(*self).to_le_bytes();
1252 Ok(())
1253 }
1254}
1255
1256unsafe impl Lift for char {
1257 #[inline]
1258 fn linear_lift_from_flat(
1259 _cx: &mut LiftContext<'_>,
1260 ty: InterfaceType,
1261 src: &Self::Lower,
1262 ) -> Result<Self> {
1263 debug_assert!(matches!(ty, InterfaceType::Char));
1264 Ok(char::try_from(src.get_u32())?)
1265 }
1266
1267 #[inline]
1268 fn linear_lift_from_memory(
1269 _cx: &mut LiftContext<'_>,
1270 ty: InterfaceType,
1271 bytes: &[u8],
1272 ) -> Result<Self> {
1273 debug_assert!(matches!(ty, InterfaceType::Char));
1274 debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1275 let bits = u32::from_le_bytes(*bytes.as_array().unwrap());
1276 Ok(char::try_from(bits)?)
1277 }
1278}
1279
1280fn lift_pointer_pair_from_flat(
1281 cx: &mut LiftContext<'_>,
1282 src: &[ValRaw; 2],
1283) -> Result<(usize, usize)> {
1284 let _ = cx; let ptr = src[0].get_u32();
1287 let len = src[1].get_u32();
1288 Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1289}
1290
1291fn lift_pointer_pair_from_memory(cx: &mut LiftContext<'_>, bytes: &[u8]) -> Result<(usize, usize)> {
1292 let _ = cx; let ptr = u32::from_le_bytes(*bytes[..4].as_array().unwrap());
1295 let len = u32::from_le_bytes(*bytes[4..].as_array().unwrap());
1296 Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1297}
1298
1299fn lower_pointer_pair_to_flat<T>(
1300 cx: &mut LowerContext<T>,
1301 dst: &mut MaybeUninit<[ValRaw; 2]>,
1302 ptr: usize,
1303 len: usize,
1304) {
1305 let _ = cx; map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64));
1309 map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64));
1310}
1311
1312fn lower_pointer_pair_to_memory<T>(
1313 cx: &mut LowerContext<T>,
1314 offset: usize,
1315 ptr: usize,
1316 len: usize,
1317) {
1318 *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
1320 *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
1321}
1322
1323const UTF16_TAG: usize = 1 << 31;
1325const MAX_STRING_BYTE_LENGTH: usize = (1 << 31) - 1;
1326
1327unsafe impl ComponentType for str {
1330 type Lower = [ValRaw; 2];
1331
1332 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1333
1334 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1335 match ty {
1336 InterfaceType::String => Ok(()),
1337 other => bail!("expected `string` found `{}`", desc(other)),
1338 }
1339 }
1340}
1341
1342unsafe impl Lower for str {
1343 fn linear_lower_to_flat<T>(
1344 &self,
1345 cx: &mut LowerContext<'_, T>,
1346 ty: InterfaceType,
1347 dst: &mut MaybeUninit<[ValRaw; 2]>,
1348 ) -> Result<()> {
1349 debug_assert!(matches!(ty, InterfaceType::String));
1350 let (ptr, len) = lower_string(cx, self)?;
1351 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1352 Ok(())
1353 }
1354
1355 fn linear_lower_to_memory<T>(
1356 &self,
1357 cx: &mut LowerContext<'_, T>,
1358 ty: InterfaceType,
1359 offset: usize,
1360 ) -> Result<()> {
1361 debug_assert!(matches!(ty, InterfaceType::String));
1362 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1363 let (ptr, len) = lower_string(cx, self)?;
1364 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1365 Ok(())
1366 }
1367}
1368
1369fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize, usize)> {
1370 match cx.options().string_encoding {
1386 StringEncoding::Utf8 => {
1391 if string.len() > MAX_STRING_BYTE_LENGTH {
1392 bail!(
1393 "string length of {} too large to copy into wasm",
1394 string.len()
1395 );
1396 }
1397 let ptr = cx.realloc(0, 0, 1, string.len())?;
1398 cx.as_slice_mut()[ptr..][..string.len()].copy_from_slice(string.as_bytes());
1399 Ok((ptr, string.len()))
1400 }
1401
1402 StringEncoding::Utf16 => {
1406 let size = string.len() * 2;
1407 if size > MAX_STRING_BYTE_LENGTH {
1408 bail!(
1409 "string length of {} too large to copy into wasm",
1410 string.len()
1411 );
1412 }
1413 let mut ptr = cx.realloc(0, 0, 2, size)?;
1414 let mut copied = 0;
1415 let bytes = &mut cx.as_slice_mut()[ptr..][..size];
1416 for (u, bytes) in string.encode_utf16().zip(bytes.chunks_mut(2)) {
1417 let u_bytes = u.to_le_bytes();
1418 bytes[0] = u_bytes[0];
1419 bytes[1] = u_bytes[1];
1420 copied += 1;
1421 }
1422 if (copied * 2) < size {
1423 ptr = cx.realloc(ptr, size, 2, copied * 2)?;
1424 }
1425 Ok((ptr, copied))
1426 }
1427
1428 StringEncoding::CompactUtf16 => {
1429 let bytes = string.as_bytes();
1431 let mut iter = string.char_indices();
1432 let mut ptr = cx.realloc(0, 0, 2, bytes.len())?;
1433 let mut dst = &mut cx.as_slice_mut()[ptr..][..bytes.len()];
1434 let mut result = 0;
1435 while let Some((i, ch)) = iter.next() {
1436 if let Ok(byte) = u8::try_from(u32::from(ch)) {
1438 dst[result] = byte;
1439 result += 1;
1440 continue;
1441 }
1442
1443 let worst_case = bytes
1446 .len()
1447 .checked_mul(2)
1448 .ok_or_else(|| format_err!("byte length overflow"))?;
1449 if worst_case > MAX_STRING_BYTE_LENGTH {
1450 bail!("byte length too large");
1451 }
1452 ptr = cx.realloc(ptr, bytes.len(), 2, worst_case)?;
1453 dst = &mut cx.as_slice_mut()[ptr..][..worst_case];
1454
1455 for i in (0..result).rev() {
1458 dst[2 * i] = dst[i];
1459 dst[2 * i + 1] = 0;
1460 }
1461
1462 for (u, bytes) in string[i..]
1464 .encode_utf16()
1465 .zip(dst[2 * result..].chunks_mut(2))
1466 {
1467 let u_bytes = u.to_le_bytes();
1468 bytes[0] = u_bytes[0];
1469 bytes[1] = u_bytes[1];
1470 result += 1;
1471 }
1472 if worst_case > 2 * result {
1473 ptr = cx.realloc(ptr, worst_case, 2, 2 * result)?;
1474 }
1475 return Ok((ptr, result | UTF16_TAG));
1476 }
1477 if result < bytes.len() {
1478 ptr = cx.realloc(ptr, bytes.len(), 2, result)?;
1479 }
1480 Ok((ptr, result))
1481 }
1482 }
1483}
1484
1485pub struct WasmStr {
1516 ptr: usize,
1517 len: usize,
1518 options: OptionsIndex,
1519 instance: Instance,
1520}
1521
1522impl WasmStr {
1523 pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1524 let (byte_len, align) = match cx.options().string_encoding {
1525 StringEncoding::Utf8 => (Some(len), 1_usize),
1526 StringEncoding::Utf16 => (len.checked_mul(2), 2),
1527 StringEncoding::CompactUtf16 => {
1528 if len & UTF16_TAG == 0 {
1529 (Some(len), 2)
1530 } else {
1531 ((len ^ UTF16_TAG).checked_mul(2), 2)
1532 }
1533 }
1534 };
1535 debug_assert!(align.is_power_of_two());
1536 if ptr & (align - 1) != 0 {
1537 bail!("string pointer not aligned to {align}");
1538 }
1539 match byte_len.and_then(|len| ptr.checked_add(len)) {
1540 Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?,
1541 _ => bail!("string pointer/length out of bounds of memory"),
1542 }
1543 Ok(WasmStr {
1544 ptr,
1545 len,
1546 options: cx.options_index(),
1547 instance: cx.instance_handle(),
1548 })
1549 }
1550
1551 pub fn to_str<'a, T: 'static>(
1573 &self,
1574 store: impl Into<StoreContext<'a, T>>,
1575 ) -> Result<Cow<'a, str>> {
1576 let store = store.into().0;
1577 let memory = self.instance.options_memory(store, self.options);
1578 let encoding = self.instance.options(store, self.options).string_encoding;
1579 self.to_str_from_memory(encoding, memory)
1580 }
1581
1582 pub(crate) fn to_str_from_memory<'a>(
1583 &self,
1584 encoding: StringEncoding,
1585 memory: &'a [u8],
1586 ) -> Result<Cow<'a, str>> {
1587 match encoding {
1588 StringEncoding::Utf8 => self.decode_utf8(memory),
1589 StringEncoding::Utf16 => self.decode_utf16(memory, self.len),
1590 StringEncoding::CompactUtf16 => {
1591 if self.len & UTF16_TAG == 0 {
1592 self.decode_latin1(memory)
1593 } else {
1594 self.decode_utf16(memory, self.len ^ UTF16_TAG)
1595 }
1596 }
1597 }
1598 }
1599
1600 fn decode_utf8<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1601 Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into())
1605 }
1606
1607 fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result<Cow<'a, str>> {
1608 let (chunks, rest) = &memory[self.ptr..][..len * 2].as_chunks::<2>();
1610 debug_assert!(rest.is_empty());
1611 Ok(
1612 core::char::decode_utf16(chunks.iter().map(|chunk| u16::from_le_bytes(*chunk)))
1613 .collect::<Result<String, _>>()?
1614 .into(),
1615 )
1616 }
1617
1618 fn decode_latin1<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1619 Ok(encoding_rs::mem::decode_latin1(
1621 &memory[self.ptr..][..self.len],
1622 ))
1623 }
1624}
1625
1626unsafe impl ComponentType for WasmStr {
1629 type Lower = <str as ComponentType>::Lower;
1630
1631 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1632
1633 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1634 match ty {
1635 InterfaceType::String => Ok(()),
1636 other => bail!("expected `string` found `{}`", desc(other)),
1637 }
1638 }
1639}
1640
1641unsafe impl Lift for WasmStr {
1642 #[inline]
1643 fn linear_lift_from_flat(
1644 cx: &mut LiftContext<'_>,
1645 ty: InterfaceType,
1646 src: &Self::Lower,
1647 ) -> Result<Self> {
1648 debug_assert!(matches!(ty, InterfaceType::String));
1649 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1650 WasmStr::new(ptr, len, cx)
1651 }
1652
1653 #[inline]
1654 fn linear_lift_from_memory(
1655 cx: &mut LiftContext<'_>,
1656 ty: InterfaceType,
1657 bytes: &[u8],
1658 ) -> Result<Self> {
1659 debug_assert!(matches!(ty, InterfaceType::String));
1660 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1661 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1662 WasmStr::new(ptr, len, cx)
1663 }
1664}
1665
1666unsafe impl<T> ComponentType for [T]
1667where
1668 T: ComponentType,
1669{
1670 type Lower = [ValRaw; 2];
1671
1672 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1673
1674 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1675 match ty {
1676 InterfaceType::List(t) => T::typecheck(&types.types[*t].element, types),
1677 other => bail!("expected `list` found `{}`", desc(other)),
1678 }
1679 }
1680}
1681
1682unsafe impl<T> Lower for [T]
1683where
1684 T: Lower,
1685{
1686 fn linear_lower_to_flat<U>(
1687 &self,
1688 cx: &mut LowerContext<'_, U>,
1689 ty: InterfaceType,
1690 dst: &mut MaybeUninit<[ValRaw; 2]>,
1691 ) -> Result<()> {
1692 let elem = match ty {
1693 InterfaceType::List(i) => cx.types[i].element,
1694 _ => bad_type_info(),
1695 };
1696 let (ptr, len) = lower_list(cx, elem, self)?;
1697 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1698 Ok(())
1699 }
1700
1701 fn linear_lower_to_memory<U>(
1702 &self,
1703 cx: &mut LowerContext<'_, U>,
1704 ty: InterfaceType,
1705 offset: usize,
1706 ) -> Result<()> {
1707 let elem = match ty {
1708 InterfaceType::List(i) => cx.types[i].element,
1709 _ => bad_type_info(),
1710 };
1711 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1712 let (ptr, len) = lower_list(cx, elem, self)?;
1713 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1714 Ok(())
1715 }
1716}
1717
1718fn lower_list<T, U>(
1734 cx: &mut LowerContext<'_, U>,
1735 ty: InterfaceType,
1736 list: &[T],
1737) -> Result<(usize, usize)>
1738where
1739 T: Lower,
1740{
1741 let elem_size = T::SIZE32;
1742 let size = list
1743 .len()
1744 .checked_mul(elem_size)
1745 .ok_or_else(|| format_err!("size overflow copying a list"))?;
1746 let ptr = cx.realloc(0, 0, T::ALIGN32, size)?;
1747 T::linear_store_list_to_memory(cx, ty, ptr, list)?;
1748 Ok((ptr, list.len()))
1749}
1750
1751pub struct WasmList<T> {
1768 ptr: usize,
1769 len: usize,
1770 options: OptionsIndex,
1771 elem: InterfaceType,
1772 instance: Instance,
1773 _marker: marker::PhantomData<T>,
1774}
1775
1776impl<T: Lift> WasmList<T> {
1777 pub(crate) fn new(
1778 ptr: usize,
1779 len: usize,
1780 cx: &mut LiftContext<'_>,
1781 elem: InterfaceType,
1782 ) -> Result<WasmList<T>> {
1783 match len
1784 .checked_mul(T::SIZE32)
1785 .and_then(|len| ptr.checked_add(len))
1786 {
1787 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<T>())?,
1788 _ => bail!("list pointer/length out of bounds of memory"),
1789 }
1790 if ptr % usize::try_from(T::ALIGN32)? != 0 {
1791 bail!("list pointer is not aligned")
1792 }
1793 Ok(WasmList {
1794 ptr,
1795 len,
1796 options: cx.options_index(),
1797 elem,
1798 instance: cx.instance_handle(),
1799 _marker: marker::PhantomData,
1800 })
1801 }
1802
1803 #[inline]
1805 pub fn len(&self) -> usize {
1806 self.len
1807 }
1808
1809 pub fn get(&self, mut store: impl AsContextMut, index: usize) -> Option<Result<T>> {
1824 let store = store.as_context_mut().0;
1825 let mut cx = match LiftContext::new(store, self.options, self.instance) {
1826 Ok(cx) => cx,
1827 Err(e) => return Some(Err(e)),
1828 };
1829 self.get_from_store(&mut cx, index)
1830 }
1831
1832 fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1833 if index >= self.len {
1834 return None;
1835 }
1836 let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1843 Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1844 }
1845
1846 pub fn iter<'a, U: 'static>(
1851 &'a self,
1852 store: impl Into<StoreContextMut<'a, U>>,
1853 ) -> Result<impl ExactSizeIterator<Item = Result<T>> + 'a> {
1854 let store = store.into().0;
1855 let mut cx = LiftContext::new(store, self.options, self.instance)?;
1856 Ok((0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap()))
1857 }
1858}
1859
1860macro_rules! raw_wasm_list_accessors {
1861 ($($i:ident)*) => ($(
1862 impl WasmList<$i> {
1863 pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1881 let memory = self.instance.options_memory(store.into().0, self.options);
1882 self._as_le_slice(memory)
1883 }
1884
1885 fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1886 let byte_size = self.len * mem::size_of::<$i>();
1888 let bytes = &all_of_memory[self.ptr..][..byte_size];
1889
1890 unsafe {
1902 let (head, body, tail) = bytes.align_to::<$i>();
1903 assert!(head.is_empty() && tail.is_empty());
1904 body
1905 }
1906 }
1907 }
1908 )*)
1909}
1910
1911raw_wasm_list_accessors! {
1912 i8 i16 i32 i64
1913 u8 u16 u32 u64
1914}
1915
1916unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
1919 type Lower = <[T] as ComponentType>::Lower;
1920
1921 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1922
1923 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1924 <[T] as ComponentType>::typecheck(ty, types)
1925 }
1926}
1927
1928unsafe impl<T: Lift> Lift for WasmList<T> {
1929 fn linear_lift_from_flat(
1930 cx: &mut LiftContext<'_>,
1931 ty: InterfaceType,
1932 src: &Self::Lower,
1933 ) -> Result<Self> {
1934 let elem = match ty {
1935 InterfaceType::List(i) => cx.types[i].element,
1936 _ => bad_type_info(),
1937 };
1938 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1939 WasmList::new(ptr, len, cx, elem)
1940 }
1941
1942 fn linear_lift_from_memory(
1943 cx: &mut LiftContext<'_>,
1944 ty: InterfaceType,
1945 bytes: &[u8],
1946 ) -> Result<Self> {
1947 let elem = match ty {
1948 InterfaceType::List(i) => cx.types[i].element,
1949 _ => bad_type_info(),
1950 };
1951 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1952 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1953 WasmList::new(ptr, len, cx, elem)
1954 }
1955}
1956
1957fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap {
1964 match ty {
1965 InterfaceType::Map(i) => &types[i],
1966 _ => bad_type_info(),
1967 }
1968}
1969
1970unsafe impl<K, V> ComponentType for BTreeMap<K, V>
1971where
1972 K: ComponentType,
1973 V: ComponentType,
1974{
1975 type Lower = [ValRaw; 2];
1976
1977 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1978
1979 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1980 match ty {
1981 InterfaceType::Map(t) => {
1982 let map_ty = &types.types[*t];
1983 K::typecheck(&map_ty.key, types)?;
1984 V::typecheck(&map_ty.value, types)?;
1985 Ok(())
1986 }
1987 other => bail!("expected `map` found `{}`", desc(other)),
1988 }
1989 }
1990}
1991
1992forward_type_impls! {
1994 (K: ComponentType, V: ComponentType, S: Send + Sync) HashMap<K, V, S> => BTreeMap<K, V>,
1995 (K: ComponentType, V: ComponentType, S: Send + Sync) TryHashMap<K, V, S> => BTreeMap<K, V>,
1996 (K: ComponentType, V: ComponentType, S: Send + Sync) IndexMap<K, V, S> => BTreeMap<K, V>,
1997}
1998
1999macro_rules! map_lowers {
2000 ($(($($generics:tt)*) $a:ty,)*) => ($(
2001 unsafe impl <$($generics)*> Lower for $a {
2002 fn linear_lower_to_flat<U>(
2003 &self,
2004 cx: &mut LowerContext<'_, U>,
2005 ty: InterfaceType,
2006 dst: &mut MaybeUninit<[ValRaw; 2]>,
2007 ) -> Result<()> {
2008 lower_map_to_flat(cx, ty, dst, self.iter())
2009 }
2010
2011 fn linear_lower_to_memory<U>(
2012 &self,
2013 cx: &mut LowerContext<'_, U>,
2014 ty: InterfaceType,
2015 offset: usize,
2016 ) -> Result<()> {
2017 lower_map_to_memory(cx, ty, offset, self.iter())
2018 }
2019 }
2020 )*)
2021}
2022
2023map_lowers! {
2024 (K: Lower, V: Lower, S: Send + Sync) HashMap<K, V, S>,
2025 (K: Lower, V: Lower, S: Send + Sync) TryHashMap<K, V, S>,
2026 (K: Lower, V: Lower) BTreeMap<K, V>,
2027 (K: Lower, V: Lower, S: Send + Sync) IndexMap<K, V, S>,
2028}
2029
2030unsafe impl<K, V, S> Lift for HashMap<K, V, S>
2031where
2032 K: Lift + Eq + Hash,
2033 V: Lift,
2034 S: BuildHasher + Default + Send + Sync,
2035{
2036 fn linear_lift_from_flat(
2037 cx: &mut LiftContext<'_>,
2038 ty: InterfaceType,
2039 src: &Self::Lower,
2040 ) -> Result<Self> {
2041 Ok(TryHashMap::<K, V, S>::linear_lift_from_flat(cx, ty, src)?.into())
2042 }
2043
2044 fn linear_lift_from_memory(
2045 cx: &mut LiftContext<'_>,
2046 ty: InterfaceType,
2047 bytes: &[u8],
2048 ) -> Result<Self> {
2049 Ok(TryHashMap::<K, V, S>::linear_lift_from_memory(cx, ty, bytes)?.into())
2050 }
2051}
2052
2053macro_rules! map_lifts {
2054 ($(($($generics:tt)*) $a:ty,)*) => ($(
2055 unsafe impl <$($generics)*> Lift for $a {
2056 fn linear_lift_from_flat(
2057 cx: &mut LiftContext<'_>,
2058 ty: InterfaceType,
2059 src: &Self::Lower,
2060 ) -> Result<Self> {
2061 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
2062 lift_map(cx, ty, ptr, len)
2063 }
2064
2065 fn linear_lift_from_memory(
2066 cx: &mut LiftContext<'_>,
2067 ty: InterfaceType,
2068 bytes: &[u8],
2069 ) -> Result<Self> {
2070 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2071 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
2072 lift_map(cx, ty, ptr, len)
2073 }
2074 }
2075 )*)
2076}
2077
2078map_lifts! {
2079 (K: Lift + Eq + Hash, V: Lift, S: BuildHasher + Default + Send + Sync) TryHashMap<K, V, S>,
2080 (K: Lift + Ord, V: Lift) BTreeMap<K, V>,
2081 (K: Lift + Eq + Hash, V: Lift, S: BuildHasher + Default + Send + Sync) IndexMap<K, V, S>,
2082}
2083
2084fn lower_map_to_flat<'a, K, V, U>(
2085 cx: &mut LowerContext<'_, U>,
2086 ty: InterfaceType,
2087 dst: &mut MaybeUninit<[ValRaw; 2]>,
2088 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2089) -> Result<()>
2090where
2091 K: Lower + 'a,
2092 V: Lower + 'a,
2093{
2094 let map = map_abi(ty, &cx.types);
2095 let (ptr, len) = lower_map_iter(cx, map, entries)?;
2096 lower_pointer_pair_to_flat(cx, dst, ptr, len);
2097 Ok(())
2098}
2099
2100fn lower_map_to_memory<'a, K, V, U>(
2101 cx: &mut LowerContext<'_, U>,
2102 ty: InterfaceType,
2103 offset: usize,
2104 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2105) -> Result<()>
2106where
2107 K: Lower + 'a,
2108 V: Lower + 'a,
2109{
2110 let map = map_abi(ty, &cx.types);
2111 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2112 let (ptr, len) = lower_map_iter(cx, map, entries)?;
2113 lower_pointer_pair_to_memory(cx, offset, ptr, len);
2114 Ok(())
2115}
2116
2117fn lower_map_iter<'a, K, V, U>(
2118 cx: &mut LowerContext<'_, U>,
2119 map: &TypeMap,
2120 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2121) -> Result<(usize, usize)>
2122where
2123 K: Lower + 'a,
2124 V: Lower + 'a,
2125{
2126 let len = entries.len();
2127 let size = len
2128 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2129 .ok_or_else(|| format_err!("size overflow copying a map"))?;
2130 let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?;
2131
2132 let mut entry_offset = ptr;
2133 for (key, value) in entries {
2134 <K as Lower>::linear_lower_to_memory(key, cx, map.key, entry_offset)?;
2136 <V as Lower>::linear_lower_to_memory(
2138 value,
2139 cx,
2140 map.value,
2141 entry_offset + usize::try_from(map.value_offset32)?,
2142 )?;
2143 entry_offset += usize::try_from(map.entry_abi.size32)?;
2144 }
2145
2146 Ok((ptr, len))
2147}
2148
2149trait LiftMap<K, V>: Sized {
2151 fn with_capacity(len: usize) -> Result<Self>;
2153
2154 fn push(&mut self, key: K, value: V) -> Result<()>;
2156}
2157
2158impl<K, V, S> LiftMap<K, V> for TryHashMap<K, V, S>
2159where
2160 K: Eq + Hash,
2161 S: BuildHasher + Default,
2162{
2163 fn with_capacity(len: usize) -> Result<Self> {
2164 Ok(TryHashMap::with_capacity_and_hasher(len, S::default())?)
2165 }
2166
2167 fn push(&mut self, key: K, value: V) -> Result<()> {
2168 self.insert(key, value)?;
2169 Ok(())
2170 }
2171}
2172
2173impl<K, V> LiftMap<K, V> for BTreeMap<K, V>
2174where
2175 K: Ord,
2176{
2177 fn with_capacity(_len: usize) -> Result<Self> {
2178 Ok(BTreeMap::new())
2179 }
2180
2181 fn push(&mut self, key: K, value: V) -> Result<()> {
2182 self.insert(key, value);
2183 Ok(())
2184 }
2185}
2186
2187impl<K, V, S> LiftMap<K, V> for IndexMap<K, V, S>
2188where
2189 K: Eq + Hash,
2190 S: BuildHasher + Default,
2191{
2192 fn with_capacity(len: usize) -> Result<Self> {
2193 let mut map = IndexMap::with_hasher(S::default());
2194 map.try_reserve(len)
2195 .map_err(|_| OutOfMemory::new(len.saturating_mul(mem::size_of::<(K, V)>())))?;
2196 Ok(map)
2197 }
2198
2199 fn push(&mut self, key: K, value: V) -> Result<()> {
2201 self.insert(key, value);
2202 Ok(())
2203 }
2204}
2205
2206fn lift_map<M, K, V>(
2207 cx: &mut LiftContext<'_>,
2208 ty: InterfaceType,
2209 ptr: usize,
2210 len: usize,
2211) -> Result<M>
2212where
2213 M: LiftMap<K, V>,
2214 K: Lift,
2215 V: Lift,
2216{
2217 let map = map_abi(ty, &cx.types);
2218 match len
2219 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2220 .and_then(|total| ptr.checked_add(total))
2221 {
2222 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(K, V)>())?,
2223 _ => bail!("map pointer/length out of bounds of memory"),
2224 }
2225 if ptr % (map.entry_abi.align32 as usize) != 0 {
2226 bail!("map pointer is not aligned");
2227 }
2228
2229 let mut result = M::with_capacity(len)?;
2230 for i in 0..len {
2231 let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?);
2232
2233 let key_bytes = &cx.memory()[entry_base..][..K::SIZE32];
2234 let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?;
2235
2236 let value_bytes =
2237 &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32];
2238 let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?;
2239
2240 result.push(key, value)?;
2241 }
2242
2243 Ok(result)
2244}
2245
2246fn typecheck_tuple(
2248 ty: &InterfaceType,
2249 types: &InstanceType<'_>,
2250 expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2251) -> Result<()> {
2252 match ty {
2253 InterfaceType::Tuple(t) => {
2254 let tuple = &types.types[*t];
2255 if tuple.types.len() != expected.len() {
2256 bail!(
2257 "expected {}-tuple, found {}-tuple",
2258 expected.len(),
2259 tuple.types.len()
2260 );
2261 }
2262 for (ty, check) in tuple.types.iter().zip(expected) {
2263 check(ty, types)?;
2264 }
2265 Ok(())
2266 }
2267 other => bail!("expected `tuple` found `{}`", desc(other)),
2268 }
2269}
2270
2271pub fn typecheck_record(
2274 ty: &InterfaceType,
2275 types: &InstanceType<'_>,
2276 expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2277) -> Result<()> {
2278 match ty {
2279 InterfaceType::Record(index) => {
2280 let fields = &types.types[*index].fields;
2281
2282 if fields.len() != expected.len() {
2283 bail!(
2284 "expected record of {} fields, found {} fields",
2285 expected.len(),
2286 fields.len()
2287 );
2288 }
2289
2290 for (field, &(name, check)) in fields.iter().zip(expected) {
2291 check(&field.ty, types)
2292 .with_context(|| format!("type mismatch for field {name}"))?;
2293
2294 if *field.name != *name {
2295 bail!("expected record field named {}, found {}", name, field.name);
2296 }
2297 }
2298
2299 Ok(())
2300 }
2301 other => bail!("expected `record` found `{}`", desc(other)),
2302 }
2303}
2304
2305pub fn typecheck_variant(
2308 ty: &InterfaceType,
2309 types: &InstanceType<'_>,
2310 expected: &[(
2311 &str,
2312 Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2313 )],
2314) -> Result<()> {
2315 match ty {
2316 InterfaceType::Variant(index) => {
2317 let cases = &types.types[*index].cases;
2318
2319 if cases.len() != expected.len() {
2320 bail!(
2321 "expected variant of {} cases, found {} cases",
2322 expected.len(),
2323 cases.len()
2324 );
2325 }
2326
2327 for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2328 if **case_name != *name {
2329 bail!("expected variant case named {name}, found {case_name}");
2330 }
2331
2332 match (check, case_ty) {
2333 (Some(check), Some(ty)) => check(ty, types)
2334 .with_context(|| format!("type mismatch for case {name}"))?,
2335 (None, None) => {}
2336 (Some(_), None) => {
2337 bail!("case `{name}` has no type but one was expected")
2338 }
2339 (None, Some(_)) => {
2340 bail!("case `{name}` has a type but none was expected")
2341 }
2342 }
2343 }
2344
2345 Ok(())
2346 }
2347 other => bail!("expected `variant` found `{}`", desc(other)),
2348 }
2349}
2350
2351pub fn typecheck_enum(
2354 ty: &InterfaceType,
2355 types: &InstanceType<'_>,
2356 expected: &[&str],
2357) -> Result<()> {
2358 match ty {
2359 InterfaceType::Enum(index) => {
2360 let names = &types.types[*index].names;
2361
2362 if names.len() != expected.len() {
2363 bail!(
2364 "expected enum of {} names, found {} names",
2365 expected.len(),
2366 names.len()
2367 );
2368 }
2369
2370 for (name, expected) in names.iter().zip(expected) {
2371 if **name != **expected {
2372 bail!("expected enum case named {expected}, found {name}");
2373 }
2374 }
2375
2376 Ok(())
2377 }
2378 other => bail!("expected `enum` found `{}`", desc(other)),
2379 }
2380}
2381
2382pub fn typecheck_flags(
2385 ty: &InterfaceType,
2386 types: &InstanceType<'_>,
2387 expected: &[&str],
2388) -> Result<()> {
2389 match ty {
2390 InterfaceType::Flags(index) => {
2391 let names = &types.types[*index].names;
2392
2393 if names.len() != expected.len() {
2394 bail!(
2395 "expected flags type with {} names, found {} names",
2396 expected.len(),
2397 names.len()
2398 );
2399 }
2400
2401 for (name, expected) in names.iter().zip(expected) {
2402 if **name != **expected {
2403 bail!("expected flag named {expected}, found {name}");
2404 }
2405 }
2406
2407 Ok(())
2408 }
2409 other => bail!("expected `flags` found `{}`", desc(other)),
2410 }
2411}
2412
2413pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2415 f.write_str("(")?;
2416 let mut wrote = false;
2417 for (index, name) in names.iter().enumerate() {
2418 if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2419 if wrote {
2420 f.write_str("|")?;
2421 } else {
2422 wrote = true;
2423 }
2424
2425 f.write_str(name)?;
2426 }
2427 }
2428 f.write_str(")")
2429}
2430
2431unsafe impl<T> ComponentType for Option<T>
2432where
2433 T: ComponentType,
2434{
2435 type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2436
2437 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2438 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC;
2439
2440 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2441 match ty {
2442 InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2443 other => bail!("expected `option` found `{}`", desc(other)),
2444 }
2445 }
2446}
2447
2448unsafe impl<T> ComponentVariant for Option<T>
2449where
2450 T: ComponentType,
2451{
2452 const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2453}
2454
2455unsafe impl<T> Lower for Option<T>
2456where
2457 T: Lower,
2458{
2459 fn linear_lower_to_flat<U>(
2460 &self,
2461 cx: &mut LowerContext<'_, U>,
2462 ty: InterfaceType,
2463 dst: &mut MaybeUninit<Self::Lower>,
2464 ) -> Result<()> {
2465 let payload = match ty {
2466 InterfaceType::Option(ty) => cx.types[ty].ty,
2467 _ => bad_type_info(),
2468 };
2469 match self {
2470 None => {
2471 map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2472 unsafe {
2479 map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2480 }
2481 }
2482 Some(val) => {
2483 map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2484 val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2485 }
2486 }
2487 Ok(())
2488 }
2489
2490 fn linear_lower_to_memory<U>(
2491 &self,
2492 cx: &mut LowerContext<'_, U>,
2493 ty: InterfaceType,
2494 offset: usize,
2495 ) -> Result<()> {
2496 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2497 let payload = match ty {
2498 InterfaceType::Option(ty) => cx.types[ty].ty,
2499 _ => bad_type_info(),
2500 };
2501 match self {
2502 None => {
2503 cx.get::<1>(offset)[0] = 0;
2504 }
2505 Some(val) => {
2506 cx.get::<1>(offset)[0] = 1;
2507 val.linear_lower_to_memory(
2508 cx,
2509 payload,
2510 offset + (Self::INFO.payload_offset32 as usize),
2511 )?;
2512 }
2513 }
2514 Ok(())
2515 }
2516}
2517
2518unsafe impl<T> Lift for Option<T>
2519where
2520 T: Lift,
2521{
2522 fn linear_lift_from_flat(
2523 cx: &mut LiftContext<'_>,
2524 ty: InterfaceType,
2525 src: &Self::Lower,
2526 ) -> Result<Self> {
2527 let payload = match ty {
2528 InterfaceType::Option(ty) => cx.types[ty].ty,
2529 _ => bad_type_info(),
2530 };
2531 Ok(match src.A1.get_i32() {
2532 0 => None,
2533 1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2534 _ => bail!("invalid option discriminant"),
2535 })
2536 }
2537
2538 fn linear_lift_from_memory(
2539 cx: &mut LiftContext<'_>,
2540 ty: InterfaceType,
2541 bytes: &[u8],
2542 ) -> Result<Self> {
2543 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2544 let payload_ty = match ty {
2545 InterfaceType::Option(ty) => cx.types[ty].ty,
2546 _ => bad_type_info(),
2547 };
2548 let discrim = bytes[0];
2549 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2550 match discrim {
2551 0 => Ok(None),
2552 1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2553 _ => bail!("invalid option discriminant"),
2554 }
2555 }
2556}
2557
2558#[derive(Clone, Copy)]
2559#[repr(C)]
2560pub struct ResultLower<T: Copy, E: Copy> {
2561 tag: ValRaw,
2562 payload: ResultLowerPayload<T, E>,
2563}
2564
2565#[derive(Clone, Copy)]
2566#[repr(C)]
2567union ResultLowerPayload<T: Copy, E: Copy> {
2568 ok: T,
2569 err: E,
2570}
2571
2572unsafe impl<T, E> ComponentType for Result<T, E>
2573where
2574 T: ComponentType,
2575 E: ComponentType,
2576{
2577 type Lower = ResultLower<T::Lower, E::Lower>;
2578
2579 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2580 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC || E::MAY_REQUIRE_REALLOC;
2581
2582 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2583 match ty {
2584 InterfaceType::Result(r) => {
2585 let result = &types.types[*r];
2586 match &result.ok {
2587 Some(ty) => T::typecheck(ty, types)?,
2588 None if T::IS_RUST_UNIT_TYPE => {}
2589 None => bail!("expected no `ok` type"),
2590 }
2591 match &result.err {
2592 Some(ty) => E::typecheck(ty, types)?,
2593 None if E::IS_RUST_UNIT_TYPE => {}
2594 None => bail!("expected no `err` type"),
2595 }
2596 Ok(())
2597 }
2598 other => bail!("expected `result` found `{}`", desc(other)),
2599 }
2600 }
2601}
2602
2603pub unsafe fn lower_payload<P, T>(
2616 payload: &mut MaybeUninit<P>,
2617 typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2618 lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2619) -> Result<()> {
2620 let typed = typed_payload(payload);
2621 lower(typed)?;
2622
2623 let typed_len = unsafe { storage_as_slice(typed).len() };
2624 let payload = unsafe { storage_as_slice_mut(payload) };
2625 for slot in payload[typed_len..].iter_mut() {
2626 slot.write(ValRaw::u64(0));
2627 }
2628 Ok(())
2629}
2630
2631unsafe impl<T, E> ComponentVariant for Result<T, E>
2632where
2633 T: ComponentType,
2634 E: ComponentType,
2635{
2636 const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2637}
2638
2639unsafe impl<T, E> Lower for Result<T, E>
2640where
2641 T: Lower,
2642 E: Lower,
2643{
2644 fn linear_lower_to_flat<U>(
2645 &self,
2646 cx: &mut LowerContext<'_, U>,
2647 ty: InterfaceType,
2648 dst: &mut MaybeUninit<Self::Lower>,
2649 ) -> Result<()> {
2650 let (ok, err) = match ty {
2651 InterfaceType::Result(ty) => {
2652 let ty = &cx.types[ty];
2653 (ty.ok, ty.err)
2654 }
2655 _ => bad_type_info(),
2656 };
2657
2658 match self {
2720 Ok(e) => {
2721 map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2722 unsafe {
2723 lower_payload(
2724 map_maybe_uninit!(dst.payload),
2725 |payload| map_maybe_uninit!(payload.ok),
2726 |dst| match ok {
2727 Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2728 None => Ok(()),
2729 },
2730 )
2731 }
2732 }
2733 Err(e) => {
2734 map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2735 unsafe {
2736 lower_payload(
2737 map_maybe_uninit!(dst.payload),
2738 |payload| map_maybe_uninit!(payload.err),
2739 |dst| match err {
2740 Some(err) => e.linear_lower_to_flat(cx, err, dst),
2741 None => Ok(()),
2742 },
2743 )
2744 }
2745 }
2746 }
2747 }
2748
2749 fn linear_lower_to_memory<U>(
2750 &self,
2751 cx: &mut LowerContext<'_, U>,
2752 ty: InterfaceType,
2753 offset: usize,
2754 ) -> Result<()> {
2755 let (ok, err) = match ty {
2756 InterfaceType::Result(ty) => {
2757 let ty = &cx.types[ty];
2758 (ty.ok, ty.err)
2759 }
2760 _ => bad_type_info(),
2761 };
2762 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2763 let payload_offset = Self::INFO.payload_offset32 as usize;
2764 match self {
2765 Ok(e) => {
2766 cx.get::<1>(offset)[0] = 0;
2767 if let Some(ok) = ok {
2768 e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2769 }
2770 }
2771 Err(e) => {
2772 cx.get::<1>(offset)[0] = 1;
2773 if let Some(err) = err {
2774 e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2775 }
2776 }
2777 }
2778 Ok(())
2779 }
2780}
2781
2782unsafe impl<T, E> Lift for Result<T, E>
2783where
2784 T: Lift,
2785 E: Lift,
2786{
2787 #[inline]
2788 fn linear_lift_from_flat(
2789 cx: &mut LiftContext<'_>,
2790 ty: InterfaceType,
2791 src: &Self::Lower,
2792 ) -> Result<Self> {
2793 let (ok, err) = match ty {
2794 InterfaceType::Result(ty) => {
2795 let ty = &cx.types[ty];
2796 (ty.ok, ty.err)
2797 }
2798 _ => bad_type_info(),
2799 };
2800 Ok(match src.tag.get_i32() {
2820 0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2821 1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2822 _ => bail!("invalid expected discriminant"),
2823 })
2824 }
2825
2826 #[inline]
2827 fn linear_lift_from_memory(
2828 cx: &mut LiftContext<'_>,
2829 ty: InterfaceType,
2830 bytes: &[u8],
2831 ) -> Result<Self> {
2832 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2833 let discrim = bytes[0];
2834 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2835 let (ok, err) = match ty {
2836 InterfaceType::Result(ty) => {
2837 let ty = &cx.types[ty];
2838 (ty.ok, ty.err)
2839 }
2840 _ => bad_type_info(),
2841 };
2842 match discrim {
2843 0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2844 1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2845 _ => bail!("invalid expected discriminant"),
2846 }
2847 }
2848}
2849
2850fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2851where
2852 T: Lift,
2853{
2854 match ty {
2855 Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2856 None => Ok(empty_lift()),
2857 }
2858}
2859
2860fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2861where
2862 T: Lift,
2863{
2864 match ty {
2865 Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2866 None => Ok(empty_lift()),
2867 }
2868}
2869
2870fn empty_lift<T>() -> T
2871where
2872 T: Lift,
2873{
2874 assert!(T::IS_RUST_UNIT_TYPE);
2875 assert_eq!(mem::size_of::<T>(), 0);
2876 unsafe { MaybeUninit::uninit().assume_init() }
2877}
2878
2879#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2884#[doc(hidden)]
2885#[derive(Clone, Copy)]
2886#[repr(C)]
2887pub struct TupleLower<
2888 T1 = (),
2889 T2 = (),
2890 T3 = (),
2891 T4 = (),
2892 T5 = (),
2893 T6 = (),
2894 T7 = (),
2895 T8 = (),
2896 T9 = (),
2897 T10 = (),
2898 T11 = (),
2899 T12 = (),
2900 T13 = (),
2901 T14 = (),
2902 T15 = (),
2903 T16 = (),
2904 T17 = (),
2905> {
2906 A1: T1,
2908 A2: T2,
2909 A3: T3,
2910 A4: T4,
2911 A5: T5,
2912 A6: T6,
2913 A7: T7,
2914 A8: T8,
2915 A9: T9,
2916 A10: T10,
2917 A11: T11,
2918 A12: T12,
2919 A13: T13,
2920 A14: T14,
2921 A15: T15,
2922 A16: T16,
2923 A17: T17,
2924 _align_tuple_lower0_correctly: [ValRaw; 0],
2925}
2926
2927macro_rules! impl_component_ty_for_tuples {
2928 ($n:tt $($t:ident)*) => {
2929 #[allow(non_snake_case, reason = "macro-generated code")]
2930 unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2931 where $($t: ComponentType),*
2932 {
2933 type Lower = TupleLower<$($t::Lower),*>;
2934
2935 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2936 $($t::ABI),*
2937 ]);
2938 const MAY_REQUIRE_REALLOC: bool = false $(|| $t::MAY_REQUIRE_REALLOC)*;
2939
2940 const IS_RUST_UNIT_TYPE: bool = {
2941 let mut _is_unit = true;
2942 $(
2943 let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2944 _is_unit = false;
2945 )*
2946 _is_unit
2947 };
2948
2949 fn typecheck(
2950 ty: &InterfaceType,
2951 types: &InstanceType<'_>,
2952 ) -> Result<()> {
2953 typecheck_tuple(ty, types, &[$($t::typecheck),*])
2954 }
2955 }
2956
2957 #[allow(non_snake_case, reason = "macro-generated code")]
2958 unsafe impl<$($t,)*> Lower for ($($t,)*)
2959 where $($t: Lower),*
2960 {
2961 fn linear_lower_to_flat<U>(
2962 &self,
2963 cx: &mut LowerContext<'_, U>,
2964 ty: InterfaceType,
2965 _dst: &mut MaybeUninit<Self::Lower>,
2966 ) -> Result<()> {
2967 let types = match ty {
2968 InterfaceType::Tuple(t) => &cx.types[t].types,
2969 _ => bad_type_info(),
2970 };
2971 let ($($t,)*) = self;
2972 let mut _types = types.iter();
2973 $(
2974 let ty = *_types.next().unwrap_or_else(bad_type_info);
2975 $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2976 )*
2977 Ok(())
2978 }
2979
2980 fn linear_lower_to_memory<U>(
2981 &self,
2982 cx: &mut LowerContext<'_, U>,
2983 ty: InterfaceType,
2984 mut _offset: usize,
2985 ) -> Result<()> {
2986 debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2987 let types = match ty {
2988 InterfaceType::Tuple(t) => &cx.types[t].types,
2989 _ => bad_type_info(),
2990 };
2991 let ($($t,)*) = self;
2992 let mut _types = types.iter();
2993 $(
2994 let ty = *_types.next().unwrap_or_else(bad_type_info);
2995 $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2996 )*
2997 Ok(())
2998 }
2999 }
3000
3001 #[allow(non_snake_case, reason = "macro-generated code")]
3002 unsafe impl<$($t,)*> Lift for ($($t,)*)
3003 where $($t: Lift),*
3004 {
3005 #[inline]
3006 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
3007 let types = match ty {
3008 InterfaceType::Tuple(t) => &cx.types[t].types,
3009 _ => bad_type_info(),
3010 };
3011 let mut _types = types.iter();
3012 Ok(($(
3013 $t::linear_lift_from_flat(
3014 cx,
3015 *_types.next().unwrap_or_else(bad_type_info),
3016 &_src.$t,
3017 )?,
3018 )*))
3019 }
3020
3021 #[inline]
3022 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
3023 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3024 let types = match ty {
3025 InterfaceType::Tuple(t) => &cx.types[t].types,
3026 _ => bad_type_info(),
3027 };
3028 let mut _types = types.iter();
3029 let mut _offset = 0;
3030 $(
3031 let ty = *_types.next().unwrap_or_else(bad_type_info);
3032 let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
3033 )*
3034 Ok(($($t,)*))
3035 }
3036 }
3037
3038 #[allow(non_snake_case, reason = "macro-generated code")]
3039 unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
3040 where $($t: ComponentType),*
3041 {}
3042 };
3043}
3044
3045for_each_function_signature!(impl_component_ty_for_tuples);
3046
3047unsafe impl<T, const N: usize> ComponentType for [T; N]
3048where
3049 T: ComponentType,
3050{
3051 type Lower = [T::Lower; N];
3052
3053 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_length_list_static(&T::ABI, N);
3054
3055 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
3056 match ty {
3057 InterfaceType::FixedLengthList(t) => {
3058 let list = &types.types[*t];
3059 match usize::try_from(list.size) {
3060 Ok(n) if n == N => {}
3061 _ => bail!("expected `list<_, {}>` found `list<_, {N}>`", list.size),
3062 }
3063 T::typecheck(&list.element, types)
3064 }
3065 other => bail!("expected `list<_, {N}>` found `{}`", desc(other)),
3066 }
3067 }
3068}
3069
3070unsafe impl<T, const N: usize> Lower for [T; N]
3071where
3072 T: Lower,
3073{
3074 fn linear_lower_to_flat<U>(
3075 &self,
3076 cx: &mut LowerContext<'_, U>,
3077 ty: InterfaceType,
3078 dst: &mut MaybeUninit<Self::Lower>,
3079 ) -> Result<()> {
3080 let element = match ty {
3081 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3082 _ => bad_type_info(),
3083 };
3084 for (i, val) in self.iter().enumerate() {
3085 val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
3086 }
3087 Ok(())
3088 }
3089
3090 fn linear_lower_to_memory<U>(
3091 &self,
3092 cx: &mut LowerContext<'_, U>,
3093 ty: InterfaceType,
3094 offset: usize,
3095 ) -> Result<()> {
3096 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
3097 let element = match ty {
3098 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3099 _ => bad_type_info(),
3100 };
3101 for (i, val) in self.iter().enumerate() {
3102 val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
3103 }
3104 Ok(())
3105 }
3106}
3107
3108unsafe impl<T, const N: usize> Lift for [T; N]
3109where
3110 T: Lift + Sized,
3111{
3112 fn linear_lift_from_flat(
3113 cx: &mut LiftContext<'_>,
3114 ty: InterfaceType,
3115 src: &Self::Lower,
3116 ) -> Result<Self> {
3117 let element = match ty {
3118 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3119 _ => bad_type_info(),
3120 };
3121 array_try_from_fn(|n| T::linear_lift_from_flat(cx, element, &src[n]))
3122 }
3123
3124 fn linear_lift_from_memory(
3125 cx: &mut LiftContext<'_>,
3126 ty: InterfaceType,
3127 bytes: &[u8],
3128 ) -> Result<Self> {
3129 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3130 let element = match ty {
3131 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3132 _ => bad_type_info(),
3133 };
3134 let mut offset = 0;
3135 array_try_from_fn(|_n| {
3136 let res = T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]);
3137 offset += T::SIZE32;
3138 res
3139 })
3140 }
3141}
3142
3143pub fn desc(ty: &InterfaceType) -> &'static str {
3144 match ty {
3145 InterfaceType::U8 => "u8",
3146 InterfaceType::S8 => "s8",
3147 InterfaceType::U16 => "u16",
3148 InterfaceType::S16 => "s16",
3149 InterfaceType::U32 => "u32",
3150 InterfaceType::S32 => "s32",
3151 InterfaceType::U64 => "u64",
3152 InterfaceType::S64 => "s64",
3153 InterfaceType::Float32 => "f32",
3154 InterfaceType::Float64 => "f64",
3155 InterfaceType::Bool => "bool",
3156 InterfaceType::Char => "char",
3157 InterfaceType::String => "string",
3158 InterfaceType::List(_) => "list",
3159 InterfaceType::Tuple(_) => "tuple",
3160 InterfaceType::Option(_) => "option",
3161 InterfaceType::Result(_) => "result",
3162
3163 InterfaceType::Record(_) => "record",
3164 InterfaceType::Variant(_) => "variant",
3165 InterfaceType::Flags(_) => "flags",
3166 InterfaceType::Enum(_) => "enum",
3167 InterfaceType::Own(_) => "owned resource",
3168 InterfaceType::Borrow(_) => "borrowed resource",
3169 InterfaceType::Future(_) => "future",
3170 InterfaceType::Stream(_) => "stream",
3171 InterfaceType::ErrorContext(_) => "error-context",
3172 InterfaceType::Map(_) => "map",
3173 InterfaceType::FixedLengthList(_) => "list<_, N>",
3174 }
3175}
3176
3177#[cold]
3178#[doc(hidden)]
3179pub fn bad_type_info<T>() -> T {
3180 panic!("bad type information detected");
3184}