use crate::{contract_def::HasEvents, prelude::*};
use core::cell::OnceCell;
use crate::contract_env::ContractEnv;
use core::ops::{Deref, DerefMut};
pub trait Module {
fn new(env: Rc<ContractEnv>) -> Self;
fn env(&self) -> Rc<ContractEnv>;
}
pub trait ModuleComponent {
fn instance(env: Rc<ContractEnv>, index: u8) -> Self;
}
pub trait Revertible {
fn revert<E: Into<OdraError>>(&self, error: E) -> !;
}
impl Revertible for Rc<ContractEnv> {
fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
self.as_ref().revert(error)
}
}
impl<T: Module> Revertible for T {
fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
self.env().revert(error)
}
}
pub trait ModulePrimitive: ModuleComponent {}
pub struct SubModule<T> {
env: Rc<ContractEnv>,
module: OnceCell<T>,
index: u8
}
impl<T: Module> ModuleComponent for SubModule<T> {
fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
Self {
env,
module: OnceCell::new(),
index
}
}
}
impl<M: ModulePrimitive> HasEvents for M {
fn events() -> Vec<crate::contract_def::Event> {
Vec::new()
}
}
impl<M: HasEvents> HasEvents for SubModule<M> {
fn events() -> Vec<crate::contract_def::Event> {
M::events()
}
fn event_schemas() -> crate::prelude::BTreeMap<String, casper_event_standard::Schema> {
M::event_schemas()
}
}
impl<T: Module> SubModule<T> {
pub fn module(&self) -> &T {
self.module
.get_or_init(|| T::new(Rc::new(self.env.child(self.index))))
}
pub fn module_mut(&mut self) -> &mut T {
if self.module.get().is_none() {
let _ = self.module();
}
self.module.get_mut().unwrap()
}
}
impl<T: Module> Deref for SubModule<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.module()
}
}
impl<T: Module> DerefMut for SubModule<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.module_mut()
}
}