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 PassFatPointerAndReadWrite<T>(PhantomData<T>);
234
235impl<T> RIType for PassFatPointerAndReadWrite<T> {
236 type FFIType = u64;
237 type Inner = T;
238}
239
240#[cfg(not(substrate_runtime))]
241impl<'a> FromFFIValue<'a> for PassFatPointerAndReadWrite<&'a mut [u8]> {
242 type Owned = 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 context.read_memory(Pointer::new(ptr), len)
250 }
251
252 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
253 &mut *owned
254 }
255
256 fn write_back_into_runtime(
257 value: Self::Owned,
258 context: &mut dyn FunctionContext,
259 arg: Self::FFIType,
260 ) -> Result<()> {
261 let (ptr, len) = unpack_ptr_and_len(arg);
262 assert_eq!(len as usize, value.len());
263 context.write_memory(Pointer::new(ptr), &value)
264 }
265}
266
267#[cfg(substrate_runtime)]
268impl<'a> IntoFFIValue for PassFatPointerAndReadWrite<&'a mut [u8]> {
269 type Destructor = ();
270
271 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
272 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
273 }
274}
275
276pub struct PassFatPointerAndWrite<T>(PhantomData<T>);
285
286impl<T> RIType for PassFatPointerAndWrite<T> {
287 type FFIType = u64;
288 type Inner = T;
289}
290
291#[cfg(not(substrate_runtime))]
292impl<'a> FromFFIValue<'a> for PassFatPointerAndWrite<&'a mut [u8]> {
293 type Owned = Vec<u8>;
294
295 fn from_ffi_value(
296 _context: &mut dyn FunctionContext,
297 arg: Self::FFIType,
298 ) -> Result<Self::Owned> {
299 let (_ptr, len) = unpack_ptr_and_len(arg);
300 Ok(alloc::vec![0u8; len as usize])
301 }
302
303 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
304 &mut *owned
305 }
306
307 fn write_back_into_runtime(
308 value: Self::Owned,
309 context: &mut dyn FunctionContext,
310 arg: Self::FFIType,
311 ) -> Result<()> {
312 let (ptr, len) = unpack_ptr_and_len(arg);
313 assert_eq!(len as usize, value.len());
314 context.write_memory(Pointer::new(ptr), &value)
315 }
316}
317
318#[cfg(substrate_runtime)]
319impl<'a> IntoFFIValue for PassFatPointerAndWrite<&'a mut [u8]> {
320 type Destructor = ();
321
322 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
323 (pack_ptr_and_len(value.as_ptr() as u32, value.len() as u32), ())
324 }
325}
326
327pub struct PassPointerAndWrite<T, const N: usize>(PhantomData<(T, [u8; N])>);
337
338impl<T, const N: usize> RIType for PassPointerAndWrite<T, N> {
339 type FFIType = u32;
340 type Inner = T;
341}
342
343#[cfg(not(substrate_runtime))]
344impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndWrite<&'a mut T, N>
345where
346 T: Default + AsRef<[u8]>,
347{
348 type Owned = T;
349
350 fn from_ffi_value(
351 _context: &mut dyn FunctionContext,
352 _arg: Self::FFIType,
353 ) -> Result<Self::Owned> {
354 Ok(T::default())
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 value = value.as_ref();
367 assert_eq!(value.len(), N);
368 context.write_memory(Pointer::new(arg), value)
369 }
370}
371
372#[cfg(substrate_runtime)]
373impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N>
374where
375 T: AsMut<[u8]>,
376{
377 type Destructor = ();
378
379 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
380 let value = value.as_mut();
381 assert_eq!(value.len(), N);
382 (value.as_ptr() as u32, ())
383 }
384}
385
386pub struct PassFatPointerAndDecode<T>(PhantomData<T>);
394
395impl<T> RIType for PassFatPointerAndDecode<T> {
396 type FFIType = u64;
397 type Inner = T;
398}
399
400#[cfg(not(substrate_runtime))]
401impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode<T> {
402 type Owned = Option<T>;
403
404 fn from_ffi_value(
405 context: &mut dyn FunctionContext,
406 arg: Self::FFIType,
407 ) -> Result<Self::Owned> {
408 let (ptr, len) = unpack_ptr_and_len(arg);
409 let vec = context.read_memory(Pointer::new(ptr), len)?;
410 T::decode(&mut &vec[..]).map_err(|error| format!(
411 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
412 type_name::<T>())
413 ).map(Some)
414 }
415
416 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
417 owned.take().expect("this is called only once and is never 'None'")
418 }
419}
420
421#[cfg(substrate_runtime)]
422impl<T: codec::Encode> IntoFFIValue for PassFatPointerAndDecode<T> {
423 type Destructor = Vec<u8>;
424
425 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
426 let data = value.encode();
427 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
428 }
429}
430
431pub struct PassFatPointerAndDecodeSlice<T>(PhantomData<T>);
440
441impl<T> RIType for PassFatPointerAndDecodeSlice<T> {
442 type FFIType = u64;
443 type Inner = T;
444}
445
446#[cfg(not(substrate_runtime))]
447impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> {
448 type Owned = Vec<T>;
449
450 fn from_ffi_value(
451 context: &mut dyn FunctionContext,
452 arg: Self::FFIType,
453 ) -> Result<Self::Owned> {
454 let (ptr, len) = unpack_ptr_and_len(arg);
455 let vec = context.read_memory(Pointer::new(ptr), len)?;
456 <Vec::<T> as codec::Decode>::decode(&mut &vec[..]).map_err(|error| format!(
457 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
458 type_name::<Vec<T>>()
459 ))
460 }
461
462 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
463 &*owned
464 }
465}
466
467#[cfg(substrate_runtime)]
468impl<'a, T: codec::Encode> IntoFFIValue for PassFatPointerAndDecodeSlice<&'a [T]> {
469 type Destructor = Vec<u8>;
470
471 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
472 let data = codec::Encode::encode(value);
473 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
474 }
475}
476
477trait Primitive: Copy {}
479
480impl Primitive for u8 {}
481impl Primitive for u16 {}
482impl Primitive for u32 {}
483impl Primitive for u64 {}
484
485impl Primitive for i8 {}
486impl Primitive for i16 {}
487impl Primitive for i32 {}
488impl Primitive for i64 {}
489
490pub struct PassAs<T, U>(PhantomData<(T, U)>);
495
496impl<T, U> RIType for PassAs<T, U>
497where
498 U: RIType,
499{
500 type FFIType = <U as RIType>::FFIType;
501 type Inner = T;
502}
503
504#[cfg(not(substrate_runtime))]
505impl<'a, T, U> FromFFIValue<'a> for PassAs<T, U>
506where
507 U: RIType + FromFFIValue<'a> + Primitive,
508 T: TryFrom<<U as FromFFIValue<'a>>::Owned> + Copy,
509{
510 type Owned = T;
511
512 fn from_ffi_value(
513 context: &mut dyn FunctionContext,
514 arg: Self::FFIType,
515 ) -> Result<Self::Owned> {
516 <U as FromFFIValue>::from_ffi_value(context, arg).and_then(|value| value.try_into()
517 .map_err(|_| format!(
518 "failed to convert '{}' (passed as '{}') into '{}' when marshalling hostcall's arguments through the FFI boundary",
519 type_name::<U>(),
520 type_name::<Self::FFIType>(),
521 type_name::<Self::Owned>()
522 )))
523 }
524
525 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
526 *owned
527 }
528}
529
530#[cfg(substrate_runtime)]
531impl<T, U> IntoFFIValue for PassAs<T, U>
532where
533 U: RIType + IntoFFIValue + Primitive,
534 U::Inner: From<T>,
535 T: Copy,
536{
537 type Destructor = <U as IntoFFIValue>::Destructor;
538
539 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
540 let mut value = U::Inner::from(*value);
541 <U as IntoFFIValue>::into_ffi_value(&mut value)
542 }
543}
544
545pub struct ReturnAs<T, U>(PhantomData<(T, U)>);
550
551impl<T, U> RIType for ReturnAs<T, U>
552where
553 U: RIType,
554{
555 type FFIType = <U as RIType>::FFIType;
556 type Inner = T;
557}
558
559#[cfg(not(substrate_runtime))]
560impl<T, U> IntoFFIValue for ReturnAs<T, U>
561where
562 U: RIType + IntoFFIValue + Primitive,
563 <U as RIType>::Inner: From<Self::Inner>,
564{
565 fn into_ffi_value(
566 value: Self::Inner,
567 context: &mut dyn FunctionContext,
568 ) -> Result<Self::FFIType> {
569 let value: <U as RIType>::Inner = value.into();
570 <U as IntoFFIValue>::into_ffi_value(value, context)
571 }
572}
573
574#[cfg(substrate_runtime)]
575impl<T, U> FromFFIValue for ReturnAs<T, U>
576where
577 U: RIType + FromFFIValue + Primitive,
578 Self::Inner: TryFrom<U::Inner>,
579{
580 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
581 let value = <U as FromFFIValue>::from_ffi_value(arg);
582 match Self::Inner::try_from(value) {
583 Ok(value) => value,
584 Err(_) => {
585 panic!(
586 "failed to convert '{}' (passed as '{}') into a '{}' when marshalling a hostcall's return value through the FFI boundary",
587 type_name::<U::Inner>(),
588 type_name::<Self::FFIType>(),
589 type_name::<Self::Inner>()
590 );
591 },
592 }
593 }
594}
595
596pub struct AllocateAndReturnPointer<T, const N: usize>(PhantomData<(T, [u8; N])>);
609
610impl<T, const N: usize> RIType for AllocateAndReturnPointer<T, N> {
611 type FFIType = u32;
612 type Inner = T;
613}
614
615#[cfg(not(substrate_runtime))]
616impl<T, const N: usize> IntoFFIValue for AllocateAndReturnPointer<T, N>
617where
618 T: AsRef<[u8]>,
619{
620 fn into_ffi_value(
621 value: Self::Inner,
622 context: &mut dyn FunctionContext,
623 ) -> Result<Self::FFIType> {
624 let value = value.as_ref();
625 assert_eq!(
626 value.len(),
627 N,
628 "expected the byte blob to be {N} bytes long, is {} bytes when returning '{}' from a host function",
629 value.len(),
630 type_name::<T>()
631 );
632
633 let addr = context.allocate_memory(value.len() as u32)?;
634 context.write_memory(addr, value)?;
635 Ok(addr.into())
636 }
637}
638
639#[cfg(substrate_runtime)]
640impl<T: codec::Decode, const N: usize> FromFFIValue for AllocateAndReturnPointer<T, N>
641where
642 T: From<[u8; N]>,
643{
644 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
645 let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
648
649 let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
651 T::from(array)
652 }
653}
654
655pub struct AllocateAndReturnFatPointer<T>(PhantomData<T>);
668
669impl<T> RIType for AllocateAndReturnFatPointer<T> {
670 type FFIType = u64;
671 type Inner = T;
672}
673
674#[cfg(not(substrate_runtime))]
675impl<T> IntoFFIValue for AllocateAndReturnFatPointer<T>
676where
677 T: AsRef<[u8]>,
678{
679 fn into_ffi_value(
680 value: Self::Inner,
681 context: &mut dyn FunctionContext,
682 ) -> Result<Self::FFIType> {
683 let value = value.as_ref();
684 let ptr = context.allocate_memory(value.len() as u32)?;
685 context.write_memory(ptr, &value)?;
686 Ok(pack_ptr_and_len(ptr.into(), value.len() as u32))
687 }
688}
689
690#[cfg(substrate_runtime)]
691impl<T> FromFFIValue for AllocateAndReturnFatPointer<T>
692where
693 T: From<Vec<u8>>,
694{
695 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
696 let (ptr, len) = unpack_ptr_and_len(arg);
697 let len = len as usize;
698 let vec = if len == 0 {
699 Vec::new()
700 } else {
701 unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
704 };
705
706 T::from(vec)
707 }
708}
709
710pub struct AllocateAndReturnByCodec<T>(PhantomData<T>);
723
724impl<T> RIType for AllocateAndReturnByCodec<T> {
725 type FFIType = u64;
726 type Inner = T;
727}
728
729#[cfg(not(substrate_runtime))]
730impl<T: codec::Encode> IntoFFIValue for AllocateAndReturnByCodec<T> {
731 fn into_ffi_value(value: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
732 let vec = value.encode();
733 let ptr = context.allocate_memory(vec.len() as u32)?;
734 context.write_memory(ptr, &vec)?;
735 Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
736 }
737}
738
739#[cfg(substrate_runtime)]
740impl<T: codec::Decode> FromFFIValue for AllocateAndReturnByCodec<T> {
741 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
742 let (ptr, len) = unpack_ptr_and_len(arg);
743 let len = len as usize;
744
745 let encoded = if len == 0 {
746 bytes::Bytes::new()
747 } else {
748 bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) })
751 };
752
753 match codec::decode_from_bytes(encoded) {
754 Ok(value) => value,
755 Err(error) => {
756 panic!(
757 "failed to decode '{}' when marshalling a hostcall's return value through the FFI boundary: {error}",
758 type_name::<T>(),
759 );
760 },
761 }
762 }
763}