subxt_core/runtime_api/
payload.rs1use alloc::borrow::Cow;
9use alloc::borrow::ToOwned;
10use alloc::string::String;
11use alloc::vec::Vec;
12use core::marker::PhantomData;
13use derive_where::derive_where;
14use scale_encode::EncodeAsFields;
15use scale_value::Composite;
16
17use crate::dynamic::DecodedValueThunk;
18use crate::error::MetadataError;
19use crate::Error;
20
21use crate::metadata::{DecodeWithMetadata, Metadata};
22
23pub trait Payload {
44 type ReturnType: DecodeWithMetadata;
48
49 fn trait_name(&self) -> &str;
51
52 fn method_name(&self) -> &str;
54
55 fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error>;
57
58 fn encode_args(&self, metadata: &Metadata) -> Result<Vec<u8>, Error> {
61 let mut v = Vec::new();
62 self.encode_args_to(metadata, &mut v)?;
63 Ok(v)
64 }
65
66 fn validation_hash(&self) -> Option<[u8; 32]> {
68 None
69 }
70}
71
72#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsData)]
78pub struct DefaultPayload<ArgsData, ReturnTy> {
79 trait_name: Cow<'static, str>,
80 method_name: Cow<'static, str>,
81 args_data: ArgsData,
82 validation_hash: Option<[u8; 32]>,
83 _marker: PhantomData<ReturnTy>,
84}
85
86pub type StaticPayload<ArgsData, ReturnTy> = DefaultPayload<ArgsData, ReturnTy>;
88pub type DynamicPayload = DefaultPayload<Composite<()>, DecodedValueThunk>;
90
91impl<ArgsData: EncodeAsFields, ReturnTy: DecodeWithMetadata> Payload
92 for DefaultPayload<ArgsData, ReturnTy>
93{
94 type ReturnType = ReturnTy;
95
96 fn trait_name(&self) -> &str {
97 &self.trait_name
98 }
99
100 fn method_name(&self) -> &str {
101 &self.method_name
102 }
103
104 fn encode_args_to(&self, metadata: &Metadata, out: &mut Vec<u8>) -> Result<(), Error> {
105 let api_method = metadata
106 .runtime_api_trait_by_name_err(&self.trait_name)?
107 .method_by_name(&self.method_name)
108 .ok_or_else(|| MetadataError::RuntimeMethodNotFound((*self.method_name).to_owned()))?;
109 let mut fields = api_method
110 .inputs()
111 .map(|input| scale_encode::Field::named(input.ty, &input.name));
112
113 self.args_data
114 .encode_as_fields_to(&mut fields, metadata.types(), out)?;
115 Ok(())
116 }
117
118 fn validation_hash(&self) -> Option<[u8; 32]> {
119 self.validation_hash
120 }
121}
122
123impl<ReturnTy, ArgsData> DefaultPayload<ArgsData, ReturnTy> {
124 pub fn new(
126 trait_name: impl Into<String>,
127 method_name: impl Into<String>,
128 args_data: ArgsData,
129 ) -> Self {
130 DefaultPayload {
131 trait_name: Cow::Owned(trait_name.into()),
132 method_name: Cow::Owned(method_name.into()),
133 args_data,
134 validation_hash: None,
135 _marker: PhantomData,
136 }
137 }
138
139 #[doc(hidden)]
144 pub fn new_static(
145 trait_name: &'static str,
146 method_name: &'static str,
147 args_data: ArgsData,
148 hash: [u8; 32],
149 ) -> DefaultPayload<ArgsData, ReturnTy> {
150 DefaultPayload {
151 trait_name: Cow::Borrowed(trait_name),
152 method_name: Cow::Borrowed(method_name),
153 args_data,
154 validation_hash: Some(hash),
155 _marker: core::marker::PhantomData,
156 }
157 }
158
159 pub fn unvalidated(self) -> Self {
161 Self {
162 validation_hash: None,
163 ..self
164 }
165 }
166
167 pub fn trait_name(&self) -> &str {
169 &self.trait_name
170 }
171
172 pub fn method_name(&self) -> &str {
174 &self.method_name
175 }
176
177 pub fn args_data(&self) -> &ArgsData {
179 &self.args_data
180 }
181}
182
183pub fn dynamic(
185 trait_name: impl Into<String>,
186 method_name: impl Into<String>,
187 args_data: impl Into<Composite<()>>,
188) -> DynamicPayload {
189 DefaultPayload::new(trait_name, method_name, args_data.into())
190}