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/// Something that can be created from a ffi value.
25///
26/// # Safety
27///
28/// It is unsafe behavior to call `Something::into_ffi_value().get()` and take this as input for
29/// `from_ffi_value`. Implementations are safe to assume that the `arg` given to `from_ffi_value`
30/// is only generated by the corresponding [`host::IntoFFIValue`](crate::host::IntoFFIValue)
31/// implementation.
32pub trait FromFFIValue: Sized + RIType {
33	/// Create `Self` from the given ffi value.
34	fn from_ffi_value(arg: Self::FFIType) -> Self;
35}
36
37/// Something that can be converted into a ffi value.
38pub trait IntoFFIValue: RIType {
39	/// The owned rust type that is stored with the ffi value in [`WrappedFFIValue`].
40	///
41	/// If no owned value is required, `()` can be used as a type.
42	type Owned;
43
44	/// Convert `self` into a [`WrappedFFIValue`].
45	fn into_ffi_value(&self) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
46}
47
48/// Represents a wrapped ffi value.
49///
50/// It is either the ffi value itself or the ffi value plus some other owned value. By providing
51/// support for storing another owned value besides the actual ffi value certain performance
52/// optimizations can be applied. For example using the pointer to a `Vec<u8>`, while using the
53/// pointer to a SCALE encoded `Vec<u8>` that is stored in this wrapper for any other `Vec<T>`.
54pub enum WrappedFFIValue<T, O = ()> {
55	Wrapped(T),
56	WrappedAndOwned(T, O),
57}
58
59impl<T: Copy, O> WrappedFFIValue<T, O> {
60	/// Returns the wrapped ffi value.
61	pub fn get(&self) -> T {
62		match self {
63			Self::Wrapped(data) | Self::WrappedAndOwned(data, _) => *data,
64		}
65	}
66}
67
68impl<T, O> From<T> for WrappedFFIValue<T, O> {
69	fn from(val: T) -> Self {
70		WrappedFFIValue::Wrapped(val)
71	}
72}
73
74impl<T, O> From<(T, O)> for WrappedFFIValue<T, O> {
75	fn from(val: (T, O)) -> Self {
76		WrappedFFIValue::WrappedAndOwned(val.0, val.1)
77	}
78}
79
80/// The state of an exchangeable function.
81#[derive(Clone, Copy)]
82enum ExchangeableFunctionState {
83	/// Original function is present
84	Original,
85	/// The function has been replaced.
86	Replaced,
87}
88
89/// A function which implementation can be exchanged.
90///
91/// Internally this works by swapping function pointers.
92pub struct ExchangeableFunction<T>(Cell<(T, ExchangeableFunctionState)>);
93
94impl<T> ExchangeableFunction<T> {
95	/// Create a new instance of `ExchangeableFunction`.
96	pub const fn new(impl_: T) -> Self {
97		Self(Cell::new((impl_, ExchangeableFunctionState::Original)))
98	}
99}
100
101impl<T: Copy> ExchangeableFunction<T> {
102	/// Replace the implementation with `new_impl`.
103	///
104	/// # Panics
105	///
106	/// Panics when trying to replace an already replaced implementation.
107	///
108	/// # Returns
109	///
110	/// Returns the original implementation wrapped in [`RestoreImplementation`].
111	pub fn replace_implementation(&'static self, new_impl: T) -> RestoreImplementation<T> {
112		if let ExchangeableFunctionState::Replaced = self.0.get().1 {
113			panic!("Trying to replace an already replaced implementation!")
114		}
115
116		let old = self.0.replace((new_impl, ExchangeableFunctionState::Replaced));
117
118		RestoreImplementation(self, Some(old.0))
119	}
120
121	/// Restore the original implementation.
122	fn restore_orig_implementation(&self, orig: T) {
123		self.0.set((orig, ExchangeableFunctionState::Original));
124	}
125
126	/// Returns the internal function pointer.
127	pub fn get(&self) -> T {
128		self.0.get().0
129	}
130}
131
132// Wasm does not support threads, so this is safe; qed.
133unsafe impl<T> Sync for ExchangeableFunction<T> {}
134
135/// Restores a function implementation on drop.
136///
137/// Stores a static reference to the function object and the original implementation.
138pub struct RestoreImplementation<T: 'static + Copy>(&'static ExchangeableFunction<T>, Option<T>);
139
140impl<T: Copy> Drop for RestoreImplementation<T> {
141	fn drop(&mut self) {
142		self.0
143			.restore_orig_implementation(self.1.take().expect("Value is only taken on drop; qed"));
144	}
145}