use serde::{Serialize, de::DeserializeOwned};
use tari_bor::{from_value, to_value};
use tari_template_abi::{EngineOp, call_engine, rust::prelude::*};
use tari_template_lib_types::{ComponentAddress, TemplateAddress, access_rules::ComponentAccessRules, bytes::Bytes};
use crate::{
args::{CallAction, CallInvokeArg, CallMethodArg, ComponentAction, ComponentInvokeArg, ComponentRef, InvokeResult},
caller_context::CallerContext,
};
#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct ComponentManager {
address: ComponentAddress,
}
impl ComponentManager {
pub(crate) fn new(address: ComponentAddress) -> Self {
Self { address }
}
pub fn get(address: ComponentAddress) -> Self {
Self { address }
}
pub fn current() -> Self {
Self::new(CallerContext::current_component_address())
}
pub fn call<T: Into<String>, R: DeserializeOwned, B: Into<Bytes>>(&self, method: T, args: Vec<B>) -> R {
self.call_internal(CallMethodArg {
component_address: self.address,
method: method.into(),
args: args.into_iter().map(Into::into).collect(),
})
}
fn call_internal<T: DeserializeOwned>(&self, arg: CallMethodArg) -> T {
let result = call_engine::<_, InvokeResult>(EngineOp::CallInvoke, &CallInvokeArg {
action: CallAction::CallMethod,
args: invoke_args![arg],
});
result
.decode()
.expect("failed to decode component call result from engine")
}
pub fn invoke<T: Into<String>, B: Into<Bytes>>(&self, method: T, args: Vec<B>) {
self.call(method, args)
}
pub fn get_state<T: DeserializeOwned>(&self) -> T {
let result = call_engine::<_, InvokeResult>(EngineOp::ComponentInvoke, &ComponentInvokeArg {
component_ref: ComponentRef::Ref(self.address),
action: ComponentAction::GetState,
args: invoke_args![],
});
let component: tari_bor::Value = result.decode().expect("failed to decode component state from engine");
from_value(&component).expect("Failed to decode component state")
}
pub fn set_state<T: Serialize>(&self, state: T) {
let state = to_value(&state).expect("Failed to encode component state");
let _result = call_engine::<_, InvokeResult>(EngineOp::ComponentInvoke, &ComponentInvokeArg {
component_ref: ComponentRef::Ref(self.address),
action: ComponentAction::SetState,
args: invoke_args![state],
});
}
pub fn set_access_rules(&self, access_rules: ComponentAccessRules) {
call_engine::<_, InvokeResult>(EngineOp::ComponentInvoke, &ComponentInvokeArg {
component_ref: ComponentRef::Ref(self.address),
action: ComponentAction::SetAccessRules,
args: invoke_args![access_rules],
});
}
pub fn get_template_address(&self) -> TemplateAddress {
let result = call_engine::<_, InvokeResult>(EngineOp::ComponentInvoke, &ComponentInvokeArg {
component_ref: ComponentRef::Ref(self.address),
action: ComponentAction::GetTemplateAddress,
args: invoke_args![],
});
result
.decode()
.expect("failed to decode component template address from engine")
}
pub fn component_address(&self) -> ComponentAddress {
self.address
}
}