use serde::{Serialize, de::DeserializeOwned};
use tari_bor::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,
error_variants::ERR_ENGINE_DECODE_FAIL,
models::Proof,
};
#[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(ERR_ENGINE_DECODE_FAIL)
}
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![],
});
result.decode().expect(ERR_ENGINE_DECODE_FAIL)
}
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(ERR_ENGINE_DECODE_FAIL)
}
pub fn get_owner_proof(&self) -> Proof {
let result = call_engine::<_, InvokeResult>(EngineOp::ComponentInvoke, &ComponentInvokeArg {
component_ref: ComponentRef::Ref(self.address),
action: ComponentAction::GetOwnerProof,
args: invoke_args![],
});
result.decode().expect(ERR_ENGINE_DECODE_FAIL)
}
pub fn component_address(&self) -> ComponentAddress {
self.address
}
}