use scale_encode::EncodeAsFields;
use scale_value::{Composite, Value, ValueDef, Variant};
use std::borrow::Cow;
pub trait Payload {
type CallData: EncodeAsFields;
fn pallet_name(&self) -> &str;
fn call_name(&self) -> &str;
fn call_data(&self) -> &Self::CallData;
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
None
}
}
macro_rules! boxed_payload {
($ty:path) => {
impl<T: Payload + ?Sized> Payload for $ty {
type CallData = T::CallData;
fn pallet_name(&self) -> &str {
self.as_ref().pallet_name()
}
fn call_name(&self) -> &str {
self.as_ref().call_name()
}
fn call_data(&self) -> &Self::CallData {
self.as_ref().call_data()
}
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
self.as_ref().validation_details()
}
}
};
}
boxed_payload!(Box<T>);
boxed_payload!(std::sync::Arc<T>);
boxed_payload!(std::rc::Rc<T>);
pub struct ValidationDetails<'a> {
pub pallet_name: &'a str,
pub call_name: &'a str,
pub hash: [u8; 32],
}
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct StaticPayload<CallData> {
pallet_name: Cow<'static, str>,
call_name: Cow<'static, str>,
call_data: CallData,
validation_hash: Option<[u8; 32]>,
}
pub type DynamicPayload<CallData> = StaticPayload<CallData>;
impl<CallData> StaticPayload<CallData> {
pub fn new(
pallet_name: impl Into<String>,
call_name: impl Into<String>,
call_data: CallData,
) -> Self {
StaticPayload {
pallet_name: Cow::Owned(pallet_name.into()),
call_name: Cow::Owned(call_name.into()),
call_data,
validation_hash: None,
}
}
#[doc(hidden)]
pub fn new_static(
pallet_name: &'static str,
call_name: &'static str,
call_data: CallData,
validation_hash: [u8; 32],
) -> Self {
StaticPayload {
pallet_name: Cow::Borrowed(pallet_name),
call_name: Cow::Borrowed(call_name),
call_data,
validation_hash: Some(validation_hash),
}
}
pub fn unvalidated(self) -> Self {
Self {
validation_hash: None,
..self
}
}
pub fn call_data(&self) -> &CallData {
&self.call_data
}
pub fn pallet_name(&self) -> &str {
&self.pallet_name
}
pub fn call_name(&self) -> &str {
&self.call_name
}
}
impl StaticPayload<Composite<()>> {
pub fn into_value(self) -> Value<()> {
let call = Value {
context: (),
value: ValueDef::Variant(Variant {
name: self.call_name.into_owned(),
values: self.call_data,
}),
};
Value::unnamed_variant(self.pallet_name, [call])
}
}
impl<CD: EncodeAsFields> Payload for StaticPayload<CD> {
type CallData = CD;
fn pallet_name(&self) -> &str {
&self.pallet_name
}
fn call_name(&self) -> &str {
&self.call_name
}
fn call_data(&self) -> &Self::CallData {
&self.call_data
}
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
self.validation_hash.map(|hash| ValidationDetails {
pallet_name: &self.pallet_name,
call_name: &self.call_name,
hash,
})
}
}
pub fn dynamic<CallData>(
pallet_name: impl Into<String>,
call_name: impl Into<String>,
call_data: CallData,
) -> DynamicPayload<CallData> {
StaticPayload::new(pallet_name, call_name, call_data)
}