referrerpolicy=no-referrer-when-downgrade

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 a value into the host by a fat pointer, writing it back after the host call ends.
226///
227/// This casts the value into a `&mut [u8]` and passes a pointer to that byte blob and its length
228/// to the host. Then the host reads that blob and converts it into an owned type and passes it
229/// as a mutable reference to the host function. After the host function finishes the byte blob
230/// is written back into the guest memory.
231///
232/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
233pub 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
276/// Pass a pointer into the host and write to it after the host call ends.
277///
278/// This casts a given type into `&mut [u8]` using `AsMut<[u8]>` and passes a pointer to
279/// that byte slice into the host. The host *doesn't* read from this and instead creates
280/// a default instance of type `T` and passes it as a `&mut T` into the host function
281/// implementation. After the host function finishes this value is then cast into a `&[u8]` using
282/// `AsRef<[u8]>` and written back into the guest memory.
283///
284/// Raw FFI type: `u32` (a pointer)
285pub 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
335/// Pass a `T` into the host using the SCALE codec.
336///
337/// This encodes a `T` into a `Vec<u8>` using the SCALE codec and then
338/// passes a pointer to that byte blob and its length to the host,
339/// which then reads it and decodes back into `T`.
340///
341/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
342pub 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
380/// Pass a `&[T]` into the host using the SCALE codec.
381///
382/// This encodes a `&[T]` into a `Vec<u8>` using the SCALE codec and then
383/// passes a pointer to that byte blob and its length to the host,
384/// which then reads it and decodes back into `Vec<T>` and passes
385/// a reference to that (as `&[T]`) into the host function.
386///
387/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
388pub 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
426/// A trait signifying a primitive type.
427trait 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
439/// Pass `T` through the FFI boundary by first converting it to `U` in the runtime, and then
440/// converting it back to `T` on the host's side.
441///
442/// Raw FFI type: same as `U`'s FFI type
443pub 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
494/// Return `T` through the FFI boundary by first converting it to `U` on the host's side, and then
495/// converting it back to `T` in the runtime.
496///
497/// Raw FFI type: same as `U`'s FFI type
498pub 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
545/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
546///
547/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
548/// using the legacy allocator, copies the slice into the runtime memory, and
549/// returns a pointer to it.
550///
551/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
552///
553/// Ideally use a mutable slice to return data to the guest, for example using
554/// the [`PassPointerAndWrite`] strategy.
555///
556/// Raw FFI type: `u32` (a pointer to the byte blob)
557pub 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		// SAFETY: This memory was allocated by the host allocator with the exact
595		// capacity needed, so it's safe to make a `Vec` out of it.
596		let value = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) };
597
598		// SAFETY: Reading a `[u8; N]` from a `&[u8]` which is at least `N` elements long is safe.
599		let array = unsafe { *(value.as_ptr() as *const [u8; N]) };
600		T::from(array)
601	}
602}
603
604/// (DEPRECATED) Return `T` as a blob of bytes into the runtime.
605///
606/// Uses `T::AsRef<[u8]>` to cast `T` into a `&[u8]`, allocates runtime memory
607/// using the legacy allocator, copies the slice into the runtime memory, and
608/// returns a pointer to it.
609///
610/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
611///
612/// Ideally use a mutable slice to return data to the guest, for example using
613/// the [`PassPointerAndWrite`] strategy.
614///
615/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
616pub 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			// SAFETY: This memory was allocated by the host allocator with the exact
651			// capacity needed, so it's safe to make a `Vec` out of it.
652			unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
653		};
654
655		T::from(vec)
656	}
657}
658
659/// (DEPRECATED) Return `T` into the runtime using the SCALE codec.
660///
661/// Encodes `T` using the SCALE codec, allocates runtime memory using the legacy
662/// allocator, copies the encoded payload into the runtime memory, and returns
663/// a fat pointer to it.
664///
665/// THIS STRATEGY IS DEPRECATED; DO NOT USE FOR NEW HOST FUNCTIONS!
666///
667/// Ideally use a mutable slice to return data to the guest, for example using
668/// the [`PassPointerAndWrite`] strategy.
669///
670/// Raw FFI type: `u64` (a fat pointer; upper 32 bits is the size, lower 32 bits is the pointer)
671pub 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			// SAFETY: This memory was allocated by the host allocator with the exact
698			// capacity needed, so it's safe to make a `Vec` out of it.
699			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}