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