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 PassPointerAndWrite<T, const N: usize>(PhantomData<(T, [u8; N])>);
286
287impl<T, const N: usize> RIType for PassPointerAndWrite<T, N> {
288 type FFIType = u32;
289 type Inner = T;
290}
291
292#[cfg(not(substrate_runtime))]
293impl<'a, T, const N: usize> FromFFIValue<'a> for PassPointerAndWrite<&'a mut T, N>
294where
295 T: Default + AsRef<[u8]>,
296{
297 type Owned = T;
298
299 fn from_ffi_value(
300 _context: &mut dyn FunctionContext,
301 _arg: Self::FFIType,
302 ) -> Result<Self::Owned> {
303 Ok(T::default())
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 value = value.as_ref();
316 assert_eq!(value.len(), N);
317 context.write_memory(Pointer::new(arg), value)
318 }
319}
320
321#[cfg(substrate_runtime)]
322impl<'a, T, const N: usize> IntoFFIValue for PassPointerAndWrite<&'a mut T, N>
323where
324 T: AsMut<[u8]>,
325{
326 type Destructor = ();
327
328 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
329 let value = value.as_mut();
330 assert_eq!(value.len(), N);
331 (value.as_ptr() as u32, ())
332 }
333}
334
335pub struct PassFatPointerAndDecode<T>(PhantomData<T>);
343
344impl<T> RIType for PassFatPointerAndDecode<T> {
345 type FFIType = u64;
346 type Inner = T;
347}
348
349#[cfg(not(substrate_runtime))]
350impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecode<T> {
351 type Owned = Option<T>;
352
353 fn from_ffi_value(
354 context: &mut dyn FunctionContext,
355 arg: Self::FFIType,
356 ) -> Result<Self::Owned> {
357 let (ptr, len) = unpack_ptr_and_len(arg);
358 let vec = context.read_memory(Pointer::new(ptr), len)?;
359 T::decode(&mut &vec[..]).map_err(|error| format!(
360 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
361 type_name::<T>())
362 ).map(Some)
363 }
364
365 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
366 owned.take().expect("this is called only once and is never 'None'")
367 }
368}
369
370#[cfg(substrate_runtime)]
371impl<T: codec::Encode> IntoFFIValue for PassFatPointerAndDecode<T> {
372 type Destructor = Vec<u8>;
373
374 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
375 let data = value.encode();
376 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
377 }
378}
379
380pub struct PassFatPointerAndDecodeSlice<T>(PhantomData<T>);
389
390impl<T> RIType for PassFatPointerAndDecodeSlice<T> {
391 type FFIType = u64;
392 type Inner = T;
393}
394
395#[cfg(not(substrate_runtime))]
396impl<'a, T: codec::Decode> FromFFIValue<'a> for PassFatPointerAndDecodeSlice<&'a [T]> {
397 type Owned = Vec<T>;
398
399 fn from_ffi_value(
400 context: &mut dyn FunctionContext,
401 arg: Self::FFIType,
402 ) -> Result<Self::Owned> {
403 let (ptr, len) = unpack_ptr_and_len(arg);
404 let vec = context.read_memory(Pointer::new(ptr), len)?;
405 <Vec::<T> as codec::Decode>::decode(&mut &vec[..]).map_err(|error| format!(
406 "could not SCALE-decode '{}' when marshalling hostcall's arguments through the FFI boundary: {error}",
407 type_name::<Vec<T>>()
408 ))
409 }
410
411 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
412 &*owned
413 }
414}
415
416#[cfg(substrate_runtime)]
417impl<'a, T: codec::Encode> IntoFFIValue for PassFatPointerAndDecodeSlice<&'a [T]> {
418 type Destructor = Vec<u8>;
419
420 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
421 let data = codec::Encode::encode(value);
422 (pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32), data)
423 }
424}
425
426trait Primitive: Copy {}
428
429impl Primitive for u8 {}
430impl Primitive for u16 {}
431impl Primitive for u32 {}
432impl Primitive for u64 {}
433
434impl Primitive for i8 {}
435impl Primitive for i16 {}
436impl Primitive for i32 {}
437impl Primitive for i64 {}
438
439pub struct PassAs<T, U>(PhantomData<(T, U)>);
444
445impl<T, U> RIType for PassAs<T, U>
446where
447 U: RIType,
448{
449 type FFIType = <U as RIType>::FFIType;
450 type Inner = T;
451}
452
453#[cfg(not(substrate_runtime))]
454impl<'a, T, U> FromFFIValue<'a> for PassAs<T, U>
455where
456 U: RIType + FromFFIValue<'a> + Primitive,
457 T: TryFrom<<U as FromFFIValue<'a>>::Owned> + Copy,
458{
459 type Owned = T;
460
461 fn from_ffi_value(
462 context: &mut dyn FunctionContext,
463 arg: Self::FFIType,
464 ) -> Result<Self::Owned> {
465 <U as FromFFIValue>::from_ffi_value(context, arg).and_then(|value| value.try_into()
466 .map_err(|_| format!(
467 "failed to convert '{}' (passed as '{}') into '{}' when marshalling hostcall's arguments through the FFI boundary",
468 type_name::<U>(),
469 type_name::<Self::FFIType>(),
470 type_name::<Self::Owned>()
471 )))
472 }
473
474 fn take_from_owned(owned: &'a mut Self::Owned) -> Self::Inner {
475 *owned
476 }
477}
478
479#[cfg(substrate_runtime)]
480impl<T, U> IntoFFIValue for PassAs<T, U>
481where
482 U: RIType + IntoFFIValue + Primitive,
483 U::Inner: From<T>,
484 T: Copy,
485{
486 type Destructor = <U as IntoFFIValue>::Destructor;
487
488 fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor) {
489 let mut value = U::Inner::from(*value);
490 <U as IntoFFIValue>::into_ffi_value(&mut value)
491 }
492}
493
494pub struct ReturnAs<T, U>(PhantomData<(T, U)>);
499
500impl<T, U> RIType for ReturnAs<T, U>
501where
502 U: RIType,
503{
504 type FFIType = <U as RIType>::FFIType;
505 type Inner = T;
506}
507
508#[cfg(not(substrate_runtime))]
509impl<T, U> IntoFFIValue for ReturnAs<T, U>
510where
511 U: RIType + IntoFFIValue + Primitive,
512 <U as RIType>::Inner: From<Self::Inner>,
513{
514 fn into_ffi_value(
515 value: Self::Inner,
516 context: &mut dyn FunctionContext,
517 ) -> Result<Self::FFIType> {
518 let value: <U as RIType>::Inner = value.into();
519 <U as IntoFFIValue>::into_ffi_value(value, context)
520 }
521}
522
523#[cfg(substrate_runtime)]
524impl<T, U> FromFFIValue for ReturnAs<T, U>
525where
526 U: RIType + FromFFIValue + Primitive,
527 Self::Inner: TryFrom<U::Inner>,
528{
529 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
530 let value = <U as FromFFIValue>::from_ffi_value(arg);
531 match Self::Inner::try_from(value) {
532 Ok(value) => value,
533 Err(_) => {
534 panic!(
535 "failed to convert '{}' (passed as '{}') into a '{}' when marshalling a hostcall's return value through the FFI boundary",
536 type_name::<U::Inner>(),
537 type_name::<Self::FFIType>(),
538 type_name::<Self::Inner>()
539 );
540 },
541 }
542 }
543}
544
545pub struct AllocateAndReturnPointer<T, const N: usize>(PhantomData<(T, [u8; N])>);
558
559impl<T, const N: usize> RIType for AllocateAndReturnPointer<T, N> {
560 type FFIType = u32;
561 type Inner = T;
562}
563
564#[cfg(not(substrate_runtime))]
565impl<T, const N: usize> IntoFFIValue for AllocateAndReturnPointer<T, N>
566where
567 T: AsRef<[u8]>,
568{
569 fn into_ffi_value(
570 value: Self::Inner,
571 context: &mut dyn FunctionContext,
572 ) -> Result<Self::FFIType> {
573 let value = value.as_ref();
574 assert_eq!(
575 value.len(),
576 N,
577 "expected the byte blob to be {N} bytes long, is {} bytes when returning '{}' from a host function",
578 value.len(),
579 type_name::<T>()
580 );
581
582 let addr = context.allocate_memory(value.len() as u32)?;
583 context.write_memory(addr, value)?;
584 Ok(addr.into())
585 }
586}
587
588#[cfg(substrate_runtime)]
589impl<T: codec::Decode, const N: usize> FromFFIValue for AllocateAndReturnPointer<T, N>
590where
591 T: From<[u8; N]>,
592{
593 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
594 let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
597
598 let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
600 T::from(array)
601 }
602}
603
604pub struct AllocateAndReturnFatPointer<T>(PhantomData<T>);
617
618impl<T> RIType for AllocateAndReturnFatPointer<T> {
619 type FFIType = u64;
620 type Inner = T;
621}
622
623#[cfg(not(substrate_runtime))]
624impl<T> IntoFFIValue for AllocateAndReturnFatPointer<T>
625where
626 T: AsRef<[u8]>,
627{
628 fn into_ffi_value(
629 value: Self::Inner,
630 context: &mut dyn FunctionContext,
631 ) -> Result<Self::FFIType> {
632 let value = value.as_ref();
633 let ptr = context.allocate_memory(value.len() as u32)?;
634 context.write_memory(ptr, &value)?;
635 Ok(pack_ptr_and_len(ptr.into(), value.len() as u32))
636 }
637}
638
639#[cfg(substrate_runtime)]
640impl<T> FromFFIValue for AllocateAndReturnFatPointer<T>
641where
642 T: From<Vec<u8>>,
643{
644 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
645 let (ptr, len) = unpack_ptr_and_len(arg);
646 let len = len as usize;
647 let vec = if len == 0 {
648 Vec::new()
649 } else {
650 unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
653 };
654
655 T::from(vec)
656 }
657}
658
659pub struct AllocateAndReturnByCodec<T>(PhantomData<T>);
672
673impl<T> RIType for AllocateAndReturnByCodec<T> {
674 type FFIType = u64;
675 type Inner = T;
676}
677
678#[cfg(not(substrate_runtime))]
679impl<T: codec::Encode> IntoFFIValue for AllocateAndReturnByCodec<T> {
680 fn into_ffi_value(value: T, context: &mut dyn FunctionContext) -> Result<Self::FFIType> {
681 let vec = value.encode();
682 let ptr = context.allocate_memory(vec.len() as u32)?;
683 context.write_memory(ptr, &vec)?;
684 Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
685 }
686}
687
688#[cfg(substrate_runtime)]
689impl<T: codec::Decode> FromFFIValue for AllocateAndReturnByCodec<T> {
690 fn from_ffi_value(arg: Self::FFIType) -> Self::Inner {
691 let (ptr, len) = unpack_ptr_and_len(arg);
692 let len = len as usize;
693
694 let encoded = if len == 0 {
695 bytes::Bytes::new()
696 } else {
697 bytes::Bytes::from(unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) })
700 };
701
702 match codec::decode_from_bytes(encoded) {
703 Ok(value) => value,
704 Err(error) => {
705 panic!(
706 "failed to decode '{}' when marshalling a hostcall's return value through the FFI boundary: {error}",
707 type_name::<T>(),
708 );
709 },
710 }
711 }
712}