tp_runtime_interface/
impls.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2019-2021 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 implementations for the runtime interface traits.
19
20use crate::{
21	RIType, Pointer, pass_by::{PassBy, Codec, Inner, PassByInner, Enum},
22	util::{unpack_ptr_and_len, pack_ptr_and_len},
23};
24#[cfg(feature = "std")]
25use crate::host::*;
26#[cfg(not(feature = "std"))]
27use crate::wasm::*;
28
29#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
30use static_assertions::assert_eq_size;
31
32#[cfg(feature = "std")]
33use tetcore_wasm_interface::{FunctionContext, Result};
34
35use codec::{Encode, Decode};
36
37use tetcore_std::{any::TypeId, mem, vec::Vec};
38
39#[cfg(feature = "std")]
40use tetcore_std::borrow::Cow;
41
42// Make sure that our assumptions for storing a pointer + its size in `u64` is valid.
43#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
44assert_eq_size!(usize, u32);
45#[cfg(all(not(feature = "std"), not(feature = "disable_target_static_assertions")))]
46assert_eq_size!(*const u8, u32);
47
48/// Implement the traits for the given primitive traits.
49macro_rules! impl_traits_for_primitives {
50	(
51		$(
52			$rty:ty, $fty:ty,
53		)*
54	) => {
55		$(
56			/// The type is passed directly.
57			impl RIType for $rty {
58				type FFIType = $fty;
59			}
60
61			#[cfg(not(feature = "std"))]
62			impl IntoFFIValue for $rty {
63				type Owned = ();
64
65				fn into_ffi_value(&self) -> WrappedFFIValue<$fty> {
66					(*self as $fty).into()
67				}
68			}
69
70			#[cfg(not(feature = "std"))]
71			impl FromFFIValue for $rty {
72				fn from_ffi_value(arg: $fty) -> $rty {
73					arg as $rty
74				}
75			}
76
77			#[cfg(feature = "std")]
78			impl FromFFIValue for $rty {
79				type SelfInstance = $rty;
80
81				fn from_ffi_value(_: &mut dyn FunctionContext, arg: $fty) -> Result<$rty> {
82					Ok(arg as $rty)
83				}
84			}
85
86			#[cfg(feature = "std")]
87			impl IntoFFIValue for $rty {
88				fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<$fty> {
89					Ok(self as $fty)
90				}
91			}
92		)*
93	}
94}
95
96impl_traits_for_primitives! {
97	u8, u8,
98	u16, u16,
99	u32, u32,
100	u64, u64,
101	i8, i8,
102	i16, i16,
103	i32, i32,
104	i64, i64,
105}
106
107/// `bool` is passed as `u8`.
108///
109/// - `1`: true
110/// - `0`: false
111impl RIType for bool {
112	type FFIType = u8;
113}
114
115#[cfg(not(feature = "std"))]
116impl IntoFFIValue for bool {
117	type Owned = ();
118
119	fn into_ffi_value(&self) -> WrappedFFIValue<u8> {
120		if *self { 1 } else { 0 }.into()
121	}
122}
123
124#[cfg(not(feature = "std"))]
125impl FromFFIValue for bool {
126	fn from_ffi_value(arg: u8) -> bool {
127		arg == 1
128	}
129}
130
131#[cfg(feature = "std")]
132impl FromFFIValue for bool {
133	type SelfInstance = bool;
134
135	fn from_ffi_value(_: &mut dyn FunctionContext, arg: u8) -> Result<bool> {
136		Ok(arg == 1)
137	}
138}
139
140#[cfg(feature = "std")]
141impl IntoFFIValue for bool {
142	fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u8> {
143		Ok(if self { 1 } else { 0 })
144	}
145}
146
147/// The type is passed as `u64`.
148///
149/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
150///
151/// If `T == u8` the length and the pointer are taken directly from `Self`.
152/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector.
153impl<T> RIType for Vec<T> {
154	type FFIType = u64;
155}
156
157#[cfg(feature = "std")]
158impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
159	fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u64> {
160		let vec: Cow<'_, [u8]> = if TypeId::of::<T>() == TypeId::of::<u8>() {
161			unsafe { Cow::Borrowed(mem::transmute(&self[..])) }
162		} else {
163			Cow::Owned(self.encode())
164		};
165
166		let ptr = context.allocate_memory(vec.as_ref().len() as u32)?;
167		context.write_memory(ptr, &vec)?;
168
169		Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
170	}
171}
172
173#[cfg(feature = "std")]
174impl<T: 'static + Decode> FromFFIValue for Vec<T> {
175	type SelfInstance = Vec<T>;
176
177	fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
178		<[T] as FromFFIValue>::from_ffi_value(context, arg)
179	}
180}
181
182#[cfg(not(feature = "std"))]
183impl<T: 'static + Encode> IntoFFIValue for Vec<T> {
184	type Owned = Vec<u8>;
185
186	fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
187		self[..].into_ffi_value()
188	}
189}
190
191#[cfg(not(feature = "std"))]
192impl<T: 'static + Decode> FromFFIValue for Vec<T> {
193	fn from_ffi_value(arg: u64) -> Vec<T> {
194		let (ptr, len) = unpack_ptr_and_len(arg);
195		let len = len as usize;
196
197		if len == 0 {
198			return Vec::new();
199		}
200
201		let data = unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) };
202
203		if TypeId::of::<T>() == TypeId::of::<u8>() {
204			unsafe { mem::transmute(data) }
205		} else {
206			Self::decode(&mut &data[..]).expect("Host to wasm values are encoded correctly; qed")
207		}
208	}
209}
210
211/// The type is passed as `u64`.
212///
213/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
214///
215/// If `T == u8` the length and the pointer are taken directly from `Self`.
216/// Otherwise `Self` is encoded and the length and the pointer are taken from the encoded vector.
217impl<T> RIType for [T] {
218	type FFIType = u64;
219}
220
221#[cfg(feature = "std")]
222impl<T: 'static + Decode> FromFFIValue for [T] {
223	type SelfInstance = Vec<T>;
224
225	fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<Vec<T>> {
226		let (ptr, len) = unpack_ptr_and_len(arg);
227
228		let vec = context.read_memory(Pointer::new(ptr), len)?;
229
230		if TypeId::of::<T>() == TypeId::of::<u8>() {
231			Ok(unsafe { mem::transmute(vec) })
232		} else {
233			Ok(Vec::<T>::decode(&mut &vec[..]).expect("Wasm to host values are encoded correctly; qed"))
234		}
235	}
236}
237
238#[cfg(feature = "std")]
239impl IntoPreallocatedFFIValue for [u8] {
240	type SelfInstance = Vec<u8>;
241
242	fn into_preallocated_ffi_value(
243		self_instance: Self::SelfInstance,
244		context: &mut dyn FunctionContext,
245		allocated: u64,
246	) -> Result<()> {
247		let (ptr, len) = unpack_ptr_and_len(allocated);
248
249		if (len as usize) < self_instance.len() {
250			Err(
251				format!(
252					"Preallocated buffer is not big enough (given {} vs needed {})!",
253					len,
254					self_instance.len()
255				)
256			)
257		} else {
258			context.write_memory(Pointer::new(ptr), &self_instance)
259		}
260	}
261}
262
263#[cfg(not(feature = "std"))]
264impl<T: 'static + Encode> IntoFFIValue for [T] {
265	type Owned = Vec<u8>;
266
267	fn into_ffi_value(&self) -> WrappedFFIValue<u64, Vec<u8>> {
268		if TypeId::of::<T>() == TypeId::of::<u8>() {
269			let slice = unsafe { mem::transmute::<&[T], &[u8]>(self) };
270			pack_ptr_and_len(slice.as_ptr() as u32, slice.len() as u32).into()
271		} else {
272			let data = self.encode();
273			let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32);
274			(ffi_value, data).into()
275		}
276	}
277}
278
279/// Implement the traits for the `[u8; N]` arrays, where `N` is the input to this macro.
280macro_rules! impl_traits_for_arrays {
281	(
282		$(
283			$n:expr
284		),*
285		$(,)?
286	) => {
287		$(
288			/// The type is passed as `u32`.
289			///
290			/// The `u32` is the pointer to the array.
291			impl RIType for [u8; $n] {
292				type FFIType = u32;
293			}
294
295			#[cfg(not(feature = "std"))]
296			impl IntoFFIValue for [u8; $n] {
297				type Owned = ();
298
299				fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
300					(self.as_ptr() as u32).into()
301				}
302			}
303
304			#[cfg(not(feature = "std"))]
305			impl FromFFIValue for [u8; $n] {
306				fn from_ffi_value(arg: u32) -> [u8; $n] {
307					let mut res = [0u8; $n];
308					let data = unsafe { Vec::from_raw_parts(arg as *mut u8, $n, $n) };
309
310					res.copy_from_slice(&data);
311
312					res
313				}
314			}
315
316			#[cfg(feature = "std")]
317			impl FromFFIValue for [u8; $n] {
318				type SelfInstance = [u8; $n];
319
320				fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> {
321					let data = context.read_memory(Pointer::new(arg), $n)?;
322					let mut res = [0u8; $n];
323					res.copy_from_slice(&data);
324					Ok(res)
325				}
326			}
327
328			#[cfg(feature = "std")]
329			impl IntoFFIValue for [u8; $n] {
330				fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u32> {
331					let addr = context.allocate_memory($n)?;
332					context.write_memory(addr, &self)?;
333					Ok(addr.into())
334				}
335			}
336
337			#[cfg(feature = "std")]
338			impl IntoPreallocatedFFIValue for [u8; $n] {
339				type SelfInstance = [u8; $n];
340
341				fn into_preallocated_ffi_value(
342					self_instance: Self::SelfInstance,
343					context: &mut dyn FunctionContext,
344					allocated: u32,
345				) -> Result<()> {
346					context.write_memory(Pointer::new(allocated), &self_instance)
347				}
348			}
349		)*
350	}
351}
352
353impl_traits_for_arrays! {
354	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
355	27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
356	51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
357	75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
358}
359
360impl<T: codec::Codec, E: codec::Codec> PassBy for tetcore_std::result::Result<T, E> {
361	type PassBy = Codec<Self>;
362}
363
364impl<T: codec::Codec> PassBy for Option<T> {
365	type PassBy = Codec<Self>;
366}
367
368#[impl_trait_for_tuples::impl_for_tuples(30)]
369#[tuple_types_no_default_trait_bound]
370impl PassBy for Tuple where Self: codec::Codec {
371	type PassBy = Codec<Self>;
372}
373
374/// Implement `PassBy` with `Inner` for the given fixed sized hash types.
375macro_rules! for_primitive_types {
376	{ $( $hash:ident $n:expr ),* $(,)? } => {
377		$(
378			impl PassBy for tetsy_primitive_types::$hash {
379				type PassBy = Inner<Self, [u8; $n]>;
380			}
381
382			impl PassByInner for tetsy_primitive_types::$hash {
383				type Inner = [u8; $n];
384
385				fn inner(&self) -> &Self::Inner {
386					&self.0
387				}
388
389				fn into_inner(self) -> Self::Inner {
390					self.0
391				}
392
393				fn from_inner(inner: Self::Inner) -> Self {
394					Self(inner)
395				}
396			}
397		)*
398	}
399}
400
401for_primitive_types! {
402	H160 20,
403	H256 32,
404	H512 64,
405}
406
407/// The type is passed as `u64`.
408///
409/// The `u64` value is build by `length 32bit << 32 | pointer 32bit`
410///
411/// The length and the pointer are taken directly from `Self`.
412impl RIType for str {
413	type FFIType = u64;
414}
415
416#[cfg(feature = "std")]
417impl FromFFIValue for str {
418	type SelfInstance = String;
419
420	fn from_ffi_value(context: &mut dyn FunctionContext, arg: u64) -> Result<String> {
421		let (ptr, len) = unpack_ptr_and_len(arg);
422
423		let vec = context.read_memory(Pointer::new(ptr), len)?;
424
425		// The data is valid utf8, as it is stored as `&str` in wasm.
426		String::from_utf8(vec).map_err(|_| "Invalid utf8 data provided".into())
427	}
428}
429
430#[cfg(not(feature = "std"))]
431impl IntoFFIValue for str {
432	type Owned = ();
433
434	fn into_ffi_value(&self) -> WrappedFFIValue<u64, ()> {
435		let bytes = self.as_bytes();
436		pack_ptr_and_len(bytes.as_ptr() as u32, bytes.len() as u32).into()
437	}
438}
439
440#[cfg(feature = "std")]
441impl<T: tetcore_wasm_interface::PointerType> RIType for Pointer<T> {
442	type FFIType = u32;
443}
444
445/// The type is passed as `u32`.
446#[cfg(not(feature = "std"))]
447impl<T> RIType for Pointer<T> {
448	type FFIType = u32;
449}
450
451#[cfg(not(feature = "std"))]
452impl<T> IntoFFIValue for Pointer<T> {
453	type Owned = ();
454
455	fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
456		(*self as u32).into()
457	}
458}
459
460#[cfg(not(feature = "std"))]
461impl<T> FromFFIValue for Pointer<T> {
462	fn from_ffi_value(arg: u32) -> Self {
463		arg as _
464	}
465}
466
467#[cfg(feature = "std")]
468impl<T: tetcore_wasm_interface::PointerType> FromFFIValue for Pointer<T> {
469	type SelfInstance = Self;
470
471	fn from_ffi_value(_: &mut dyn FunctionContext, arg: u32) -> Result<Self> {
472		Ok(Pointer::new(arg))
473	}
474}
475
476#[cfg(feature = "std")]
477impl<T: tetcore_wasm_interface::PointerType> IntoFFIValue for Pointer<T> {
478	fn into_ffi_value(self, _: &mut dyn FunctionContext) -> Result<u32> {
479		Ok(self.into())
480	}
481}
482
483/// Implement the traits for `u128`/`i128`
484macro_rules! for_u128_i128 {
485	($type:ty) => {
486		/// `u128`/`i128` is passed as `u32`.
487		///
488		/// The `u32` is a pointer to an `[u8; 16]` array.
489		impl RIType for $type {
490			type FFIType = u32;
491		}
492
493		#[cfg(not(feature = "std"))]
494		impl IntoFFIValue for $type {
495			type Owned = ();
496
497			fn into_ffi_value(&self) -> WrappedFFIValue<u32> {
498				unsafe { (mem::transmute::<&Self, *const u8>(self) as u32).into() }
499			}
500		}
501
502		#[cfg(not(feature = "std"))]
503		impl FromFFIValue for $type {
504			fn from_ffi_value(arg: u32) -> $type {
505				<$type>::from_le_bytes(<[u8; mem::size_of::<$type>()]>::from_ffi_value(arg))
506			}
507		}
508
509		#[cfg(feature = "std")]
510		impl FromFFIValue for $type {
511			type SelfInstance = $type;
512
513			fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<$type> {
514				let data = context.read_memory(Pointer::new(arg), mem::size_of::<$type>() as u32)?;
515				let mut res = [0u8; mem::size_of::<$type>()];
516				res.copy_from_slice(&data);
517				Ok(<$type>::from_le_bytes(res))
518			}
519		}
520
521		#[cfg(feature = "std")]
522		impl IntoFFIValue for $type {
523			fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result<u32> {
524				let addr = context.allocate_memory(mem::size_of::<$type>() as u32)?;
525				context.write_memory(addr, &self.to_le_bytes())?;
526				Ok(addr.into())
527			}
528		}
529	}
530}
531
532for_u128_i128!(u128);
533for_u128_i128!(i128);
534
535impl PassBy for tetcore_wasm_interface::ValueType {
536	type PassBy = Enum<tetcore_wasm_interface::ValueType>;
537}
538
539impl PassBy for tetcore_wasm_interface::Value {
540	type PassBy = Codec<tetcore_wasm_interface::Value>;
541}
542
543impl PassBy for tetcore_storage::TrackedStorageKey {
544	type PassBy = Codec<Self>;
545}