1use crate::{
22 util::{pack_ptr_and_len, unpack_ptr_and_len},
23 RIType,
24};
25
26#[cfg(not(substrate_runtime))]
27use crate::host::*;
28
29#[cfg(substrate_runtime)]
30use crate::wasm::*;
31
32#[cfg(not(substrate_runtime))]
33use sp_wasm_interface::{FunctionContext, Pointer, Result};
34
35#[cfg(not(substrate_runtime))]
36use alloc::{format, string::String};
37
38use alloc::vec::Vec;
39use core::{any::type_name, marker::PhantomData};
40
41pub struct PassPointerAndReadCopy<T, const N: usize>(PhantomData<(T, [u8; N])>);
52
53impl<T, const N: usize> RIType for PassPointerAndReadCopy<T, N> {
54 type FFIType = u32;
55 type Inner = T;
56}
57
58#[cfg(not(substrate_runtime))]
59impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndReadCopy<T, N>
60where
61 T: From<[u8; N]> + Copy,
62{
63 type Owned = T;
64
65 fn from_ffi_value(
66 context: &mut dyn FunctionContext,
67 arg: Self::FFIType,
68 ) -> Result<Self::Owned> {
69 let mut out = [0; N];
70 context.read_memory_into(Pointer::new(arg), &mut out)?;
71 Ok(T::from(out))
72 }
73
74 #[inline]
75 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
76 *owned
77 }
78}
79
80#[cfg(substrate_runtime)]
81impl<T, const N: usize> IntoFFIValue for PassPointerAndReadCopy<T, N>
82where
83 T: AsRef<[u8]>,
84{
85 type Destructor = ();
86
87 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
88 assert_eq!(value.as_ref().len(), N);
91 (value.as_ref().as_ptr() as u32, ())
92 }
93}
94
95pub struct PassPointerAndRead<T, const N: usize>(PhantomData<(T, [u8; N])>);
106
107impl<'a, T, const N: usize> RIType for PassPointerAndRead<&'a T, N> {
108 type FFIType = u32;
109 type Inner = &'a T;
110}
111
112#[cfg(not(substrate_runtime))]
113impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndRead<&'a T, N>
114where
115 T: From<[u8; N]>,
116{
117 type Owned = T;
118
119 fn from_ffi_value(
120 context: &mut dyn FunctionContext,
121 arg: Self::FFIType,
122 ) -> Result<Self::Owned> {
123 let mut out = [0; N];
124 context.read_memory_into(Pointer::new(arg), &mut out)?;
125 Ok(T::from(out))
126 }
127
128 #[inline]
129 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
130 &*owned
131 }
132}
133
134#[cfg(substrate_runtime)]
135impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndRead<&'a T, N>
136where
137 T: AsRef<[u8]>,
138{
139 type Destructor = ();
140
141 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
142 assert_eq!(value.as_ref().len(), N);
143 (value.as_ref().as_ptr() as u32, ())
144 }
145}
146
147pub struct PassFatPointerAndRead<T>(PhantomData<T>);
155
156impl<T> RIType for PassFatPointerAndRead<T> {
157 type FFIType = u64;
158 type Inner = T;
159}
160
161#[cfg(not(substrate_runtime))]
162impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a [u8]> {
163 type Owned = Vec<u8>;
164
165 fn from_ffi_value(
166 context: &mut dyn FunctionContext,
167 arg: Self::FFIType,
168 ) -> Result<Self::Owned> {
169 let (ptr, len) = unpack_ptr_and_len(arg);
170 context.read_memory(Pointer::new(ptr), len)
171 }
172
173 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
174 &*owned
175 }
176}
177
178#[cfg(not(substrate_runtime))]
179impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<&'a str> {
180 type Owned = String;
181
182 fn from_ffi_value(
183 context: &mut dyn FunctionContext,
184 arg: Self::FFIType,
185 ) -> Result<Self::Owned> {
186 let (ptr, len) = unpack_ptr_and_len(arg);
187 let vec = context.read_memory(Pointer::new(ptr), len)?;
188 String::from_utf8(vec).map_err(|_| "could not parse '&str' when marshalling hostcall's arguments through the FFI boundary: the string is not valid UTF-8".into())
189 }
190
191 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
192 &*owned
193 }
194}
195
196#[cfg(not(substrate_runtime))]
197impl<'a> FromFFIValue<'a> for PassFatPointerAndRead<Vec<u8>> {
198 type Owned = Vec<u8>;
199
200 fn from_ffi_value(
201 context: &mut dyn FunctionContext,
202 arg: Self::FFIType,
203 ) -> Result<Self::Owned> {
204 <PassFatPointerAndRead<&[u8]> as FromFFIValue>::from_ffi_value(context, arg)
205 }
206
207 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
208 core::mem::take(owned)
209 }
210}
211
212#[cfg(substrate_runtime)]
213impl<T> IntoFFIValue for PassFatPointerAndRead<T>
214where
215 T: AsRef<[u8]>,
216{
217 type Destructor = ();
218
219 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
220 let value = value.as_ref();
221 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
222 }
223}
224
225pub struct PassFatPointerAndReadOption<T>(PhantomData<T>);
234
235impl<T> RIType for PassFatPointerAndReadOption<T> {
236 type FFIType = u64;
237 type Inner = Option<T>;
238}
239
240#[cfg(not(substrate_runtime))]
241impl<'a> FromFFIValue<'a> for PassFatPointerAndReadOption<&'a [u8]> {
242 type Owned = Option<Vec<u8>>;
243
244 fn from_ffi_value(
245 context: &mut dyn FunctionContext,
246 arg: Self::FFIType,
247 ) -> Result<Self::Owned> {
248 let (ptr, len) = unpack_ptr_and_len(arg);
249 if ptr == 0 {
250 Ok(None)
251 } else {
252 context.read_memory(Pointer::new(ptr), len).map(Some)
253 }
254 }
255
256 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
257 owned.as_deref()
258 }
259}
260
261#[cfg(substrate_runtime)]
262impl<T> IntoFFIValue for PassFatPointerAndReadOption<T>
263where
264 T: AsRef<[u8]>,
265{
266 type Destructor = ();
267
268 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
269 match value {
270 Some(value) => {
271 let value = value.as_ref();
272 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
273 },
274 None => (pack_ptr_and_len(0, 0), ()),
275 }
276 }
277}
278
279pub struct PassFatPointerAndReadWrite<T>(PhantomData<T>);
288
289impl<T> RIType for PassFatPointerAndReadWrite<T> {
290 type FFIType = u64;
291 type Inner = T;
292}
293
294#[cfg(not(substrate_runtime))]
295impl<'a> FromFFIValue<'a> for PassFatPointerAndReadWrite<&'a mut [u8]> {
296 type Owned = Vec<u8>;
297
298 fn from_ffi_value(
299 context: &mut dyn FunctionContext,
300 arg: Self::FFIType,
301 ) -> Result<Self::Owned> {
302 let (ptr, len) = unpack_ptr_and_len(arg);
303 context.read_memory(Pointer::new(ptr), len)
304 }
305
306 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
307 &mut *owned
308 }
309
310 fn write_back_into_runtime(
311 value: Self::Owned,
312 context: &mut dyn FunctionContext,
313 arg: Self::FFIType,
314 ) -> Result<()> {
315 let (ptr, len) = unpack_ptr_and_len(arg);
316 assert_eq!(len as usize, value.len());
317 context.write_memory(Pointer::new(ptr), &value)
318 }
319}
320
321#[cfg(substrate_runtime)]
322impl<'a> IntoFFIValue for PassFatPointerAndReadWrite<&'a mut [u8]> {
323 type Destructor = ();
324
325 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
326 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
327 }
328}
329
330pub struct PassFatPointerAndWrite<T>(PhantomData<T>);
339
340impl<T> RIType for PassFatPointerAndWrite<T> {
341 type FFIType = u64;
342 type Inner = T;
343}
344
345#[cfg(not(substrate_runtime))]
346impl<'a> FromFFIValue<'a> for PassFatPointerAndWrite<&'a mut [u8]> {
347 type Owned = Vec<u8>;
348
349 fn from_ffi_value(
350 _context: &mut dyn FunctionContext,
351 arg: Self::FFIType,
352 ) -> Result<Self::Owned> {
353 let (_ptr, len) = unpack_ptr_and_len(arg);
354 Ok(alloc::vec![0u8; len as usize])
355 }
356
357 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
358 &mut *owned
359 }
360
361 fn write_back_into_runtime(
362 value: Self::Owned,
363 context: &mut dyn FunctionContext,
364 arg: Self::FFIType,
365 ) -> Result<()> {
366 let (ptr, len) = unpack_ptr_and_len(arg);
367 assert_eq!(len as usize, value.len());
368 context.write_memory(Pointer::new(ptr), &value)
369 }
370}
371
372#[cfg(substrate_runtime)]
373impl<'a> IntoFFIValue for PassFatPointerAndWrite<&'a mut [u8]> {
374 type Destructor = ();
375
376 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
377 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
378 }
379}
380
381pub struct PassPointerAndWrite<T, const N: usize>(PhantomData<(T, [u8; N])>);
391
392impl<T, const N: usize> RIType for PassPointerAndWrite<T, N> {
393 type FFIType = u32;
394 type Inner = T;
395}
396
397#[cfg(not(substrate_runtime))]
398impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndWrite<&'a mut T, N>
399where
400 T: Default + AsRef<[u8]>,
401{
402 type Owned = T;
403
404 fn from_ffi_value(
405 _context: &mut dyn FunctionContext,
406 _arg: Self::FFIType,
407 ) -> Result<Self::Owned> {
408 Ok(T::default())
409 }
410
411 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
412 &mut *owned
413 }
414
415 fn write_back_into_runtime(
416 value: Self::Owned,
417 context: &mut dyn FunctionContext,
418 arg: Self::FFIType,
419 ) -> Result<()> {
420 let value = value.as_ref();
421 assert_eq!(value.len(), N);
422 context.write_memory(Pointer::new(arg), value)
423 }
424}
425
426#[cfg(substrate_runtime)]
427impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N>
428where
429 T: AsMut<[u8]>,
430{
431 type Destructor = ();
432
433 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
434 let value = value.as_mut();
435 assert_eq!(value.len(), N);
436 (value.as_ptr() as u32, ())
437 }
438}
439
440pub struct PassFatPointerAndDecode<T>(PhantomData<T>);
448
449impl<T> RIType for PassFatPointerAndDecode<T> {
450 type FFIType = u64;
451 type Inner = T;
452}
453
454#[cfg(not(substrate_runtime))]
455impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode<T> {
456 type Owned = Option<T>;
457
458 fn from_ffi_value(
459 context: &mut dyn FunctionContext,
460 arg: Self::FFIType,
461 ) -> Result<Self::Owned> {
462 let (ptr, len) = unpack_ptr_and_len(arg);
463 let vec = context.read_memory(Pointer::new(ptr), len)?;
464 T::decode(&mut &vec[..]).map_err(|error| format!(
465 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
466 type_name::<T>())
467 ).map(Some)
468 }
469
470 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
471 owned.take().expect("this is called only once and is never 'None'")
472 }
473}
474
475#[cfg(substrate_runtime)]
476impl<T: codec::Encode> IntoFFIValue for PassFatPointerAndDecode<T> {
477 type Destructor = Vec<u8>;
478
479 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
480 let data = value.encode();
481 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
482 }
483}
484
485pub struct PassFatPointerAndDecodeSlice<T>(PhantomData<T>);
494
495impl<T> RIType for PassFatPointerAndDecodeSlice<T> {
496 type FFIType = u64;
497 type Inner = T;
498}
499
500#[cfg(not(substrate_runtime))]
501impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> {
502 type Owned = Vec<T>;
503
504 fn from_ffi_value(
505 context: &mut dyn FunctionContext,
506 arg: Self::FFIType,
507 ) -> Result<Self::Owned> {
508 let (ptr, len) = unpack_ptr_and_len(arg);
509 let vec = context.read_memory(Pointer::new(ptr), len)?;
510 <Vec::<T> as codec::Decode>::decode(&mut &vec[..]).map_err(|error| format!(
511 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
512 type_name::<Vec<T>>()
513 ))
514 }
515
516 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
517 &*owned
518 }
519}
520
521#[cfg(substrate_runtime)]
522impl<'a, T: codec::Encode> IntoFFIValue for PassFatPointerAndDecodeSlice<&'a [T]> {
523 type Destructor = Vec<u8>;
524
525 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
526 let data = codec::Encode::encode(value);
527 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
528 }
529}
530
531trait Primitive: Copy {}
533
534impl Primitive for u8 {}
535impl Primitive for u16 {}
536impl Primitive for u32 {}
537impl Primitive for u64 {}
538
539impl Primitive for i8 {}
540impl Primitive for i16 {}
541impl Primitive for i32 {}
542impl Primitive for i64 {}
543
544pub struct PassAs<T, U>(PhantomData<(T, U)>);
549
550impl<T, U> RIType for PassAs<T, U>
551where
552 U: RIType,
553{
554 type FFIType = <U as RIType>::FFIType;
555 type Inner = T;
556}
557
558#[cfg(not(substrate_runtime))]
559impl<'a, T, U> FromFFIValue<'a> for PassAs<T, U>
560where
561 U: RIType + FromFFIValue<'a> + Primitive,
562 T: TryFrom<<U as FromFFIValue<'a>>::Owned> + Copy,
563{
564 type Owned = T;
565
566 fn from_ffi_value(
567 context: &mut dyn FunctionContext,
568 arg: Self::FFIType,
569 ) -> Result<Self::Owned> {
570 <U as FromFFIValue>::from_ffi_value(context, arg).and_then(|value| value.try_into()
571 .map_err(|_| format!(
572 "failed to convert '{}' (passed as '{}') into '{}' when marshalling hostcall's arguments through the FFI boundary",
573 type_name::<U>(),
574 type_name::<Self::FFIType>(),
575 type_name::<Self::Owned>()
576 )))
577 }
578
579 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
580 *owned
581 }
582}
583
584#[cfg(substrate_runtime)]
585impl<T, U> IntoFFIValue for PassAs<T, U>
586where
587 U: RIType + IntoFFIValue + Primitive,
588 U::Inner: From<T>,
589 T: Copy,
590{
591 type Destructor = <U as IntoFFIValue>::Destructor;
592
593 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
594 let mut value = U::Inner::from(*value);
595 <U as IntoFFIValue>::into_ffi_value(&mut value)
596 }
597}
598
599pub struct ReturnAs<T, U>(PhantomData<(T, U)>);
604
605impl<T, U> RIType for ReturnAs<T, U>
606where
607 U: RIType,
608{
609 type FFIType = <U as RIType>::FFIType;
610 type Inner = T;
611}
612
613#[cfg(not(substrate_runtime))]
614impl<T, U> IntoFFIValue for ReturnAs<T, U>
615where
616 U: RIType + IntoFFIValue + Primitive,
617 <U as RIType>::Inner: From<Self::Inner>,
618{
619 fn into_ffi_value(
620 value: Self::Inner,
621 context: &mut dyn FunctionContext,
622 ) -> Result<Self::FFIType> {
623 let value: <U as RIType>::Inner = value.into();
624 <U as IntoFFIValue>::into_ffi_value(value, context)
625 }
626}
627
628#[cfg(substrate_runtime)]
629impl<T, U> FromFFIValue for ReturnAs<T, U>
630where
631 U: RIType + FromFFIValue + Primitive,
632 Self::Inner: TryFrom<U::Inner>,
633{
634 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
635 let value = <U as FromFFIValue>::from_ffi_value(arg);
636 match Self::Inner::try_from(value) {
637 Ok(value) => value,
638 Err(_) => {
639 panic!(
640 "failed to convert '{}' (passed as '{}') into a '{}' when marshalling a hostcall's return value through the FFI boundary",
641 type_name::<U::Inner>(),
642 type_name::<Self::FFIType>(),
643 type_name::<Self::Inner>()
644 );
645 },
646 }
647 }
648}
649
650pub struct ConvertAndReturnAs<T, U, V>(PhantomData<(T, U, V)>);
658
659impl<T, U, V> RIType for ConvertAndReturnAs<T, U, V>
660where
661 V: RIType,
662{
663 type FFIType = <V as RIType>::FFIType;
664 type Inner = T;
665}
666
667#[cfg(not(substrate_runtime))]
668impl<T, U, V> IntoFFIValue for ConvertAndReturnAs<T, U, V>
669where
670 V: RIType + IntoFFIValue + Primitive,
671 <V as RIType>::Inner: From<U>,
672 U: From<Self::Inner>,
673{
674 fn into_ffi_value(
675 value: Self::Inner,
676 context: &mut dyn FunctionContext,
677 ) -> Result<Self::FFIType> {
678 let value: U = value.into();
679 let value: <V as RIType>::Inner = value.into();
680 <V as IntoFFIValue>::into_ffi_value(value, context)
681 }
682}
683
684#[cfg(substrate_runtime)]
685impl<T, U, V> FromFFIValue for ConvertAndReturnAs<T, U, V>
686where
687 V: RIType + FromFFIValue + Primitive,
688 U: TryFrom<V::Inner>,
689 Self::Inner: From<U>,
690{
691 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
692 let value = <V as FromFFIValue>::from_ffi_value(arg);
693 let value = match U::try_from(value) {
694 Ok(value) => value,
695 Err(_) => {
696 panic!(
697 "failed to convert '{}' (passed as '{}') into a intermediate type '{}' when marshalling a hostcall's return value through the FFI boundary",
698 type_name::<V::Inner>(),
699 type_name::<Self::FFIType>(),
700 type_name::<U>()
701 );
702 },
703 };
704 value.into()
705 }
706}
707
708pub struct AllocateAndReturnPointer<T, const N: usize>(PhantomData<(T, [u8; N])>);
721
722impl<T, const N: usize> RIType for AllocateAndReturnPointer<T, N> {
723 type FFIType = u32;
724 type Inner = T;
725}
726
727#[cfg(not(substrate_runtime))]
728impl<T, const N: usize> IntoFFIValue for AllocateAndReturnPointer<T, N>
729where
730 T: AsRef<[u8]>,
731{
732 fn into_ffi_value(
733 value: Self::Inner,
734 context: &mut dyn FunctionContext,
735 ) -> Result<Self::FFIType> {
736 let value = value.as_ref();
737 assert_eq!(
738 value.len(),
739 N,
740 "expected the byte blob to be {N} bytes long, is {} bytes when returning '{}' from a host function",
741 value.len(),
742 type_name::<T>()
743 );
744
745 let addr = context.allocate_memory(value.len() as u32)?;
746 context.write_memory(addr, value)?;
747 Ok(addr.into())
748 }
749}
750
751#[cfg(substrate_runtime)]
752impl<T: codec::Decode, const N: usize> FromFFIValue for AllocateAndReturnPointer<T, N>
753where
754 T: From<[u8; N]>,
755{
756 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
757 let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
760
761 let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
763 T::from(array)
764 }
765}
766
767pub struct AllocateAndReturnFatPointer<T>(PhantomData<T>);
780
781impl<T> RIType for AllocateAndReturnFatPointer<T> {
782 type FFIType = u64;
783 type Inner = T;
784}
785
786#[cfg(not(substrate_runtime))]
787impl<T> IntoFFIValue for AllocateAndReturnFatPointer<T>
788where
789 T: AsRef<[u8]>,
790{
791 fn into_ffi_value(
792 value: Self::Inner,
793 context: &mut dyn FunctionContext,
794 ) -> Result<Self::FFIType> {
795 let value = value.as_ref();
796 let ptr = context.allocate_memory(value.len() as u32)?;
797 context.write_memory(ptr, &value)?;
798 Ok(pack_ptr_and_len(ptr.into(), value.len() as u32))
799 }
800}
801
802#[cfg(substrate_runtime)]
803impl<T> FromFFIValue for AllocateAndReturnFatPointer<T>
804where
805 T: From<Vec<u8>>,
806{
807 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
808 let (ptr, len) = unpack_ptr_and_len(arg);
809 let len = len as usize;
810 let vec = if len == 0 {
811 Vec::new()
812 } else {
813 unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
816 };
817
818 T::from(vec)
819 }
820}
821
822pub struct AllocateAndReturnByCodec<T>(PhantomData<T>);
835
836impl<T> RIType for AllocateAndReturnByCodec<T> {
837 type FFIType = u64;
838 type Inner = T;
839}
840
841#[cfg(not(substrate_runtime))]
842impl<T: codec::Encode> IntoFFIValue for AllocateAndReturnByCodec<T> {
843 fn into_ffi_value(value: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
844 let vec = value.encode();
845 let ptr = context.allocate_memory(vec.len() as u32)?;
846 context.write_memory(ptr, &vec)?;
847 Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
848 }
849}
850
851#[cfg(substrate_runtime)]
852impl<T: codec::Decode> FromFFIValue for AllocateAndReturnByCodec<T> {
853 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
854 let (ptr, len) = unpack_ptr_and_len(arg);
855 let len = len as usize;
856
857 let encoded = if len == 0 {
858 bytes::Bytes::new()
859 } else {
860 bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) })
863 };
864
865 match codec::decode_from_bytes(encoded) {
866 Ok(value) => value,
867 Err(error) => {
868 panic!(
869 "failed to decode '{}' when marshalling a hostcall's return value through the FFI boundary: {error}",
870 type_name::<T>(),
871 );
872 },
873 }
874 }
875}