sp_runtime_interface/
pass_by.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Provides host <-> runtime FFI marshalling strategy newtype wrappers
19//! for defining runtime interfaces.
20
21use 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
41/// Pass a value into the host by a thin pointer.
42///
43/// This casts the value into a `&[u8]` using `AsRef<[u8]>` and passes a pointer to that byte blob
44/// to the host. Then the host reads `N` bytes from that address into an `[u8; N]`, converts it
45/// into target type using `From<[u8; N]>` and passes it into the host function by a copy.
46///
47/// Use [`PassPointerAndRead`] if you want to have the host function accept a reference type
48/// on the host side or if you'd like to avoid the extra copy.
49///
50/// Raw FFI type: `u32` (a pointer)
51pub 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		// Using an 'assert' instead of a 'T: AsRef<[u8; N]>` bound since a '[u8; N]' *doesn't*
89		// implement it.
90		assert_eq!(value.as_ref().len(), N);
91		(value.as_ref().as_ptr() as u32, ())
92	}
93}
94
95/// Pass a value into the host by a thin pointer.
96///
97/// This casts the value into a `&[u8]` using `AsRef<[u8]>` and passes a pointer to that byte blob
98/// to the host. Then the host reads `N` bytes from that address into an `[u8; N]`, converts it
99/// into target type using `From<[u8; N]>` and passes it into the host function by a reference.
100///
101/// This can only be used with reference types (e.g. `&[u8; 32]`). Use [`PassPointerAndReadCopy`]
102/// if you want to have the host function accept a non-reference type on the host side.
103///
104/// Raw FFI type: `u32` (a pointer)
105pub 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
147/// Pass a value into the host by a fat pointer.
148///
149/// This casts the value into a `&[u8]` and passes a pointer to that byte blob and its length
150/// to the host. Then the host reads that blob and converts it into an owned type and passes it
151/// (either as an owned type or as a reference) to the host function.
152///
153/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
154pub 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
225/// Pass an `Option` of a value into the host by a fat pointer.
226///
227/// Behaves like [`PassFatPointerAndRead`] for the `Some` case, with `None` encoded as the
228/// sentinel fat pointer `(ptr = 0, len = 0)`. This is unambiguous: the runtime side calls
229/// `as_ptr()` on a slice, which is documented never to return null even for empty slices,
230/// so a real `Some(&[])` always carries a non-zero pointer.
231///
232/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
233pub 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
279/// Pass a value into the host by a fat pointer, writing it back after the host call ends.
280///
281/// This casts the value into a `&mut [u8]` and passes a pointer to that byte blob and its length
282/// to the host. Then the host reads that blob and converts it into an owned type and passes it
283/// as a mutable reference to the host function. After the host function finishes the byte blob
284/// is written back into the guest memory.
285///
286/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
287pub 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
330/// Pass a pointer into the host by a fat pointer, writing it back after the host call ends.
331///
332/// This casts the value into a `&mut [u8]` and passes a pointer to that byte blob and its length
333/// to the host. The host *doesn't* read from this and instead creates a zero-initialized buffer
334/// as a mutable reference to the host function. After the host function finishes the byte blob
335/// is written back into the guest memory.
336///
337/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
338pub 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
381/// Pass a pointer into the host and write to it after the host call ends.
382///
383/// This casts a given type into `&mut [u8]` using `AsMut<[u8]>` and passes a pointer to
384/// that byte slice into the host. The host *doesn't* read from this and instead creates
385/// a default instance of type `T` and passes it as a `&mut T` into the host function
386/// implementation. After the host function finishes this value is then cast into a `&[u8]` using
387/// `AsRef<[u8]>` and written back into the guest memory.
388///
389/// Raw FFI type: `u32` (a pointer)
390pub 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
440/// Pass a `T` into the host using the SCALE codec.
441///
442/// This encodes a `T` into a `Vec<u8>` using the SCALE codec and then
443/// passes a pointer to that byte blob and its length to the host,
444/// which then reads it and decodes back into `T`.
445///
446/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
447pub 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
485/// Pass a `&[T]` into the host using the SCALE codec.
486///
487/// This encodes a `&[T]` into a `Vec<u8>` using the SCALE codec and then
488/// passes a pointer to that byte blob and its length to the host,
489/// which then reads it and decodes back into `Vec<T>` and passes
490/// a reference to that (as `&[T]`) into the host function.
491///
492/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
493pub 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
531/// A trait signifying a primitive type.
532trait 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
544/// Pass `T` through the FFI boundary by first converting it to `U` in the runtime, and then
545/// converting it back to `T` on the host's side.
546///
547/// Raw FFI type: same as `U`'s FFI type
548pub 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
599/// Return `T` through the FFI boundary by first converting it to `U` on the host's side, and then
600/// converting it back to `T` in the runtime.
601///
602/// Raw FFI type: same as `U`'s FFI type
603pub 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
650/// Return `T` through the FFI boundary by first converting it to `U` and then to `V` on the
651/// host's side, and then converting it back to `U` and then to `T` in the runtime.
652///
653/// This is useful to pass types when the conversion to/from FFI type cannot be implemented
654/// directly, e.g. because of the orphan rule.
655///
656/// Raw FFI type: same as `V`'s FFI type
657pub 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
708/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
709///
710/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
711/// using the legacy allocator, copies the slice into the runtime memory, and
712/// returns a pointer to it.
713///
714/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
715///
716/// Ideally use a mutable slice to return data to the guest, for example using
717/// the [`PassPointerAndWrite`] strategy.
718///
719/// Raw FFI type: `u32` (a pointer to the byte blob)
720pub 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		// SAFETY: This memory was allocated by the host allocator with the exact
758		// capacity needed, so it's safe to make a `Vec` out of it.
759		let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
760
761		// SAFETY: Reading a `[u8; N]` from a `&[u8]` which is at least `N` elements long is safe.
762		let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
763		T::from(array)
764	}
765}
766
767/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
768///
769/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
770/// using the legacy allocator, copies the slice into the runtime memory, and
771/// returns a pointer to it.
772///
773/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
774///
775/// Ideally use a mutable slice to return data to the guest, for example using
776/// the [`PassPointerAndWrite`] strategy.
777///
778/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
779pub 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			// SAFETY: This memory was allocated by the host allocator with the exact
814			// capacity needed, so it's safe to make a `Vec` out of it.
815			unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
816		};
817
818		T::from(vec)
819	}
820}
821
822/// (DEPRECATED) Return `T` into the runtime using the SCALE codec.
823///
824/// Encodes `T` using the SCALE codec, allocates runtime memory using the legacy
825/// allocator, copies the encoded payload into the runtime memory, and returns
826/// a fat pointer to it.
827///
828/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
829///
830/// Ideally use a mutable slice to return data to the guest, for example using
831/// the [`PassPointerAndWrite`] strategy.
832///
833/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
834pub 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			// SAFETY: This memory was allocated by the host allocator with the exact
861			// capacity needed, so it's safe to make a `Vec` out of it.
862			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}