odra_core/
module.rs

1//! Module definition and implementation.
2//!
3//! An Odra module is a composition of [ModuleComponent]s (eg. other modules) and [ModulePrimitive]s
4//! ([Var](crate::var::Var), [Mapping](crate::mapping::Mapping), [List](crate::list::List)).
5//!
6//! In order to create a module, you need to create a struct that implements the [Module] trait.
7//! However, most of the time you will want to use `#[odra::module]` macro to generate the module.
8
9use crate::{contract_def::HasEvents, prelude::*};
10use core::cell::OnceCell;
11
12use crate::contract_env::ContractEnv;
13use core::ops::{Deref, DerefMut};
14
15/// Represents a module in the Odra system.
16pub trait Module {
17    /// Creates a new instance of the module with the given contract environment.
18    fn new(env: Rc<ContractEnv>) -> Self;
19
20    /// Returns the [contract environment](ContractEnv) associated with the module.
21    fn env(&self) -> Rc<ContractEnv>;
22}
23
24/// Represents a component that can be a part of a module.
25pub trait ModuleComponent {
26    /// Creates a new instance of the module component.
27    fn instance(env: Rc<ContractEnv>, index: u8) -> Self;
28}
29
30/// Represents a component that can revert the contract execution.
31pub trait Revertible {
32    /// Reverts the contract execution with the given error.
33    fn revert<E: Into<OdraError>>(&self, error: E) -> !;
34}
35
36impl Revertible for Rc<ContractEnv> {
37    fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
38        self.as_ref().revert(error)
39    }
40}
41
42impl<T: Module> Revertible for T {
43    fn revert<E: Into<OdraError>>(&self, error: E) -> ! {
44        self.env().revert(error)
45    }
46}
47
48/// A marker trait for a module component that does not emit events.
49///
50/// This trait allows to implement `HasEvents` for components like Var, List, Mapping,
51/// or any other custom component that does not emit events.
52pub trait ModulePrimitive: ModuleComponent {}
53
54/// A wrapper struct for a module implementing the [Module] trait.
55///
56/// This struct is used to implement an Odra module that is a composition of other modules.
57pub struct SubModule<T> {
58    env: Rc<ContractEnv>,
59    module: OnceCell<T>,
60    index: u8
61}
62
63impl<T: Module> ModuleComponent for SubModule<T> {
64    fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
65        Self {
66            env,
67            module: OnceCell::new(),
68            index
69        }
70    }
71}
72
73impl<M: ModulePrimitive> HasEvents for M {
74    fn events() -> Vec<crate::contract_def::Event> {
75        Vec::new()
76    }
77}
78
79impl<M: HasEvents> HasEvents for SubModule<M> {
80    fn events() -> Vec<crate::contract_def::Event> {
81        M::events()
82    }
83
84    fn event_schemas() -> crate::prelude::BTreeMap<String, casper_event_standard::Schema> {
85        M::event_schemas()
86    }
87}
88
89/// Wrapper for a module implementing the `Module` trait.
90impl<T: Module> SubModule<T> {
91    /// Returns a reference to the module.
92    ///
93    /// If the module is not yet initialized, it will be lazily initialized.
94    pub fn module(&self) -> &T {
95        self.module
96            .get_or_init(|| T::new(Rc::new(self.env.child(self.index))))
97    }
98
99    /// Returns a mutable reference to the module.
100    ///
101    /// If the module is not yet initialized, it will be lazily initialized.
102    pub fn module_mut(&mut self) -> &mut T {
103        if self.module.get().is_none() {
104            let _ = self.module();
105        }
106        self.module.get_mut().unwrap()
107    }
108}
109
110impl<T: Module> Deref for SubModule<T> {
111    type Target = T;
112
113    fn deref(&self) -> &Self::Target {
114        self.module()
115    }
116}
117
118impl<T: Module> DerefMut for SubModule<T> {
119    fn deref_mut(&mut self) -> &mut Self::Target {
120        self.module_mut()
121    }
122}