use tari_template_abi::rust::marker::PhantomData;
use tari_template_lib_types::{ComponentAddress, OwnerRule, access_rules::ComponentAccessRules};
use crate::{
caller_context::CallerContext,
engine,
models::ComponentAddressAllocation,
types::crypto::RistrettoPublicKeyBytes,
};
pub struct ComponentBuilder<T> {
component: T,
owner_rule: OwnerRule,
access_rules: ComponentAccessRules,
address_allocation: Option<ComponentAddressAllocation>,
}
impl<T> ComponentBuilder<T> {
fn new(component: T) -> Self {
Self {
component,
owner_rule: OwnerRule::default(),
access_rules: ComponentAccessRules::new(),
address_allocation: None,
}
}
pub fn with_address_allocation(self, allocation: ComponentAddressAllocation) -> Self {
self.with_address_allocation_opt(Some(allocation))
}
pub fn with_address_allocation_opt(mut self, allocation: Option<ComponentAddressAllocation>) -> Self {
if let Some(allocation) = allocation {
assert!(self.address_allocation.is_none(), "Address allocation already set");
self.address_allocation = Some(allocation);
}
self
}
pub fn with_public_key_address(mut self, public_key: RistrettoPublicKeyBytes) -> Self {
self.address_allocation = Some(CallerContext::allocate_component_address(Some(public_key)));
self
}
pub fn with_owner_rule(mut self, owner_rule: OwnerRule) -> Self {
self.owner_rule = owner_rule;
self
}
pub fn with_access_rules(mut self, access_rules: ComponentAccessRules) -> Self {
self.access_rules = access_rules;
self
}
}
impl<T: serde::Serialize> ComponentBuilder<T> {
pub fn create(self) -> Component<T> {
let address = engine().create_component(
self.component,
self.owner_rule,
self.access_rules,
self.address_allocation,
);
Component::from_address(address)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct Component<T> {
address: ComponentAddress,
#[serde(skip)]
_component: PhantomData<T>,
}
impl<T: serde::Serialize> Component<T> {
#[allow(clippy::new_ret_no_self)]
pub fn new(component: T) -> ComponentBuilder<T> {
ComponentBuilder::new(component)
}
pub fn create(component: T) -> Component<T> {
Self::new(component).create()
}
fn from_address(address: ComponentAddress) -> Self {
Self {
address,
_component: PhantomData,
}
}
pub fn address(&self) -> &ComponentAddress {
&self.address
}
}
#[cfg(test)]
mod tests {
use tari_bor::{decode, encode};
use tari_template_lib_types::ObjectKey;
use super::*;
#[test]
fn it_serializes_as_a_component_address() {
decode::<ComponentAddress>(
&encode(&Component::<u32>::from_address(ComponentAddress::new(
ObjectKey::default(),
)))
.unwrap(),
)
.unwrap();
}
}