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 = match LiftContext::new(store, self.options, self.instance) {
1813 Ok(cx) => cx,
1814 Err(e) => return Some(Err(e)),
1815 };
1816 self.get_from_store(&mut cx, index)
1817 }
1818
1819 fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1820 if index >= self.len {
1821 return None;
1822 }
1823 let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1830 Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1831 }
1832
1833 pub fn iter<'a, U: 'static>(
1838 &'a self,
1839 store: impl Into<StoreContextMut<'a, U>>,
1840 ) -> Result<impl ExactSizeIterator<Item = Result<T>> + 'a> {
1841 let store = store.into().0;
1842 let mut cx = LiftContext::new(store, self.options, self.instance)?;
1843 Ok((0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap()))
1844 }
1845}
1846
1847macro_rules! raw_wasm_list_accessors {
1848 ($($i:ident)*) => ($(
1849 impl WasmList<$i> {
1850 pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1868 let memory = self.instance.options_memory(store.into().0, self.options);
1869 self._as_le_slice(memory)
1870 }
1871
1872 fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1873 let byte_size = self.len * mem::size_of::<$i>();
1875 let bytes = &all_of_memory[self.ptr..][..byte_size];
1876
1877 unsafe {
1889 let (head, body, tail) = bytes.align_to::<$i>();
1890 assert!(head.is_empty() && tail.is_empty());
1891 body
1892 }
1893 }
1894 }
1895 )*)
1896}
1897
1898raw_wasm_list_accessors! {
1899 i8 i16 i32 i64
1900 u8 u16 u32 u64
1901}
1902
1903unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
1906 type Lower = <[T] as ComponentType>::Lower;
1907
1908 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1909
1910 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1911 <[T] as ComponentType>::typecheck(ty, types)
1912 }
1913}
1914
1915unsafe impl<T: Lift> Lift for WasmList<T> {
1916 fn linear_lift_from_flat(
1917 cx: &mut LiftContext<'_>,
1918 ty: InterfaceType,
1919 src: &Self::Lower,
1920 ) -> Result<Self> {
1921 let elem = match ty {
1922 InterfaceType::List(i) => cx.types[i].element,
1923 _ => bad_type_info(),
1924 };
1925 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1926 WasmList::new(ptr, len, cx, elem)
1927 }
1928
1929 fn linear_lift_from_memory(
1930 cx: &mut LiftContext<'_>,
1931 ty: InterfaceType,
1932 bytes: &[u8],
1933 ) -> Result<Self> {
1934 let elem = match ty {
1935 InterfaceType::List(i) => cx.types[i].element,
1936 _ => bad_type_info(),
1937 };
1938 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1939 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1940 WasmList::new(ptr, len, cx, elem)
1941 }
1942}
1943
1944fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap {
1951 match ty {
1952 InterfaceType::Map(i) => &types[i],
1953 _ => bad_type_info(),
1954 }
1955}
1956
1957unsafe impl<K, V> ComponentType for HashMap<K, V>
1958where
1959 K: ComponentType,
1960 V: ComponentType,
1961{
1962 type Lower = [ValRaw; 2];
1963
1964 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1965
1966 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1967 TryHashMap::<K, V>::typecheck(ty, types)
1968 }
1969}
1970
1971unsafe impl<K, V> Lower for HashMap<K, V>
1972where
1973 K: Lower,
1974 V: Lower,
1975{
1976 fn linear_lower_to_flat<U>(
1977 &self,
1978 cx: &mut LowerContext<'_, U>,
1979 ty: InterfaceType,
1980 dst: &mut MaybeUninit<[ValRaw; 2]>,
1981 ) -> Result<()> {
1982 let map = map_abi(ty, &cx.types);
1983 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
1984 lower_pointer_pair_to_flat(cx, dst, ptr, len);
1985 Ok(())
1986 }
1987
1988 fn linear_lower_to_memory<U>(
1989 &self,
1990 cx: &mut LowerContext<'_, U>,
1991 ty: InterfaceType,
1992 offset: usize,
1993 ) -> Result<()> {
1994 let map = map_abi(ty, &cx.types);
1995 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
1996 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
1997 lower_pointer_pair_to_memory(cx, offset, ptr, len);
1998 Ok(())
1999 }
2000}
2001
2002unsafe impl<K, V> Lift for HashMap<K, V>
2003where
2004 K: Lift + Eq + Hash,
2005 V: Lift,
2006{
2007 fn linear_lift_from_flat(
2008 cx: &mut LiftContext<'_>,
2009 ty: InterfaceType,
2010 src: &Self::Lower,
2011 ) -> Result<Self> {
2012 Ok(TryHashMap::<K, V>::linear_lift_from_flat(cx, ty, src)?.into())
2013 }
2014
2015 fn linear_lift_from_memory(
2016 cx: &mut LiftContext<'_>,
2017 ty: InterfaceType,
2018 bytes: &[u8],
2019 ) -> Result<Self> {
2020 Ok(TryHashMap::<K, V>::linear_lift_from_memory(cx, ty, bytes)?.into())
2021 }
2022}
2023
2024fn lower_map_iter<'a, K, V, U>(
2025 cx: &mut LowerContext<'_, U>,
2026 map: &TypeMap,
2027 len: usize,
2028 iter: impl Iterator<Item = (&'a K, &'a V)>,
2029) -> Result<(usize, usize)>
2030where
2031 K: Lower + 'a,
2032 V: Lower + 'a,
2033{
2034 let size = len
2035 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2036 .ok_or_else(|| format_err!("size overflow copying a map"))?;
2037 let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?;
2038
2039 let mut entry_offset = ptr;
2040 for (key, value) in iter {
2041 <K as Lower>::linear_lower_to_memory(key, cx, map.key, entry_offset)?;
2043 <V as Lower>::linear_lower_to_memory(
2045 value,
2046 cx,
2047 map.value,
2048 entry_offset + usize::try_from(map.value_offset32)?,
2049 )?;
2050 entry_offset += usize::try_from(map.entry_abi.size32)?;
2051 }
2052
2053 Ok((ptr, len))
2054}
2055
2056unsafe impl<K, V> ComponentType for TryHashMap<K, V>
2057where
2058 K: ComponentType,
2059 V: ComponentType,
2060{
2061 type Lower = [ValRaw; 2];
2062
2063 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
2064
2065 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2066 match ty {
2067 InterfaceType::Map(t) => {
2068 let map_ty = &types.types[*t];
2069 K::typecheck(&map_ty.key, types)?;
2070 V::typecheck(&map_ty.value, types)?;
2071 Ok(())
2072 }
2073 other => bail!("expected `map` found `{}`", desc(other)),
2074 }
2075 }
2076}
2077
2078unsafe impl<K, V> Lower for TryHashMap<K, V>
2079where
2080 K: Lower,
2081 V: Lower,
2082{
2083 fn linear_lower_to_flat<U>(
2084 &self,
2085 cx: &mut LowerContext<'_, U>,
2086 ty: InterfaceType,
2087 dst: &mut MaybeUninit<[ValRaw; 2]>,
2088 ) -> Result<()> {
2089 let map = map_abi(ty, &cx.types);
2090 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2091 lower_pointer_pair_to_flat(cx, dst, ptr, len);
2092 Ok(())
2093 }
2094
2095 fn linear_lower_to_memory<U>(
2096 &self,
2097 cx: &mut LowerContext<'_, U>,
2098 ty: InterfaceType,
2099 offset: usize,
2100 ) -> Result<()> {
2101 let map = map_abi(ty, &cx.types);
2102 debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2103 let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2104 lower_pointer_pair_to_memory(cx, offset, ptr, len);
2105 Ok(())
2106 }
2107}
2108
2109unsafe impl<K, V> Lift for TryHashMap<K, V>
2110where
2111 K: Lift + Eq + Hash,
2112 V: Lift,
2113{
2114 fn linear_lift_from_flat(
2115 cx: &mut LiftContext<'_>,
2116 ty: InterfaceType,
2117 src: &Self::Lower,
2118 ) -> Result<Self> {
2119 let map = map_abi(ty, &cx.types);
2120 let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
2121 lift_try_map(cx, map, ptr, len)
2122 }
2123
2124 fn linear_lift_from_memory(
2125 cx: &mut LiftContext<'_>,
2126 ty: InterfaceType,
2127 bytes: &[u8],
2128 ) -> Result<Self> {
2129 let map = map_abi(ty, &cx.types);
2130 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2131 let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
2132 lift_try_map(cx, map, ptr, len)
2133 }
2134}
2135
2136fn lift_try_map<K, V>(
2137 cx: &mut LiftContext<'_>,
2138 map: &TypeMap,
2139 ptr: usize,
2140 len: usize,
2141) -> Result<TryHashMap<K, V>>
2142where
2143 K: Lift + Eq + Hash,
2144 V: Lift,
2145{
2146 let mut result = TryHashMap::with_capacity(len)?;
2147
2148 match len
2149 .checked_mul(usize::try_from(map.entry_abi.size32)?)
2150 .and_then(|total| ptr.checked_add(total))
2151 {
2152 Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(K, V)>())?,
2153 _ => bail!("map pointer/length out of bounds of memory"),
2154 }
2155 if ptr % (map.entry_abi.align32 as usize) != 0 {
2156 bail!("map pointer is not aligned");
2157 }
2158
2159 for i in 0..len {
2160 let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?);
2161
2162 let key_bytes = &cx.memory()[entry_base..][..K::SIZE32];
2163 let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?;
2164
2165 let value_bytes =
2166 &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32];
2167 let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?;
2168
2169 result.insert(key, value)?;
2170 }
2171
2172 Ok(result)
2173}
2174
2175fn typecheck_tuple(
2177 ty: &InterfaceType,
2178 types: &InstanceType<'_>,
2179 expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2180) -> Result<()> {
2181 match ty {
2182 InterfaceType::Tuple(t) => {
2183 let tuple = &types.types[*t];
2184 if tuple.types.len() != expected.len() {
2185 bail!(
2186 "expected {}-tuple, found {}-tuple",
2187 expected.len(),
2188 tuple.types.len()
2189 );
2190 }
2191 for (ty, check) in tuple.types.iter().zip(expected) {
2192 check(ty, types)?;
2193 }
2194 Ok(())
2195 }
2196 other => bail!("expected `tuple` found `{}`", desc(other)),
2197 }
2198}
2199
2200pub fn typecheck_record(
2203 ty: &InterfaceType,
2204 types: &InstanceType<'_>,
2205 expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2206) -> Result<()> {
2207 match ty {
2208 InterfaceType::Record(index) => {
2209 let fields = &types.types[*index].fields;
2210
2211 if fields.len() != expected.len() {
2212 bail!(
2213 "expected record of {} fields, found {} fields",
2214 expected.len(),
2215 fields.len()
2216 );
2217 }
2218
2219 for (field, &(name, check)) in fields.iter().zip(expected) {
2220 check(&field.ty, types)
2221 .with_context(|| format!("type mismatch for field {name}"))?;
2222
2223 if field.name != name {
2224 bail!("expected record field named {}, found {}", name, field.name);
2225 }
2226 }
2227
2228 Ok(())
2229 }
2230 other => bail!("expected `record` found `{}`", desc(other)),
2231 }
2232}
2233
2234pub fn typecheck_variant(
2237 ty: &InterfaceType,
2238 types: &InstanceType<'_>,
2239 expected: &[(
2240 &str,
2241 Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2242 )],
2243) -> Result<()> {
2244 match ty {
2245 InterfaceType::Variant(index) => {
2246 let cases = &types.types[*index].cases;
2247
2248 if cases.len() != expected.len() {
2249 bail!(
2250 "expected variant of {} cases, found {} cases",
2251 expected.len(),
2252 cases.len()
2253 );
2254 }
2255
2256 for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2257 if *case_name != name {
2258 bail!("expected variant case named {name}, found {case_name}");
2259 }
2260
2261 match (check, case_ty) {
2262 (Some(check), Some(ty)) => check(ty, types)
2263 .with_context(|| format!("type mismatch for case {name}"))?,
2264 (None, None) => {}
2265 (Some(_), None) => {
2266 bail!("case `{name}` has no type but one was expected")
2267 }
2268 (None, Some(_)) => {
2269 bail!("case `{name}` has a type but none was expected")
2270 }
2271 }
2272 }
2273
2274 Ok(())
2275 }
2276 other => bail!("expected `variant` found `{}`", desc(other)),
2277 }
2278}
2279
2280pub fn typecheck_enum(
2283 ty: &InterfaceType,
2284 types: &InstanceType<'_>,
2285 expected: &[&str],
2286) -> Result<()> {
2287 match ty {
2288 InterfaceType::Enum(index) => {
2289 let names = &types.types[*index].names;
2290
2291 if names.len() != expected.len() {
2292 bail!(
2293 "expected enum of {} names, found {} names",
2294 expected.len(),
2295 names.len()
2296 );
2297 }
2298
2299 for (name, expected) in names.iter().zip(expected) {
2300 if name != expected {
2301 bail!("expected enum case named {expected}, found {name}");
2302 }
2303 }
2304
2305 Ok(())
2306 }
2307 other => bail!("expected `enum` found `{}`", desc(other)),
2308 }
2309}
2310
2311pub fn typecheck_flags(
2314 ty: &InterfaceType,
2315 types: &InstanceType<'_>,
2316 expected: &[&str],
2317) -> Result<()> {
2318 match ty {
2319 InterfaceType::Flags(index) => {
2320 let names = &types.types[*index].names;
2321
2322 if names.len() != expected.len() {
2323 bail!(
2324 "expected flags type with {} names, found {} names",
2325 expected.len(),
2326 names.len()
2327 );
2328 }
2329
2330 for (name, expected) in names.iter().zip(expected) {
2331 if name != expected {
2332 bail!("expected flag named {expected}, found {name}");
2333 }
2334 }
2335
2336 Ok(())
2337 }
2338 other => bail!("expected `flags` found `{}`", desc(other)),
2339 }
2340}
2341
2342pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2344 f.write_str("(")?;
2345 let mut wrote = false;
2346 for (index, name) in names.iter().enumerate() {
2347 if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2348 if wrote {
2349 f.write_str("|")?;
2350 } else {
2351 wrote = true;
2352 }
2353
2354 f.write_str(name)?;
2355 }
2356 }
2357 f.write_str(")")
2358}
2359
2360unsafe impl<T> ComponentType for Option<T>
2361where
2362 T: ComponentType,
2363{
2364 type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2365
2366 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2367 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC;
2368
2369 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2370 match ty {
2371 InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2372 other => bail!("expected `option` found `{}`", desc(other)),
2373 }
2374 }
2375}
2376
2377unsafe impl<T> ComponentVariant for Option<T>
2378where
2379 T: ComponentType,
2380{
2381 const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2382}
2383
2384unsafe impl<T> Lower for Option<T>
2385where
2386 T: Lower,
2387{
2388 fn linear_lower_to_flat<U>(
2389 &self,
2390 cx: &mut LowerContext<'_, U>,
2391 ty: InterfaceType,
2392 dst: &mut MaybeUninit<Self::Lower>,
2393 ) -> Result<()> {
2394 let payload = match ty {
2395 InterfaceType::Option(ty) => cx.types[ty].ty,
2396 _ => bad_type_info(),
2397 };
2398 match self {
2399 None => {
2400 map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2401 unsafe {
2408 map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2409 }
2410 }
2411 Some(val) => {
2412 map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2413 val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2414 }
2415 }
2416 Ok(())
2417 }
2418
2419 fn linear_lower_to_memory<U>(
2420 &self,
2421 cx: &mut LowerContext<'_, U>,
2422 ty: InterfaceType,
2423 offset: usize,
2424 ) -> Result<()> {
2425 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2426 let payload = match ty {
2427 InterfaceType::Option(ty) => cx.types[ty].ty,
2428 _ => bad_type_info(),
2429 };
2430 match self {
2431 None => {
2432 cx.get::<1>(offset)[0] = 0;
2433 }
2434 Some(val) => {
2435 cx.get::<1>(offset)[0] = 1;
2436 val.linear_lower_to_memory(
2437 cx,
2438 payload,
2439 offset + (Self::INFO.payload_offset32 as usize),
2440 )?;
2441 }
2442 }
2443 Ok(())
2444 }
2445}
2446
2447unsafe impl<T> Lift for Option<T>
2448where
2449 T: Lift,
2450{
2451 fn linear_lift_from_flat(
2452 cx: &mut LiftContext<'_>,
2453 ty: InterfaceType,
2454 src: &Self::Lower,
2455 ) -> Result<Self> {
2456 let payload = match ty {
2457 InterfaceType::Option(ty) => cx.types[ty].ty,
2458 _ => bad_type_info(),
2459 };
2460 Ok(match src.A1.get_i32() {
2461 0 => None,
2462 1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2463 _ => bail!("invalid option discriminant"),
2464 })
2465 }
2466
2467 fn linear_lift_from_memory(
2468 cx: &mut LiftContext<'_>,
2469 ty: InterfaceType,
2470 bytes: &[u8],
2471 ) -> Result<Self> {
2472 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2473 let payload_ty = match ty {
2474 InterfaceType::Option(ty) => cx.types[ty].ty,
2475 _ => bad_type_info(),
2476 };
2477 let discrim = bytes[0];
2478 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2479 match discrim {
2480 0 => Ok(None),
2481 1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2482 _ => bail!("invalid option discriminant"),
2483 }
2484 }
2485}
2486
2487#[derive(Clone, Copy)]
2488#[repr(C)]
2489pub struct ResultLower<T: Copy, E: Copy> {
2490 tag: ValRaw,
2491 payload: ResultLowerPayload<T, E>,
2492}
2493
2494#[derive(Clone, Copy)]
2495#[repr(C)]
2496union ResultLowerPayload<T: Copy, E: Copy> {
2497 ok: T,
2498 err: E,
2499}
2500
2501unsafe impl<T, E> ComponentType for Result<T, E>
2502where
2503 T: ComponentType,
2504 E: ComponentType,
2505{
2506 type Lower = ResultLower<T::Lower, E::Lower>;
2507
2508 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2509 const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC || E::MAY_REQUIRE_REALLOC;
2510
2511 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2512 match ty {
2513 InterfaceType::Result(r) => {
2514 let result = &types.types[*r];
2515 match &result.ok {
2516 Some(ty) => T::typecheck(ty, types)?,
2517 None if T::IS_RUST_UNIT_TYPE => {}
2518 None => bail!("expected no `ok` type"),
2519 }
2520 match &result.err {
2521 Some(ty) => E::typecheck(ty, types)?,
2522 None if E::IS_RUST_UNIT_TYPE => {}
2523 None => bail!("expected no `err` type"),
2524 }
2525 Ok(())
2526 }
2527 other => bail!("expected `result` found `{}`", desc(other)),
2528 }
2529 }
2530}
2531
2532pub unsafe fn lower_payload<P, T>(
2545 payload: &mut MaybeUninit<P>,
2546 typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2547 lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2548) -> Result<()> {
2549 let typed = typed_payload(payload);
2550 lower(typed)?;
2551
2552 let typed_len = unsafe { storage_as_slice(typed).len() };
2553 let payload = unsafe { storage_as_slice_mut(payload) };
2554 for slot in payload[typed_len..].iter_mut() {
2555 slot.write(ValRaw::u64(0));
2556 }
2557 Ok(())
2558}
2559
2560unsafe impl<T, E> ComponentVariant for Result<T, E>
2561where
2562 T: ComponentType,
2563 E: ComponentType,
2564{
2565 const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2566}
2567
2568unsafe impl<T, E> Lower for Result<T, E>
2569where
2570 T: Lower,
2571 E: Lower,
2572{
2573 fn linear_lower_to_flat<U>(
2574 &self,
2575 cx: &mut LowerContext<'_, U>,
2576 ty: InterfaceType,
2577 dst: &mut MaybeUninit<Self::Lower>,
2578 ) -> Result<()> {
2579 let (ok, err) = match ty {
2580 InterfaceType::Result(ty) => {
2581 let ty = &cx.types[ty];
2582 (ty.ok, ty.err)
2583 }
2584 _ => bad_type_info(),
2585 };
2586
2587 match self {
2649 Ok(e) => {
2650 map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2651 unsafe {
2652 lower_payload(
2653 map_maybe_uninit!(dst.payload),
2654 |payload| map_maybe_uninit!(payload.ok),
2655 |dst| match ok {
2656 Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2657 None => Ok(()),
2658 },
2659 )
2660 }
2661 }
2662 Err(e) => {
2663 map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2664 unsafe {
2665 lower_payload(
2666 map_maybe_uninit!(dst.payload),
2667 |payload| map_maybe_uninit!(payload.err),
2668 |dst| match err {
2669 Some(err) => e.linear_lower_to_flat(cx, err, dst),
2670 None => Ok(()),
2671 },
2672 )
2673 }
2674 }
2675 }
2676 }
2677
2678 fn linear_lower_to_memory<U>(
2679 &self,
2680 cx: &mut LowerContext<'_, U>,
2681 ty: InterfaceType,
2682 offset: usize,
2683 ) -> Result<()> {
2684 let (ok, err) = match ty {
2685 InterfaceType::Result(ty) => {
2686 let ty = &cx.types[ty];
2687 (ty.ok, ty.err)
2688 }
2689 _ => bad_type_info(),
2690 };
2691 debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2692 let payload_offset = Self::INFO.payload_offset32 as usize;
2693 match self {
2694 Ok(e) => {
2695 cx.get::<1>(offset)[0] = 0;
2696 if let Some(ok) = ok {
2697 e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2698 }
2699 }
2700 Err(e) => {
2701 cx.get::<1>(offset)[0] = 1;
2702 if let Some(err) = err {
2703 e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2704 }
2705 }
2706 }
2707 Ok(())
2708 }
2709}
2710
2711unsafe impl<T, E> Lift for Result<T, E>
2712where
2713 T: Lift,
2714 E: Lift,
2715{
2716 #[inline]
2717 fn linear_lift_from_flat(
2718 cx: &mut LiftContext<'_>,
2719 ty: InterfaceType,
2720 src: &Self::Lower,
2721 ) -> Result<Self> {
2722 let (ok, err) = match ty {
2723 InterfaceType::Result(ty) => {
2724 let ty = &cx.types[ty];
2725 (ty.ok, ty.err)
2726 }
2727 _ => bad_type_info(),
2728 };
2729 Ok(match src.tag.get_i32() {
2749 0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2750 1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2751 _ => bail!("invalid expected discriminant"),
2752 })
2753 }
2754
2755 #[inline]
2756 fn linear_lift_from_memory(
2757 cx: &mut LiftContext<'_>,
2758 ty: InterfaceType,
2759 bytes: &[u8],
2760 ) -> Result<Self> {
2761 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2762 let discrim = bytes[0];
2763 let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2764 let (ok, err) = match ty {
2765 InterfaceType::Result(ty) => {
2766 let ty = &cx.types[ty];
2767 (ty.ok, ty.err)
2768 }
2769 _ => bad_type_info(),
2770 };
2771 match discrim {
2772 0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2773 1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2774 _ => bail!("invalid expected discriminant"),
2775 }
2776 }
2777}
2778
2779fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2780where
2781 T: Lift,
2782{
2783 match ty {
2784 Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2785 None => Ok(empty_lift()),
2786 }
2787}
2788
2789fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2790where
2791 T: Lift,
2792{
2793 match ty {
2794 Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2795 None => Ok(empty_lift()),
2796 }
2797}
2798
2799fn empty_lift<T>() -> T
2800where
2801 T: Lift,
2802{
2803 assert!(T::IS_RUST_UNIT_TYPE);
2804 assert_eq!(mem::size_of::<T>(), 0);
2805 unsafe { MaybeUninit::uninit().assume_init() }
2806}
2807
2808#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2813#[doc(hidden)]
2814#[derive(Clone, Copy)]
2815#[repr(C)]
2816pub struct TupleLower<
2817 T1 = (),
2818 T2 = (),
2819 T3 = (),
2820 T4 = (),
2821 T5 = (),
2822 T6 = (),
2823 T7 = (),
2824 T8 = (),
2825 T9 = (),
2826 T10 = (),
2827 T11 = (),
2828 T12 = (),
2829 T13 = (),
2830 T14 = (),
2831 T15 = (),
2832 T16 = (),
2833 T17 = (),
2834> {
2835 A1: T1,
2837 A2: T2,
2838 A3: T3,
2839 A4: T4,
2840 A5: T5,
2841 A6: T6,
2842 A7: T7,
2843 A8: T8,
2844 A9: T9,
2845 A10: T10,
2846 A11: T11,
2847 A12: T12,
2848 A13: T13,
2849 A14: T14,
2850 A15: T15,
2851 A16: T16,
2852 A17: T17,
2853 _align_tuple_lower0_correctly: [ValRaw; 0],
2854}
2855
2856macro_rules! impl_component_ty_for_tuples {
2857 ($n:tt $($t:ident)*) => {
2858 #[allow(non_snake_case, reason = "macro-generated code")]
2859 unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2860 where $($t: ComponentType),*
2861 {
2862 type Lower = TupleLower<$($t::Lower),*>;
2863
2864 const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2865 $($t::ABI),*
2866 ]);
2867 const MAY_REQUIRE_REALLOC: bool = false $(|| $t::MAY_REQUIRE_REALLOC)*;
2868
2869 const IS_RUST_UNIT_TYPE: bool = {
2870 let mut _is_unit = true;
2871 $(
2872 let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2873 _is_unit = false;
2874 )*
2875 _is_unit
2876 };
2877
2878 fn typecheck(
2879 ty: &InterfaceType,
2880 types: &InstanceType<'_>,
2881 ) -> Result<()> {
2882 typecheck_tuple(ty, types, &[$($t::typecheck),*])
2883 }
2884 }
2885
2886 #[allow(non_snake_case, reason = "macro-generated code")]
2887 unsafe impl<$($t,)*> Lower for ($($t,)*)
2888 where $($t: Lower),*
2889 {
2890 fn linear_lower_to_flat<U>(
2891 &self,
2892 cx: &mut LowerContext<'_, U>,
2893 ty: InterfaceType,
2894 _dst: &mut MaybeUninit<Self::Lower>,
2895 ) -> Result<()> {
2896 let types = match ty {
2897 InterfaceType::Tuple(t) => &cx.types[t].types,
2898 _ => bad_type_info(),
2899 };
2900 let ($($t,)*) = self;
2901 let mut _types = types.iter();
2902 $(
2903 let ty = *_types.next().unwrap_or_else(bad_type_info);
2904 $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2905 )*
2906 Ok(())
2907 }
2908
2909 fn linear_lower_to_memory<U>(
2910 &self,
2911 cx: &mut LowerContext<'_, U>,
2912 ty: InterfaceType,
2913 mut _offset: usize,
2914 ) -> Result<()> {
2915 debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2916 let types = match ty {
2917 InterfaceType::Tuple(t) => &cx.types[t].types,
2918 _ => bad_type_info(),
2919 };
2920 let ($($t,)*) = self;
2921 let mut _types = types.iter();
2922 $(
2923 let ty = *_types.next().unwrap_or_else(bad_type_info);
2924 $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2925 )*
2926 Ok(())
2927 }
2928 }
2929
2930 #[allow(non_snake_case, reason = "macro-generated code")]
2931 unsafe impl<$($t,)*> Lift for ($($t,)*)
2932 where $($t: Lift),*
2933 {
2934 #[inline]
2935 fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
2936 let types = match ty {
2937 InterfaceType::Tuple(t) => &cx.types[t].types,
2938 _ => bad_type_info(),
2939 };
2940 let mut _types = types.iter();
2941 Ok(($(
2942 $t::linear_lift_from_flat(
2943 cx,
2944 *_types.next().unwrap_or_else(bad_type_info),
2945 &_src.$t,
2946 )?,
2947 )*))
2948 }
2949
2950 #[inline]
2951 fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
2952 debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2953 let types = match ty {
2954 InterfaceType::Tuple(t) => &cx.types[t].types,
2955 _ => bad_type_info(),
2956 };
2957 let mut _types = types.iter();
2958 let mut _offset = 0;
2959 $(
2960 let ty = *_types.next().unwrap_or_else(bad_type_info);
2961 let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
2962 )*
2963 Ok(($($t,)*))
2964 }
2965 }
2966
2967 #[allow(non_snake_case, reason = "macro-generated code")]
2968 unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
2969 where $($t: ComponentType),*
2970 {}
2971 };
2972}
2973
2974for_each_function_signature!(impl_component_ty_for_tuples);
2975
2976pub fn desc(ty: &InterfaceType) -> &'static str {
2977 match ty {
2978 InterfaceType::U8 => "u8",
2979 InterfaceType::S8 => "s8",
2980 InterfaceType::U16 => "u16",
2981 InterfaceType::S16 => "s16",
2982 InterfaceType::U32 => "u32",
2983 InterfaceType::S32 => "s32",
2984 InterfaceType::U64 => "u64",
2985 InterfaceType::S64 => "s64",
2986 InterfaceType::Float32 => "f32",
2987 InterfaceType::Float64 => "f64",
2988 InterfaceType::Bool => "bool",
2989 InterfaceType::Char => "char",
2990 InterfaceType::String => "string",
2991 InterfaceType::List(_) => "list",
2992 InterfaceType::Tuple(_) => "tuple",
2993 InterfaceType::Option(_) => "option",
2994 InterfaceType::Result(_) => "result",
2995
2996 InterfaceType::Record(_) => "record",
2997 InterfaceType::Variant(_) => "variant",
2998 InterfaceType::Flags(_) => "flags",
2999 InterfaceType::Enum(_) => "enum",
3000 InterfaceType::Own(_) => "owned resource",
3001 InterfaceType::Borrow(_) => "borrowed resource",
3002 InterfaceType::Future(_) => "future",
3003 InterfaceType::Stream(_) => "stream",
3004 InterfaceType::ErrorContext(_) => "error-context",
3005 InterfaceType::Map(_) => "map",
3006 InterfaceType::FixedLengthList(_) => "list<_, N>",
3007 }
3008}
3009
3010#[cold]
3011#[doc(hidden)]
3012pub fn bad_type_info<T>() -> T {
3013 panic!("bad type information detected");
3017}