sp_runtime_interface/
wasm.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//! Traits required by the runtime interface from the wasm side.
19
20use crate::RIType;
21
22use core::cell::Cell;
23
24/// A type used as a return value in a host function. Can be created from an FFI value.
25///
26/// Implementations are safe to assume that the `arg` given to `from_ffi_value`
27/// is only generated by the corresponding [`host::IntoFFIValue`](crate::host::IntoFFIValue)
28/// implementation.
29pub trait FromFFIValue: Sized + RIType {
30	/// Create `Self::Inner` from the given FFI value.
31	fn from_ffi_value(arg: Self::FFIType) -> Self::Inner;
32}
33
34/// A type used as a parameter in a host function. Can be turned into an FFI value.
35pub trait IntoFFIValue: RIType {
36	/// Destructor for the value passed into `into_ffi_value`.
37	type Destructor;
38
39	/// Convert `Self::Inner` into an FFI type, with an optional destructor.
40	fn into_ffi_value(value: &mut Self::Inner) -> (Self::FFIType, Self::Destructor);
41}
42
43/// The state of an exchangeable function.
44#[derive(Clone, Copy)]
45enum ExchangeableFunctionState {
46	/// Original function is present
47	Original,
48	/// The function has been replaced.
49	Replaced,
50}
51
52/// A function which implementation can be exchanged.
53///
54/// Internally this works by swapping function pointers.
55pub struct ExchangeableFunction<T>(Cell<(T, ExchangeableFunctionState)>);
56
57impl<T> ExchangeableFunction<T> {
58	/// Create a new instance of `ExchangeableFunction`.
59	pub const fn new(impl_: T) -> Self {
60		Self(Cell::new((impl_, ExchangeableFunctionState::Original)))
61	}
62}
63
64impl<T: Copy> ExchangeableFunction<T> {
65	/// Replace the implementation with `new_impl`.
66	///
67	/// # Panics
68	///
69	/// Panics when trying to replace an already replaced implementation.
70	///
71	/// # Returns
72	///
73	/// Returns the original implementation wrapped in [`RestoreImplementation`].
74	pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation<T> {
75		if let ExchangeableFunctionState::Replaced = self.0.get().1 {
76			panic!("Trying to replace an already replaced implementation!")
77		}
78
79		let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced));
80
81		RestoreImplementation(self, Some(old.0))
82	}
83
84	/// Restore the original implementation.
85	fn restore_orig_implementation(&self, orig: T) {
86		self.0.set((orig, ExchangeableFunctionState::Original));
87	}
88
89	/// Returns the internal function pointer.
90	pub fn get(&self) -> T {
91		self.0.get().0
92	}
93}
94
95// Wasm does not support threads, so this is safe; qed.
96unsafe impl<T> Sync for ExchangeableFunction<T> {}
97
98/// Restores a function implementation on drop.
99///
100/// Stores a static reference to the function object and the original implementation.
101pub struct RestoreImplementation<T: 'static + Copy>(&'static ExchangeableFunction<T>, Option<T>);
102
103impl<T: Copy> Drop for RestoreImplementation<T> {
104	fn drop(&mut self) {
105		self.0
106			.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed"));
107	}
108}