1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
use crate::{
api::{ErrorApi, ManagedTypeApi},
err_msg,
};
use dharitri_codec::{try_cast_ref, TopDecodeInput};
/// Abstracts away the loading of multi-arguments.
/// Acts as an abstract source for these arguments.
///
/// The main method, `next_arg_input` will provide a decode input,
/// from which any deserializable object can be deserialized.
///
/// Structs implementing this trait are also responsible with
/// error handling, such as:
/// - deserialization errors
/// - insufficient arguments
/// - too many arguments
/// For this reason it also requires the ErrorApi trait.
///
/// There are 2 main scenarios for it:
/// - deserializing endpoint arguments directly from the API
/// - deserializing callback arguments saved to storage, from a call data string
///
pub trait DynArgInput {
type ItemInput: TopDecodeInput;
type ErrorApi: ErrorApi + ManagedTypeApi + Sized;
fn dyn_arg_vm_api(&self) -> Self::ErrorApi;
fn vm_api_cast<CastApi: Clone + 'static>(&self) -> CastApi {
let api = self.dyn_arg_vm_api();
if let Some(cast_api_ref) = try_cast_ref::<Self::ErrorApi, CastApi>(&api) {
cast_api_ref.clone()
} else {
self.dyn_arg_vm_api().signal_error(b"unsupported operation")
}
}
/// Check if there are more arguments that can be loaded.
fn has_next(&self) -> bool;
/// Retrieves an input for deserializing an argument.
/// If the loader is out of arguments, it will crash by itself with an appropriate error,
/// without returning.
/// Use if the next argument is optional, use `has_next` beforehand.
fn next_arg_input(&mut self) -> Self::ItemInput;
/// Called after retrieving all arguments to validate that extra arguments were not provided.
fn assert_no_more_args(&self) {
if self.has_next() {
self.dyn_arg_vm_api()
.signal_error(err_msg::ARG_WRONG_NUMBER);
}
}
/// Consumes all inputs and ignores them.
/// After executing this, assert_no_more_args should not fail.
fn flush_ignore(&mut self) {
while self.has_next() {
let _ = self.next_arg_input();
}
}
}