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, const IS_RESULT: bool> {
func_id: u32,
#[allow(clippy::type_complexity)]
state: PhantomData<fn() -> (I, O, ErrorCode)>,
}
impl ChainExtensionMethod<(), (), (), false> {
#[inline]
pub fn build(func_id: u32) -> Self {
Self {
func_id,
state: Default::default(),
}
}
}
impl<O, ErrorCode, const IS_RESULT: bool>
ChainExtensionMethod<(), O, ErrorCode, IS_RESULT>
{
#[inline]
pub fn input<I>(self) -> ChainExtensionMethod<I, O, ErrorCode, IS_RESULT>
where
I: scale::Encode,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
}
impl<I, ErrorCode> ChainExtensionMethod<I, (), ErrorCode, false> {
#[inline]
pub fn output<O, const IS_RESULT: bool>(
self,
) -> ChainExtensionMethod<I, O, ErrorCode, IS_RESULT>
where
O: scale::Decode,
{
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
}
impl<I, O, const IS_RESULT: bool> ChainExtensionMethod<I, O, (), IS_RESULT> {
#[inline]
pub fn ignore_error_code(
self,
) -> ChainExtensionMethod<I, O, state::IgnoreErrorCode, IS_RESULT> {
ChainExtensionMethod {
func_id: self.func_id,
state: Default::default(),
}
}
#[inline]
pub fn handle_error_code<ErrorCode>(
self,
) -> ChainExtensionMethod<I, O, state::HandleErrorCode<ErrorCode>, IS_RESULT>
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>,
}
}
impl<I, O, ErrorCode> ChainExtensionMethod<I, O, state::HandleErrorCode<ErrorCode>, true>
where
O: IsResultType,
I: scale::Encode,
<O as IsResultType>::Ok: scale::Decode,
<O as IsResultType>::Err: scale::Decode + From<ErrorCode> + From<scale::Error>,
ErrorCode: FromStatusCode,
{
#[inline]
pub fn call(
self,
input: &I,
) -> Result<<O as IsResultType>::Ok, <O as IsResultType>::Err> {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<
I,
<O as IsResultType>::Ok,
<O as IsResultType>::Err,
ErrorCode,
_,
_,
>(
instance,
self.func_id,
input,
ErrorCode::from_status_code,
|mut output| scale::Decode::decode(&mut output).map_err(Into::into),
)
})
}
}
impl<I, O> ChainExtensionMethod<I, O, state::IgnoreErrorCode, true>
where
O: IsResultType,
I: scale::Encode,
<O as IsResultType>::Ok: scale::Decode,
<O as IsResultType>::Err: scale::Decode + From<scale::Error>,
{
#[inline]
pub fn call(
self,
input: &I,
) -> Result<<O as IsResultType>::Ok, <O as IsResultType>::Err> {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::call_chain_extension::<
I,
<O as IsResultType>::Ok,
<O as IsResultType>::Err,
<O as IsResultType>::Err,
_,
_,
>(
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, O, state::HandleErrorCode<ErrorCode>, false>
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, O, state::IgnoreErrorCode, false>
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")
})
}
}
pub trait IsResultType: private::IsResultTypeSealed {
type Ok;
type Err;
}
impl<T, E> private::IsResultTypeSealed for Result<T, E> {}
impl<T, E> IsResultType for Result<T, E> {
type Ok = T;
type Err = E;
}
mod private {
pub trait IsResultTypeSealed {}
}