use crate::{
backend::EnvBackend,
engine::{
EnvInstance,
OnInstance,
},
};
use core::marker::PhantomData;
pub trait FromStatusCode: Sized {
fn from_status_code(status_code: u32) -> Result<(), Self>;
}
#[derive(Debug)]
pub struct ChainExtensionMethod<I, O, ErrorCode> {
func_id: u32,
#[allow(clippy::type_complexity)]
state: PhantomData<fn() -> (I, O, ErrorCode)>,
}
impl ChainExtensionMethod<(), (), ()> {
#[inline]
pub fn build(func_id: u32) -> Self {
Self {
func_id,
state: Default::default(),
}
}
}
impl<O, ErrorCode> ChainExtensionMethod<(), O, ErrorCode> {
#[inline]
pub fn input<I>(self) -> ChainExtensionMethod<I, O, ErrorCode>
where
I: scale::Encode,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
}
impl<I, ErrorCode> ChainExtensionMethod<I, (), ErrorCode> {
#[inline]
pub fn output_result<T, E>(self) -> ChainExtensionMethod<I, Result<T, E>, ErrorCode>
where
Result<T, E>: scale::Decode,
E: From<scale::Error>,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
#[inline]
pub fn output<O>(self) -> ChainExtensionMethod<I, state::NoResult<O>, ErrorCode>
where
O: scale::Decode,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
}
impl<I, O> ChainExtensionMethod<I, O, ()> {
#[inline]
pub fn ignore_error_code(self) -> ChainExtensionMethod<I, O, state::IgnoreErrorCode> {
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
#[inline]
pub fn handle_error_code<ErrorCode>(
self,
) -> ChainExtensionMethod<I, O, state::HandleErrorCode<ErrorCode>>
where
ErrorCode: FromStatusCode,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
}
pub mod state {
use core::marker::PhantomData;
#[derive(Debug)]
pub enum IgnoreErrorCode {}
#[derive(Debug)]
pub struct HandleErrorCode<T> {
error_code: PhantomData<fn() -> T>,
}
#[derive(Debug)]
pub struct NoResult<T> {
no_result: PhantomData<fn() -> T>,
}
}
impl<I, T, E, ErrorCode>
ChainExtensionMethod<I, Result<T, E>, state::HandleErrorCode<ErrorCode>>
where
I: scale::Encode,
T: scale::Decode,
E: scale::Decode + From<ErrorCode> + From<scale::Error>,
ErrorCode: FromStatusCode,
{
#[inline]
pub fn call(self, input: &I) -> Result<T, E> {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<I, T, E, ErrorCode, _, _>(
instance,
self.func_id,
input,
ErrorCode::from_status_code,
|mut output| scale::Decode::decode(&mut output).map_err(Into::into),
)
})
}
}
impl<I, T, E> ChainExtensionMethod<I, Result<T, E>, state::IgnoreErrorCode>
where
I: scale::Encode,
T: scale::Decode,
E: scale::Decode + From<scale::Error>,
{
#[inline]
pub fn call(self, input: &I) -> Result<T, E> {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<I, T, E, E, _, _>(
instance,
self.func_id,
input,
|_status_code| Ok(()),
|mut output| scale::Decode::decode(&mut output).map_err(Into::into),
)
})
}
}
impl<I, O, ErrorCode>
ChainExtensionMethod<I, state::NoResult<O>, state::HandleErrorCode<ErrorCode>>
where
I: scale::Encode,
O: scale::Decode,
ErrorCode: FromStatusCode,
{
#[inline]
pub fn call(self, input: &I) -> Result<O, ErrorCode> {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<I, O, ErrorCode, ErrorCode, _, _>(
instance,
self.func_id,
input,
ErrorCode::from_status_code,
|mut output| {
let decoded = <O as scale::Decode>::decode(&mut output)
.expect("encountered error while decoding chain extension method call return value");
Ok(decoded)
},
)
})
}
}
impl<I, O> ChainExtensionMethod<I, state::NoResult<O>, state::IgnoreErrorCode>
where
I: scale::Encode,
O: scale::Decode,
{
#[inline]
pub fn call(self, input: &I) -> O {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<I, O, (), (), _, _>(
instance,
self.func_id,
input,
|_status_code| Ok(()),
|mut output| {
let decoded = <O as scale::Decode>::decode(&mut output)
.expect("encountered error while decoding chain extension method call return value");
Ok(decoded)
},
).expect("assume the chain extension method never fails")
})
}
}