use std::{
borrow::Cow,
fmt::{Debug, Display},
panic::UnwindSafe,
};
pub use externalities::{Externalities, ExternalitiesExt};
pub trait CodeExecutor: Sized + Send + Sync + CallInWasm + Clone + 'static {
type Error: Display + Debug + Send + Sync + 'static;
fn call<
R: codec::Codec + PartialEq,
NC: FnOnce() -> Result<R, String> + UnwindSafe,
>(
&self,
ext: &mut dyn Externalities,
runtime_code: &RuntimeCode,
method: &str,
data: &[u8],
use_native: bool,
native_call: Option<NC>,
) -> (Result<crate::NativeOrEncoded<R>, Self::Error>, bool);
}
pub trait FetchRuntimeCode {
fn fetch_runtime_code<'a>(&'a self) -> Option<Cow<'a, [u8]>>;
}
pub struct WrappedRuntimeCode<'a>(pub std::borrow::Cow<'a, [u8]>);
impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> {
fn fetch_runtime_code<'b>(&'b self) -> Option<Cow<'b, [u8]>> {
Some(self.0.as_ref().into())
}
}
pub struct NoneFetchRuntimeCode;
impl FetchRuntimeCode for NoneFetchRuntimeCode {
fn fetch_runtime_code<'a>(&'a self) -> Option<Cow<'a, [u8]>> {
None
}
}
#[derive(Clone)]
pub struct RuntimeCode<'a> {
pub code_fetcher: &'a dyn FetchRuntimeCode,
pub heap_pages: Option<u64>,
pub hash: Vec<u8>,
}
impl<'a> PartialEq for RuntimeCode<'a> {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl<'a> RuntimeCode<'a> {
pub fn empty() -> Self {
Self {
code_fetcher: &NoneFetchRuntimeCode,
hash: Vec::new(),
heap_pages: None,
}
}
}
impl<'a> FetchRuntimeCode for RuntimeCode<'a> {
fn fetch_runtime_code<'b>(&'b self) -> Option<Cow<'b, [u8]>> {
self.code_fetcher.fetch_runtime_code()
}
}
#[derive(Debug)]
pub struct CodeNotFound;
impl std::fmt::Display for CodeNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "the storage entry `:code` doesn't have any code")
}
}
#[derive(Clone, Copy, Debug)]
pub enum MissingHostFunctions {
Allow,
Disallow,
}
impl MissingHostFunctions {
pub fn allowed(self) -> bool {
matches!(self, Self::Allow)
}
}
pub trait CallInWasm: Send + Sync {
fn call_in_wasm(
&self,
wasm_code: &[u8],
code_hash: Option<Vec<u8>>,
method: &str,
call_data: &[u8],
ext: &mut dyn Externalities,
missing_host_functions: MissingHostFunctions,
) -> Result<Vec<u8>, String>;
}
externalities::decl_extension! {
pub struct CallInWasmExt(Box<dyn CallInWasm>);
}
impl CallInWasmExt {
pub fn new<T: CallInWasm + 'static>(inner: T) -> Self {
Self(Box::new(inner))
}
}
externalities::decl_extension! {
pub struct TaskExecutorExt(Box<dyn SpawnNamed>);
}
impl TaskExecutorExt {
pub fn new(spawn_handle: impl SpawnNamed + Send + 'static) -> Self {
Self(Box::new(spawn_handle))
}
}
pub trait RuntimeSpawn: Send {
fn spawn_call(&self, dispatcher_ref: u32, func: u32, payload: Vec<u8>) -> u64;
fn join(&self, handle: u64) -> Vec<u8>;
}
#[cfg(feature = "std")]
externalities::decl_extension! {
pub struct RuntimeSpawnExt(Box<dyn RuntimeSpawn>);
}
#[dyn_clonable::clonable]
pub trait SpawnNamed: Clone + Send + Sync {
fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
}
impl SpawnNamed for Box<dyn SpawnNamed> {
fn spawn_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
(**self).spawn_blocking(name, future)
}
fn spawn(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
(**self).spawn(name, future)
}
}