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 = cx.slice_range_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 = cx.slice_range_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.slice_range_mut(ptr, string.len())
1399 .copy_from_slice(string.as_bytes());
1400 Ok((ptr, string.len()))
1401 }
1402
1403 StringEncoding::Utf16 => {
1407 let size = string.len() * 2;
1408 if size > MAX_STRING_BYTE_LENGTH {
1409 bail!(
1410 "string length of {} too large to copy into wasm",
1411 string.len()
1412 );
1413 }
1414 let mut ptr = cx.realloc(0, 0, 2, size)?;
1415 let mut copied = 0;
1416 let bytes = cx.slice_range_mut(ptr, size);
1417 for (u, bytes) in string.encode_utf16().zip(bytes.chunks_mut(2)) {
1418 let u_bytes = u.to_le_bytes();
1419 bytes[0] = u_bytes[0];
1420 bytes[1] = u_bytes[1];
1421 copied += 1;
1422 }
1423 if (copied * 2) < size {
1424 ptr = cx.realloc(ptr, size, 2, copied * 2)?;
1425 }
1426 Ok((ptr, copied))
1427 }
1428
1429 StringEncoding::CompactUtf16 => {
1430 let bytes = string.as_bytes();
1432 let mut iter = string.char_indices();
1433 let mut ptr = cx.realloc(0, 0, 2, bytes.len())?;
1434 let mut dst = cx.slice_range_mut(ptr, bytes.len());
1435 let mut result = 0;
1436 while let Some((i, ch)) = iter.next() {
1437 if let Ok(byte) = u8::try_from(u32::from(ch)) {
1439 dst[result] = byte;
1440 result += 1;
1441 continue;
1442 }
1443
1444 let worst_case = bytes
1447 .len()
1448 .checked_mul(2)
1449 .ok_or_else(|| format_err!("byte length overflow"))?;
1450 if worst_case > MAX_STRING_BYTE_LENGTH {
1451 bail!("byte length too large");
1452 }
1453 ptr = cx.realloc(ptr, bytes.len(), 2, worst_case)?;
1454 dst = cx.slice_range_mut(ptr, worst_case);
1455
1456 for i in (0..result).rev() {
1459 dst[2 * i] = dst[i];
1460 dst[2 * i + 1] = 0;
1461 }
1462
1463 for (u, bytes) in string[i..]
1465 .encode_utf16()
1466 .zip(dst[2 * result..].chunks_mut(2))
1467 {
1468 let u_bytes = u.to_le_bytes();
1469 bytes[0] = u_bytes[0];
1470 bytes[1] = u_bytes[1];
1471 result += 1;
1472 }
1473 if worst_case > 2 * result {
1474 ptr = cx.realloc(ptr, worst_case, 2, 2 * result)?;
1475 }
1476 return Ok((ptr, result | UTF16_TAG));
1477 }
1478 if result < bytes.len() {
1479 ptr = cx.realloc(ptr, bytes.len(), 2, result)?;
1480 }
1481 Ok((ptr, result))
1482 }
1483 }
1484}
1485
1486pub struct WasmStr {
1517 ptr: usize,
1518 len: usize,
1519 options: OptionsIndex,
1520 instance: Instance,
1521}
1522
1523impl WasmStr {
1524 pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1525 let (byte_len, align) = match cx.options().string_encoding {
1526 StringEncoding::Utf8 => (Some(len), 1_usize),
1527 StringEncoding::Utf16 => (len.checked_mul(2), 2),
1528 StringEncoding::CompactUtf16 => {
1529 if len & UTF16_TAG == 0 {
1530 (Some(len), 2)
1531 } else {
1532 ((len ^ UTF16_TAG).checked_mul(2), 2)
1533 }
1534 }
1535 };
1536 debug_assert!(align.is_power_of_two());
1537 if ptr & (align - 1) != 0 {
1538 bail!("string pointer not aligned to {align}");
1539 }
1540 match byte_len.and_then(|len| ptr.checked_add(len)) {
1541 Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?,
1542 _ => bail!("string pointer/length out of bounds of memory"),
1543 }
1544 Ok(WasmStr {
1545 ptr,
1546 len,
1547 options: cx.options_index(),
1548 instance: cx.instance_handle(),
1549 })
1550 }
1551
1552 pub fn to_str<'a, T: 'static>(
1574 &self,
1575 store: impl Into<StoreContext<'a, T>>,
1576 ) -> Result<Cow<'a, str>> {
1577 let store = store.into().0;
1578 let memory = self.instance.options_memory(store, self.options);
1579 let encoding = self.instance.options(store, self.options).string_encoding;
1580 self.to_str_from_memory(encoding, memory)
1581 }
1582
1583 pub(crate) fn to_str_from_memory<'a>(
1584 &self,
1585 encoding: StringEncoding,
1586 memory: &'a [u8],
1587 ) -> Result<Cow<'a, str>> {
1588 match encoding {
1589 StringEncoding::Utf8 => self.decode_utf8(memory),
1590 StringEncoding::Utf16 => self.decode_utf16(memory, self.len),
1591 StringEncoding::CompactUtf16 => {
1592 if self.len & UTF16_TAG == 0 {
1593 self.decode_latin1(memory)
1594 } else {
1595 self.decode_utf16(memory, self.len ^ UTF16_TAG)
1596 }
1597 }
1598 }
1599 }
1600
1601 fn decode_utf8<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1602 Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into())
1606 }
1607
1608 fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result<Cow<'a, str>> {
1609 let (chunks, rest) = &memory[self.ptr..][..len * 2].as_chunks::<2>();
1611 debug_assert!(rest.is_empty());
1612 Ok(
1613 core::char::decode_utf16(chunks.iter().map(|chunk| u16::from_le_bytes(*chunk)))
1614 .collect::<Result<String, _>>()?
1615 .into(),
1616 )
1617 }
1618
1619 fn decode_latin1<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1620 Ok(encoding_rs::mem::decode_latin1(
1622 &memory[self.ptr..][..self.len],
1623 ))
1624 }
1625}
1626
1627unsafe impl ComponentType for WasmStr {
1630 type Lower = <str as ComponentType>::Lower;
1631
1632 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1633
1634 fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1635 match ty {
1636 InterfaceType::String => Ok(()),
1637 other => bail!("expected `string` found `{}`", desc(other)),
1638 }
1639 }
1640}
1641
1642unsafe impl Lift for WasmStr {
1643 #[inline]
1644 fn linear_lift_from_flat(
1645 cx: &mut LiftContext<'_>,
1646 ty: InterfaceType,
1647 src: &Self::Lower,
1648 ) -> Result<Self> {
1649 debug_assert!(matches!(ty, InterfaceType::String));
1650 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1651 WasmStr::new(ptr, len, cx)
1652 }
1653
1654 #[inline]
1655 fn linear_lift_from_memory(
1656 cx: &mut LiftContext<'_>,
1657 ty: InterfaceType,
1658 bytes: &[u8],
1659 ) -> Result<Self> {
1660 debug_assert!(matches!(ty, InterfaceType::String));
1661 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1662 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1663 WasmStr::new(ptr, len, cx)
1664 }
1665}
1666
1667unsafe impl<T> ComponentType for [T]
1668where
1669 T: ComponentType,
1670{
1671 type Lower = [ValRaw; 2];
1672
1673 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1674
1675 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1676 match ty {
1677 InterfaceType::List(t) => T::typecheck(&types.types[*t].element, types),
1678 other => bail!("expected `list` found `{}`", desc(other)),
1679 }
1680 }
1681}
1682
1683unsafe impl<T> Lower for [T]
1684where
1685 T: Lower,
1686{
1687 fn linear_lower_to_flat<U>(
1688 &self,
1689 cx: &mut LowerContext<'_, U>,
1690 ty: InterfaceType,
1691 dst: &mut MaybeUninit<[ValRaw; 2]>,
1692 ) -> Result<()> {
1693 let elem = match ty {
1694 InterfaceType::List(i) => cx.types[i].element,
1695 _ => bad_type_info(),
1696 };
1697 let (ptr, len) = lower_list(cx, elem, self)?;
1698 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1699 Ok(())
1700 }
1701
1702 fn linear_lower_to_memory<U>(
1703 &self,
1704 cx: &mut LowerContext<'_, U>,
1705 ty: InterfaceType,
1706 offset: usize,
1707 ) -> Result<()> {
1708 let elem = match ty {
1709 InterfaceType::List(i) => cx.types[i].element,
1710 _ => bad_type_info(),
1711 };
1712 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1713 let (ptr, len) = lower_list(cx, elem, self)?;
1714 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1715 Ok(())
1716 }
1717}
1718
1719fn lower_list<T, U>(
1735 cx: &mut LowerContext<'_, U>,
1736 ty: InterfaceType,
1737 list: &[T],
1738) -> Result<(usize, usize)>
1739where
1740 T: Lower,
1741{
1742 let elem_size = T::SIZE32;
1743 let size = list
1744 .len()
1745 .checked_mul(elem_size)
1746 .ok_or_else(|| format_err!("size overflow copying a list"))?;
1747 let ptr = cx.realloc(0, 0, T::ALIGN32, size)?;
1748 T::linear_store_list_to_memory(cx, ty, ptr, list)?;
1749 Ok((ptr, list.len()))
1750}
1751
1752pub struct WasmList<T> {
1769 ptr: usize,
1770 len: usize,
1771 options: OptionsIndex,
1772 elem: InterfaceType,
1773 instance: Instance,
1774 _marker: marker::PhantomData<T>,
1775}
1776
1777impl<T: Lift> WasmList<T> {
1778 pub(crate) fn new(
1779 ptr: usize,
1780 len: usize,
1781 cx: &mut LiftContext<'_>,
1782 elem: InterfaceType,
1783 ) -> Result<WasmList<T>> {
1784 match len
1785 .checked_mul(T::SIZE32)
1786 .and_then(|len| ptr.checked_add(len))
1787 {
1788 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<T>())?,
1789 _ => bail!("list pointer/length out of bounds of memory"),
1790 }
1791 if ptr % usize::try_from(T::ALIGN32)? != 0 {
1792 bail!("list pointer is not aligned")
1793 }
1794 Ok(WasmList {
1795 ptr,
1796 len,
1797 options: cx.options_index(),
1798 elem,
1799 instance: cx.instance_handle(),
1800 _marker: marker::PhantomData,
1801 })
1802 }
1803
1804 #[inline]
1806 pub fn len(&self) -> usize {
1807 self.len
1808 }
1809
1810 pub fn get(&self, mut store: impl AsContextMut, index: usize) -> Option<Result<T>> {
1825 let store = store.as_context_mut().0;
1826 let mut cx = match LiftContext::new(store, self.options, self.instance) {
1827 Ok(cx) => cx,
1828 Err(e) => return Some(Err(e)),
1829 };
1830 self.get_from_store(&mut cx, index)
1831 }
1832
1833 fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1834 if index >= self.len {
1835 return None;
1836 }
1837 let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1844 Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1845 }
1846
1847 pub fn iter<'a, U: 'static>(
1852 &'a self,
1853 store: impl Into<StoreContextMut<'a, U>>,
1854 ) -> Result<impl ExactSizeIterator<Item = Result<T>> + 'a> {
1855 let store = store.into().0;
1856 let mut cx = LiftContext::new(store, self.options, self.instance)?;
1857 Ok((0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap()))
1858 }
1859}
1860
1861macro_rules! raw_wasm_list_accessors {
1862 ($($i:ident)*) => ($(
1863 impl WasmList<$i> {
1864 pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1882 let memory = self.instance.options_memory(store.into().0, self.options);
1883 self._as_le_slice(memory)
1884 }
1885
1886 fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1887 let byte_size = self.len * mem::size_of::<$i>();
1889 let bytes = &all_of_memory[self.ptr..][..byte_size];
1890
1891 unsafe {
1903 let (head, body, tail) = bytes.align_to::<$i>();
1904 assert!(head.is_empty() && tail.is_empty());
1905 body
1906 }
1907 }
1908 }
1909 )*)
1910}
1911
1912raw_wasm_list_accessors! {
1913 i8 i16 i32 i64
1914 u8 u16 u32 u64
1915}
1916
1917unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
1920 type Lower = <[T] as ComponentType>::Lower;
1921
1922 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1923
1924 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1925 <[T] as ComponentType>::typecheck(ty, types)
1926 }
1927}
1928
1929unsafe impl<T: Lift> Lift for WasmList<T> {
1930 fn linear_lift_from_flat(
1931 cx: &mut LiftContext<'_>,
1932 ty: InterfaceType,
1933 src: &Self::Lower,
1934 ) -> Result<Self> {
1935 let elem = match ty {
1936 InterfaceType::List(i) => cx.types[i].element,
1937 _ => bad_type_info(),
1938 };
1939 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1940 WasmList::new(ptr, len, cx, elem)
1941 }
1942
1943 fn linear_lift_from_memory(
1944 cx: &mut LiftContext<'_>,
1945 ty: InterfaceType,
1946 bytes: &[u8],
1947 ) -> Result<Self> {
1948 let elem = match ty {
1949 InterfaceType::List(i) => cx.types[i].element,
1950 _ => bad_type_info(),
1951 };
1952 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1953 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1954 WasmList::new(ptr, len, cx, elem)
1955 }
1956}
1957
1958fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap {
1965 match ty {
1966 InterfaceType::Map(i) => &types[i],
1967 _ => bad_type_info(),
1968 }
1969}
1970
1971unsafe impl<K, V> ComponentType for BTreeMap<K, V>
1972where
1973 K: ComponentType,
1974 V: ComponentType,
1975{
1976 type Lower = [ValRaw; 2];
1977
1978 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1979
1980 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1981 match ty {
1982 InterfaceType::Map(t) => {
1983 let map_ty = &types.types[*t];
1984 K::typecheck(&map_ty.key, types)?;
1985 V::typecheck(&map_ty.value, types)?;
1986 Ok(())
1987 }
1988 other => bail!("expected `map` found `{}`", desc(other)),
1989 }
1990 }
1991}
1992
1993forward_type_impls! {
1995 (K: ComponentType, V: ComponentType, S: Send + Sync) HashMap<K, V, S> => BTreeMap<K, V>,
1996 (K: ComponentType, V: ComponentType, S: Send + Sync) TryHashMap<K, V, S> => BTreeMap<K, V>,
1997 (K: ComponentType, V: ComponentType, S: Send + Sync) IndexMap<K, V, S> => BTreeMap<K, V>,
1998}
1999
2000macro_rules! map_lowers {
2001 ($(($($generics:tt)*) $a:ty,)*) => ($(
2002 unsafe impl <$($generics)*> Lower for $a {
2003 fn linear_lower_to_flat<U>(
2004 &self,
2005 cx: &mut LowerContext<'_, U>,
2006 ty: InterfaceType,
2007 dst: &mut MaybeUninit<[ValRaw; 2]>,
2008 ) -> Result<()> {
2009 lower_map_to_flat(cx, ty, dst, self.iter())
2010 }
2011
2012 fn linear_lower_to_memory<U>(
2013 &self,
2014 cx: &mut LowerContext<'_, U>,
2015 ty: InterfaceType,
2016 offset: usize,
2017 ) -> Result<()> {
2018 lower_map_to_memory(cx, ty, offset, self.iter())
2019 }
2020 }
2021 )*)
2022}
2023
2024map_lowers! {
2025 (K: Lower, V: Lower, S: Send + Sync) HashMap<K, V, S>,
2026 (K: Lower, V: Lower, S: Send + Sync) TryHashMap<K, V, S>,
2027 (K: Lower, V: Lower) BTreeMap<K, V>,
2028 (K: Lower, V: Lower, S: Send + Sync) IndexMap<K, V, S>,
2029}
2030
2031unsafe impl<K, V, S> Lift for HashMap<K, V, S>
2032where
2033 K: Lift + Eq + Hash,
2034 V: Lift,
2035 S: BuildHasher + Default + Send + Sync,
2036{
2037 fn linear_lift_from_flat(
2038 cx: &mut LiftContext<'_>,
2039 ty: InterfaceType,
2040 src: &Self::Lower,
2041 ) -> Result<Self> {
2042 Ok(TryHashMap::<K, V, S>::linear_lift_from_flat(cx, ty, src)?.into())
2043 }
2044
2045 fn linear_lift_from_memory(
2046 cx: &mut LiftContext<'_>,
2047 ty: InterfaceType,
2048 bytes: &[u8],
2049 ) -> Result<Self> {
2050 Ok(TryHashMap::<K, V, S>::linear_lift_from_memory(cx, ty, bytes)?.into())
2051 }
2052}
2053
2054macro_rules! map_lifts {
2055 ($(($($generics:tt)*) $a:ty,)*) => ($(
2056 unsafe impl <$($generics)*> Lift for $a {
2057 fn linear_lift_from_flat(
2058 cx: &mut LiftContext<'_>,
2059 ty: InterfaceType,
2060 src: &Self::Lower,
2061 ) -> Result<Self> {
2062 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
2063 lift_map(cx, ty, ptr, len)
2064 }
2065
2066 fn linear_lift_from_memory(
2067 cx: &mut LiftContext<'_>,
2068 ty: InterfaceType,
2069 bytes: &[u8],
2070 ) -> Result<Self> {
2071 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2072 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
2073 lift_map(cx, ty, ptr, len)
2074 }
2075 }
2076 )*)
2077}
2078
2079map_lifts! {
2080 (K: Lift + Eq + Hash, V: Lift, S: BuildHasher + Default + Send + Sync) TryHashMap<K, V, S>,
2081 (K: Lift + Ord, V: Lift) BTreeMap<K, V>,
2082 (K: Lift + Eq + Hash, V: Lift, S: BuildHasher + Default + Send + Sync) IndexMap<K, V, S>,
2083}
2084
2085fn lower_map_to_flat<'a, K, V, U>(
2086 cx: &mut LowerContext<'_, U>,
2087 ty: InterfaceType,
2088 dst: &mut MaybeUninit<[ValRaw; 2]>,
2089 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2090) -> Result<()>
2091where
2092 K: Lower + 'a,
2093 V: Lower + 'a,
2094{
2095 let map = map_abi(ty, &cx.types);
2096 let (ptr, len) = lower_map_iter(cx, map, entries)?;
2097 lower_pointer_pair_to_flat(cx, dst, ptr, len);
2098 Ok(())
2099}
2100
2101fn lower_map_to_memory<'a, K, V, U>(
2102 cx: &mut LowerContext<'_, U>,
2103 ty: InterfaceType,
2104 offset: usize,
2105 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2106) -> Result<()>
2107where
2108 K: Lower + 'a,
2109 V: Lower + 'a,
2110{
2111 let map = map_abi(ty, &cx.types);
2112 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2113 let (ptr, len) = lower_map_iter(cx, map, entries)?;
2114 lower_pointer_pair_to_memory(cx, offset, ptr, len);
2115 Ok(())
2116}
2117
2118fn lower_map_iter<'a, K, V, U>(
2119 cx: &mut LowerContext<'_, U>,
2120 map: &TypeMap,
2121 entries: impl ExactSizeIterator<Item = (&'a K, &'a V)>,
2122) -> Result<(usize, usize)>
2123where
2124 K: Lower + 'a,
2125 V: Lower + 'a,
2126{
2127 let len = entries.len();
2128 let size = len
2129 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2130 .ok_or_else(|| format_err!("size overflow copying a map"))?;
2131 let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?;
2132
2133 let mut entry_offset = ptr;
2134 for (key, value) in entries {
2135 <K as Lower>::linear_lower_to_memory(key, cx, map.key, entry_offset)?;
2137 <V as Lower>::linear_lower_to_memory(
2139 value,
2140 cx,
2141 map.value,
2142 entry_offset + usize::try_from(map.value_offset32)?,
2143 )?;
2144 entry_offset += usize::try_from(map.entry_abi.size32)?;
2145 }
2146
2147 Ok((ptr, len))
2148}
2149
2150trait LiftMap<K, V>: Sized {
2152 fn with_capacity(len: usize) -> Result<Self>;
2154
2155 fn push(&mut self, key: K, value: V) -> Result<()>;
2157}
2158
2159impl<K, V, S> LiftMap<K, V> for TryHashMap<K, V, S>
2160where
2161 K: Eq + Hash,
2162 S: BuildHasher + Default,
2163{
2164 fn with_capacity(len: usize) -> Result<Self> {
2165 Ok(TryHashMap::with_capacity_and_hasher(len, S::default())?)
2166 }
2167
2168 fn push(&mut self, key: K, value: V) -> Result<()> {
2169 self.insert(key, value)?;
2170 Ok(())
2171 }
2172}
2173
2174impl<K, V> LiftMap<K, V> for BTreeMap<K, V>
2175where
2176 K: Ord,
2177{
2178 fn with_capacity(_len: usize) -> Result<Self> {
2179 Ok(BTreeMap::new())
2180 }
2181
2182 fn push(&mut self, key: K, value: V) -> Result<()> {
2183 self.insert(key, value);
2184 Ok(())
2185 }
2186}
2187
2188impl<K, V, S> LiftMap<K, V> for IndexMap<K, V, S>
2189where
2190 K: Eq + Hash,
2191 S: BuildHasher + Default,
2192{
2193 fn with_capacity(len: usize) -> Result<Self> {
2194 let mut map = IndexMap::with_hasher(S::default());
2195 map.try_reserve(len)
2196 .map_err(|_| OutOfMemory::new(len.saturating_mul(mem::size_of::<(K, V)>())))?;
2197 Ok(map)
2198 }
2199
2200 fn push(&mut self, key: K, value: V) -> Result<()> {
2202 self.insert(key, value);
2203 Ok(())
2204 }
2205}
2206
2207fn lift_map<M, K, V>(
2208 cx: &mut LiftContext<'_>,
2209 ty: InterfaceType,
2210 ptr: usize,
2211 len: usize,
2212) -> Result<M>
2213where
2214 M: LiftMap<K, V>,
2215 K: Lift,
2216 V: Lift,
2217{
2218 let map = map_abi(ty, &cx.types);
2219 match len
2220 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2221 .and_then(|total| ptr.checked_add(total))
2222 {
2223 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(K, V)>())?,
2224 _ => bail!("map pointer/length out of bounds of memory"),
2225 }
2226 if ptr % (map.entry_abi.align32 as usize) != 0 {
2227 bail!("map pointer is not aligned");
2228 }
2229
2230 let mut result = M::with_capacity(len)?;
2231 for i in 0..len {
2232 let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?);
2233
2234 let key_bytes = &cx.memory()[entry_base..][..K::SIZE32];
2235 let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?;
2236
2237 let value_bytes =
2238 &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32];
2239 let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?;
2240
2241 result.push(key, value)?;
2242 }
2243
2244 Ok(result)
2245}
2246
2247fn typecheck_tuple(
2249 ty: &InterfaceType,
2250 types: &InstanceType<'_>,
2251 expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2252) -> Result<()> {
2253 match ty {
2254 InterfaceType::Tuple(t) => {
2255 let tuple = &types.types[*t];
2256 if tuple.types.len() != expected.len() {
2257 bail!(
2258 "expected {}-tuple, found {}-tuple",
2259 expected.len(),
2260 tuple.types.len()
2261 );
2262 }
2263 for (ty, check) in tuple.types.iter().zip(expected) {
2264 check(ty, types)?;
2265 }
2266 Ok(())
2267 }
2268 other => bail!("expected `tuple` found `{}`", desc(other)),
2269 }
2270}
2271
2272pub fn typecheck_record(
2275 ty: &InterfaceType,
2276 types: &InstanceType<'_>,
2277 expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2278) -> Result<()> {
2279 match ty {
2280 InterfaceType::Record(index) => {
2281 let fields = &types.types[*index].fields;
2282
2283 if fields.len() != expected.len() {
2284 bail!(
2285 "expected record of {} fields, found {} fields",
2286 expected.len(),
2287 fields.len()
2288 );
2289 }
2290
2291 for (field, &(name, check)) in fields.iter().zip(expected) {
2292 check(&field.ty, types)
2293 .with_context(|| format!("type mismatch for field {name}"))?;
2294
2295 if *field.name != *name {
2296 bail!("expected record field named {}, found {}", name, field.name);
2297 }
2298 }
2299
2300 Ok(())
2301 }
2302 other => bail!("expected `record` found `{}`", desc(other)),
2303 }
2304}
2305
2306pub fn typecheck_variant(
2309 ty: &InterfaceType,
2310 types: &InstanceType<'_>,
2311 expected: &[(
2312 &str,
2313 Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2314 )],
2315) -> Result<()> {
2316 match ty {
2317 InterfaceType::Variant(index) => {
2318 let cases = &types.types[*index].cases;
2319
2320 if cases.len() != expected.len() {
2321 bail!(
2322 "expected variant of {} cases, found {} cases",
2323 expected.len(),
2324 cases.len()
2325 );
2326 }
2327
2328 for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2329 if **case_name != *name {
2330 bail!("expected variant case named {name}, found {case_name}");
2331 }
2332
2333 match (check, case_ty) {
2334 (Some(check), Some(ty)) => check(ty, types)
2335 .with_context(|| format!("type mismatch for case {name}"))?,
2336 (None, None) => {}
2337 (Some(_), None) => {
2338 bail!("case `{name}` has no type but one was expected")
2339 }
2340 (None, Some(_)) => {
2341 bail!("case `{name}` has a type but none was expected")
2342 }
2343 }
2344 }
2345
2346 Ok(())
2347 }
2348 other => bail!("expected `variant` found `{}`", desc(other)),
2349 }
2350}
2351
2352pub fn typecheck_enum(
2355 ty: &InterfaceType,
2356 types: &InstanceType<'_>,
2357 expected: &[&str],
2358) -> Result<()> {
2359 match ty {
2360 InterfaceType::Enum(index) => {
2361 let names = &types.types[*index].names;
2362
2363 if names.len() != expected.len() {
2364 bail!(
2365 "expected enum of {} names, found {} names",
2366 expected.len(),
2367 names.len()
2368 );
2369 }
2370
2371 for (name, expected) in names.iter().zip(expected) {
2372 if **name != **expected {
2373 bail!("expected enum case named {expected}, found {name}");
2374 }
2375 }
2376
2377 Ok(())
2378 }
2379 other => bail!("expected `enum` found `{}`", desc(other)),
2380 }
2381}
2382
2383pub fn typecheck_flags(
2386 ty: &InterfaceType,
2387 types: &InstanceType<'_>,
2388 expected: &[&str],
2389) -> Result<()> {
2390 match ty {
2391 InterfaceType::Flags(index) => {
2392 let names = &types.types[*index].names;
2393
2394 if names.len() != expected.len() {
2395 bail!(
2396 "expected flags type with {} names, found {} names",
2397 expected.len(),
2398 names.len()
2399 );
2400 }
2401
2402 for (name, expected) in names.iter().zip(expected) {
2403 if **name != **expected {
2404 bail!("expected flag named {expected}, found {name}");
2405 }
2406 }
2407
2408 Ok(())
2409 }
2410 other => bail!("expected `flags` found `{}`", desc(other)),
2411 }
2412}
2413
2414pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2416 f.write_str("(")?;
2417 let mut wrote = false;
2418 for (index, name) in names.iter().enumerate() {
2419 if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2420 if wrote {
2421 f.write_str("|")?;
2422 } else {
2423 wrote = true;
2424 }
2425
2426 f.write_str(name)?;
2427 }
2428 }
2429 f.write_str(")")
2430}
2431
2432unsafe impl<T> ComponentType for Option<T>
2433where
2434 T: ComponentType,
2435{
2436 type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2437
2438 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2439 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC;
2440
2441 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2442 match ty {
2443 InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2444 other => bail!("expected `option` found `{}`", desc(other)),
2445 }
2446 }
2447}
2448
2449unsafe impl<T> ComponentVariant for Option<T>
2450where
2451 T: ComponentType,
2452{
2453 const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2454}
2455
2456unsafe impl<T> Lower for Option<T>
2457where
2458 T: Lower,
2459{
2460 fn linear_lower_to_flat<U>(
2461 &self,
2462 cx: &mut LowerContext<'_, U>,
2463 ty: InterfaceType,
2464 dst: &mut MaybeUninit<Self::Lower>,
2465 ) -> Result<()> {
2466 let payload = match ty {
2467 InterfaceType::Option(ty) => cx.types[ty].ty,
2468 _ => bad_type_info(),
2469 };
2470 match self {
2471 None => {
2472 map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2473 unsafe {
2480 map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2481 }
2482 }
2483 Some(val) => {
2484 map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2485 val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2486 }
2487 }
2488 Ok(())
2489 }
2490
2491 fn linear_lower_to_memory<U>(
2492 &self,
2493 cx: &mut LowerContext<'_, U>,
2494 ty: InterfaceType,
2495 offset: usize,
2496 ) -> Result<()> {
2497 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2498 let payload = match ty {
2499 InterfaceType::Option(ty) => cx.types[ty].ty,
2500 _ => bad_type_info(),
2501 };
2502 match self {
2503 None => {
2504 cx.get::<1>(offset)[0] = 0;
2505 }
2506 Some(val) => {
2507 cx.get::<1>(offset)[0] = 1;
2508 val.linear_lower_to_memory(
2509 cx,
2510 payload,
2511 offset + (Self::INFO.payload_offset32 as usize),
2512 )?;
2513 }
2514 }
2515 Ok(())
2516 }
2517}
2518
2519unsafe impl<T> Lift for Option<T>
2520where
2521 T: Lift,
2522{
2523 fn linear_lift_from_flat(
2524 cx: &mut LiftContext<'_>,
2525 ty: InterfaceType,
2526 src: &Self::Lower,
2527 ) -> Result<Self> {
2528 let payload = match ty {
2529 InterfaceType::Option(ty) => cx.types[ty].ty,
2530 _ => bad_type_info(),
2531 };
2532 Ok(match src.A1.get_i32() {
2533 0 => None,
2534 1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2535 _ => bail!("invalid option discriminant"),
2536 })
2537 }
2538
2539 fn linear_lift_from_memory(
2540 cx: &mut LiftContext<'_>,
2541 ty: InterfaceType,
2542 bytes: &[u8],
2543 ) -> Result<Self> {
2544 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2545 let payload_ty = match ty {
2546 InterfaceType::Option(ty) => cx.types[ty].ty,
2547 _ => bad_type_info(),
2548 };
2549 let discrim = bytes[0];
2550 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2551 match discrim {
2552 0 => Ok(None),
2553 1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2554 _ => bail!("invalid option discriminant"),
2555 }
2556 }
2557}
2558
2559#[derive(Clone, Copy)]
2560#[repr(C)]
2561pub struct ResultLower<T: Copy, E: Copy> {
2562 tag: ValRaw,
2563 payload: ResultLowerPayload<T, E>,
2564}
2565
2566#[derive(Clone, Copy)]
2567#[repr(C)]
2568union ResultLowerPayload<T: Copy, E: Copy> {
2569 ok: T,
2570 err: E,
2571}
2572
2573unsafe impl<T, E> ComponentType for Result<T, E>
2574where
2575 T: ComponentType,
2576 E: ComponentType,
2577{
2578 type Lower = ResultLower<T::Lower, E::Lower>;
2579
2580 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2581 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC || E::MAY_REQUIRE_REALLOC;
2582
2583 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2584 match ty {
2585 InterfaceType::Result(r) => {
2586 let result = &types.types[*r];
2587 match &result.ok {
2588 Some(ty) => T::typecheck(ty, types)?,
2589 None if T::IS_RUST_UNIT_TYPE => {}
2590 None => bail!("expected no `ok` type"),
2591 }
2592 match &result.err {
2593 Some(ty) => E::typecheck(ty, types)?,
2594 None if E::IS_RUST_UNIT_TYPE => {}
2595 None => bail!("expected no `err` type"),
2596 }
2597 Ok(())
2598 }
2599 other => bail!("expected `result` found `{}`", desc(other)),
2600 }
2601 }
2602}
2603
2604pub unsafe fn lower_payload<P, T>(
2617 payload: &mut MaybeUninit<P>,
2618 typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2619 lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2620) -> Result<()> {
2621 let typed = typed_payload(payload);
2622 lower(typed)?;
2623
2624 let typed_len = unsafe { storage_as_slice(typed).len() };
2625 let payload = unsafe { storage_as_slice_mut(payload) };
2626 for slot in payload[typed_len..].iter_mut() {
2627 slot.write(ValRaw::u64(0));
2628 }
2629 Ok(())
2630}
2631
2632unsafe impl<T, E> ComponentVariant for Result<T, E>
2633where
2634 T: ComponentType,
2635 E: ComponentType,
2636{
2637 const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2638}
2639
2640unsafe impl<T, E> Lower for Result<T, E>
2641where
2642 T: Lower,
2643 E: Lower,
2644{
2645 fn linear_lower_to_flat<U>(
2646 &self,
2647 cx: &mut LowerContext<'_, U>,
2648 ty: InterfaceType,
2649 dst: &mut MaybeUninit<Self::Lower>,
2650 ) -> Result<()> {
2651 let (ok, err) = match ty {
2652 InterfaceType::Result(ty) => {
2653 let ty = &cx.types[ty];
2654 (ty.ok, ty.err)
2655 }
2656 _ => bad_type_info(),
2657 };
2658
2659 match self {
2721 Ok(e) => {
2722 map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2723 unsafe {
2724 lower_payload(
2725 map_maybe_uninit!(dst.payload),
2726 |payload| map_maybe_uninit!(payload.ok),
2727 |dst| match ok {
2728 Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2729 None => Ok(()),
2730 },
2731 )
2732 }
2733 }
2734 Err(e) => {
2735 map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2736 unsafe {
2737 lower_payload(
2738 map_maybe_uninit!(dst.payload),
2739 |payload| map_maybe_uninit!(payload.err),
2740 |dst| match err {
2741 Some(err) => e.linear_lower_to_flat(cx, err, dst),
2742 None => Ok(()),
2743 },
2744 )
2745 }
2746 }
2747 }
2748 }
2749
2750 fn linear_lower_to_memory<U>(
2751 &self,
2752 cx: &mut LowerContext<'_, U>,
2753 ty: InterfaceType,
2754 offset: usize,
2755 ) -> Result<()> {
2756 let (ok, err) = match ty {
2757 InterfaceType::Result(ty) => {
2758 let ty = &cx.types[ty];
2759 (ty.ok, ty.err)
2760 }
2761 _ => bad_type_info(),
2762 };
2763 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2764 let payload_offset = Self::INFO.payload_offset32 as usize;
2765 match self {
2766 Ok(e) => {
2767 cx.get::<1>(offset)[0] = 0;
2768 if let Some(ok) = ok {
2769 e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2770 }
2771 }
2772 Err(e) => {
2773 cx.get::<1>(offset)[0] = 1;
2774 if let Some(err) = err {
2775 e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2776 }
2777 }
2778 }
2779 Ok(())
2780 }
2781}
2782
2783unsafe impl<T, E> Lift for Result<T, E>
2784where
2785 T: Lift,
2786 E: Lift,
2787{
2788 #[inline]
2789 fn linear_lift_from_flat(
2790 cx: &mut LiftContext<'_>,
2791 ty: InterfaceType,
2792 src: &Self::Lower,
2793 ) -> Result<Self> {
2794 let (ok, err) = match ty {
2795 InterfaceType::Result(ty) => {
2796 let ty = &cx.types[ty];
2797 (ty.ok, ty.err)
2798 }
2799 _ => bad_type_info(),
2800 };
2801 Ok(match src.tag.get_i32() {
2821 0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2822 1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2823 _ => bail!("invalid expected discriminant"),
2824 })
2825 }
2826
2827 #[inline]
2828 fn linear_lift_from_memory(
2829 cx: &mut LiftContext<'_>,
2830 ty: InterfaceType,
2831 bytes: &[u8],
2832 ) -> Result<Self> {
2833 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2834 let discrim = bytes[0];
2835 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2836 let (ok, err) = match ty {
2837 InterfaceType::Result(ty) => {
2838 let ty = &cx.types[ty];
2839 (ty.ok, ty.err)
2840 }
2841 _ => bad_type_info(),
2842 };
2843 match discrim {
2844 0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2845 1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2846 _ => bail!("invalid expected discriminant"),
2847 }
2848 }
2849}
2850
2851fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2852where
2853 T: Lift,
2854{
2855 match ty {
2856 Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2857 None => Ok(empty_lift()),
2858 }
2859}
2860
2861fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2862where
2863 T: Lift,
2864{
2865 match ty {
2866 Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2867 None => Ok(empty_lift()),
2868 }
2869}
2870
2871fn empty_lift<T>() -> T
2872where
2873 T: Lift,
2874{
2875 assert!(T::IS_RUST_UNIT_TYPE);
2876 assert_eq!(mem::size_of::<T>(), 0);
2877 unsafe { MaybeUninit::uninit().assume_init() }
2878}
2879
2880#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2885#[doc(hidden)]
2886#[derive(Clone, Copy)]
2887#[repr(C)]
2888pub struct TupleLower<
2889 T1 = (),
2890 T2 = (),
2891 T3 = (),
2892 T4 = (),
2893 T5 = (),
2894 T6 = (),
2895 T7 = (),
2896 T8 = (),
2897 T9 = (),
2898 T10 = (),
2899 T11 = (),
2900 T12 = (),
2901 T13 = (),
2902 T14 = (),
2903 T15 = (),
2904 T16 = (),
2905 T17 = (),
2906> {
2907 A1: T1,
2909 A2: T2,
2910 A3: T3,
2911 A4: T4,
2912 A5: T5,
2913 A6: T6,
2914 A7: T7,
2915 A8: T8,
2916 A9: T9,
2917 A10: T10,
2918 A11: T11,
2919 A12: T12,
2920 A13: T13,
2921 A14: T14,
2922 A15: T15,
2923 A16: T16,
2924 A17: T17,
2925 _align_tuple_lower0_correctly: [ValRaw; 0],
2926}
2927
2928macro_rules! impl_component_ty_for_tuples {
2929 ($n:tt $($t:ident)*) => {
2930 #[allow(non_snake_case, reason = "macro-generated code")]
2931 unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2932 where $($t: ComponentType),*
2933 {
2934 type Lower = TupleLower<$($t::Lower),*>;
2935
2936 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2937 $($t::ABI),*
2938 ]);
2939 const MAY_REQUIRE_REALLOC: bool = false $(|| $t::MAY_REQUIRE_REALLOC)*;
2940
2941 const IS_RUST_UNIT_TYPE: bool = {
2942 let mut _is_unit = true;
2943 $(
2944 let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2945 _is_unit = false;
2946 )*
2947 _is_unit
2948 };
2949
2950 fn typecheck(
2951 ty: &InterfaceType,
2952 types: &InstanceType<'_>,
2953 ) -> Result<()> {
2954 typecheck_tuple(ty, types, &[$($t::typecheck),*])
2955 }
2956 }
2957
2958 #[allow(non_snake_case, reason = "macro-generated code")]
2959 unsafe impl<$($t,)*> Lower for ($($t,)*)
2960 where $($t: Lower),*
2961 {
2962 fn linear_lower_to_flat<U>(
2963 &self,
2964 cx: &mut LowerContext<'_, U>,
2965 ty: InterfaceType,
2966 _dst: &mut MaybeUninit<Self::Lower>,
2967 ) -> Result<()> {
2968 let types = match ty {
2969 InterfaceType::Tuple(t) => &cx.types[t].types,
2970 _ => bad_type_info(),
2971 };
2972 let ($($t,)*) = self;
2973 let mut _types = types.iter();
2974 $(
2975 let ty = *_types.next().unwrap_or_else(bad_type_info);
2976 $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2977 )*
2978 Ok(())
2979 }
2980
2981 fn linear_lower_to_memory<U>(
2982 &self,
2983 cx: &mut LowerContext<'_, U>,
2984 ty: InterfaceType,
2985 mut _offset: usize,
2986 ) -> Result<()> {
2987 debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2988 let types = match ty {
2989 InterfaceType::Tuple(t) => &cx.types[t].types,
2990 _ => bad_type_info(),
2991 };
2992 let ($($t,)*) = self;
2993 let mut _types = types.iter();
2994 $(
2995 let ty = *_types.next().unwrap_or_else(bad_type_info);
2996 $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2997 )*
2998 Ok(())
2999 }
3000 }
3001
3002 #[allow(non_snake_case, reason = "macro-generated code")]
3003 unsafe impl<$($t,)*> Lift for ($($t,)*)
3004 where $($t: Lift),*
3005 {
3006 #[inline]
3007 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
3008 let types = match ty {
3009 InterfaceType::Tuple(t) => &cx.types[t].types,
3010 _ => bad_type_info(),
3011 };
3012 let mut _types = types.iter();
3013 Ok(($(
3014 $t::linear_lift_from_flat(
3015 cx,
3016 *_types.next().unwrap_or_else(bad_type_info),
3017 &_src.$t,
3018 )?,
3019 )*))
3020 }
3021
3022 #[inline]
3023 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
3024 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3025 let types = match ty {
3026 InterfaceType::Tuple(t) => &cx.types[t].types,
3027 _ => bad_type_info(),
3028 };
3029 let mut _types = types.iter();
3030 let mut _offset = 0;
3031 $(
3032 let ty = *_types.next().unwrap_or_else(bad_type_info);
3033 let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
3034 )*
3035 Ok(($($t,)*))
3036 }
3037 }
3038
3039 #[allow(non_snake_case, reason = "macro-generated code")]
3040 unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
3041 where $($t: ComponentType),*
3042 {}
3043 };
3044}
3045
3046for_each_function_signature!(impl_component_ty_for_tuples);
3047
3048unsafe impl<T, const N: usize> ComponentType for [T; N]
3049where
3050 T: ComponentType,
3051{
3052 type Lower = [T::Lower; N];
3053
3054 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_length_list_static(&T::ABI, N);
3055
3056 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
3057 match ty {
3058 InterfaceType::FixedLengthList(t) => {
3059 let list = &types.types[*t];
3060 match usize::try_from(list.size) {
3061 Ok(n) if n == N => {}
3062 _ => bail!("expected `list<_, {}>` found `list<_, {N}>`", list.size),
3063 }
3064 T::typecheck(&list.element, types)
3065 }
3066 other => bail!("expected `list<_, {N}>` found `{}`", desc(other)),
3067 }
3068 }
3069}
3070
3071unsafe impl<T, const N: usize> Lower for [T; N]
3072where
3073 T: Lower,
3074{
3075 fn linear_lower_to_flat<U>(
3076 &self,
3077 cx: &mut LowerContext<'_, U>,
3078 ty: InterfaceType,
3079 dst: &mut MaybeUninit<Self::Lower>,
3080 ) -> Result<()> {
3081 let element = match ty {
3082 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3083 _ => bad_type_info(),
3084 };
3085 for (i, val) in self.iter().enumerate() {
3086 val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
3087 }
3088 Ok(())
3089 }
3090
3091 fn linear_lower_to_memory<U>(
3092 &self,
3093 cx: &mut LowerContext<'_, U>,
3094 ty: InterfaceType,
3095 offset: usize,
3096 ) -> Result<()> {
3097 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
3098 let element = match ty {
3099 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3100 _ => bad_type_info(),
3101 };
3102 for (i, val) in self.iter().enumerate() {
3103 val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
3104 }
3105 Ok(())
3106 }
3107}
3108
3109unsafe impl<T, const N: usize> Lift for [T; N]
3110where
3111 T: Lift + Sized,
3112{
3113 fn linear_lift_from_flat(
3114 cx: &mut LiftContext<'_>,
3115 ty: InterfaceType,
3116 src: &Self::Lower,
3117 ) -> Result<Self> {
3118 let element = match ty {
3119 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3120 _ => bad_type_info(),
3121 };
3122 array_try_from_fn(|n| T::linear_lift_from_flat(cx, element, &src[n]))
3123 }
3124
3125 fn linear_lift_from_memory(
3126 cx: &mut LiftContext<'_>,
3127 ty: InterfaceType,
3128 bytes: &[u8],
3129 ) -> Result<Self> {
3130 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3131 let element = match ty {
3132 InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3133 _ => bad_type_info(),
3134 };
3135 let mut offset = 0;
3136 array_try_from_fn(|_n| {
3137 let res = T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]);
3138 offset += T::SIZE32;
3139 res
3140 })
3141 }
3142}
3143
3144pub fn desc(ty: &InterfaceType) -> &'static str {
3145 match ty {
3146 InterfaceType::U8 => "u8",
3147 InterfaceType::S8 => "s8",
3148 InterfaceType::U16 => "u16",
3149 InterfaceType::S16 => "s16",
3150 InterfaceType::U32 => "u32",
3151 InterfaceType::S32 => "s32",
3152 InterfaceType::U64 => "u64",
3153 InterfaceType::S64 => "s64",
3154 InterfaceType::Float32 => "f32",
3155 InterfaceType::Float64 => "f64",
3156 InterfaceType::Bool => "bool",
3157 InterfaceType::Char => "char",
3158 InterfaceType::String => "string",
3159 InterfaceType::List(_) => "list",
3160 InterfaceType::Tuple(_) => "tuple",
3161 InterfaceType::Option(_) => "option",
3162 InterfaceType::Result(_) => "result",
3163
3164 InterfaceType::Record(_) => "record",
3165 InterfaceType::Variant(_) => "variant",
3166 InterfaceType::Flags(_) => "flags",
3167 InterfaceType::Enum(_) => "enum",
3168 InterfaceType::Own(_) => "owned resource",
3169 InterfaceType::Borrow(_) => "borrowed resource",
3170 InterfaceType::Future(_) => "future",
3171 InterfaceType::Stream(_) => "stream",
3172 InterfaceType::ErrorContext(_) => "error-context",
3173 InterfaceType::Map(_) => "map",
3174 InterfaceType::FixedLengthList(_) => "list<_, N>",
3175 }
3176}
3177
3178#[cold]
3179#[doc(hidden)]
3180pub fn bad_type_info<T>() -> T {
3181 panic!("bad type information detected");
3185}