1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::engine::scrypto_env::ScryptoVmV1Api;
use crate::prelude::ScryptoEncode;
use crate::runtime::*;
use crate::*;
use radix_engine_derive::ScryptoSbor;
use radix_engine_interface::api::{AttachedModuleId, ACTOR_REF_SELF};
use radix_engine_interface::data::scrypto::{scrypto_decode, scrypto_encode};
use radix_engine_interface::types::NodeId;
use radix_engine_interface::types::*;
use sbor::rust::marker::PhantomData;
use sbor::rust::ops::Deref;
use sbor::rust::prelude::*;
use scrypto::prelude::ScryptoDecode;

#[derive(Debug, Clone, PartialEq, Eq, Hash, ScryptoSbor)]
pub enum ModuleHandle {
    Own(Own),
    Attached(GlobalAddress, AttachedModuleId),
    SELF(AttachedModuleId),
}

impl ModuleHandle {
    pub fn as_node_id(&self) -> &NodeId {
        match self {
            ModuleHandle::Own(own) => own.as_node_id(),
            ModuleHandle::SELF(..) | ModuleHandle::Attached(..) => panic!("invalid"),
        }
    }
}

pub struct Attached<'a, O>(pub O, pub PhantomData<&'a ()>);

impl<'a, O> Deref for Attached<'a, O> {
    type Target = O;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a, O> Attached<'a, O> {
    pub fn new(o: O) -> Self {
        Attached(o, PhantomData::default())
    }
}

pub trait Attachable: Sized {
    const MODULE_ID: AttachedModuleId;

    fn attached(address: GlobalAddress) -> Self {
        Self::new(ModuleHandle::Attached(address, Self::MODULE_ID))
    }

    fn self_attached() -> Self {
        Self::new(ModuleHandle::SELF(Self::MODULE_ID))
    }

    fn new(handle: ModuleHandle) -> Self;

    fn handle(&self) -> &ModuleHandle;

    fn call<A: ScryptoEncode, T: ScryptoDecode>(&self, method: &str, args: &A) -> T {
        let args = scrypto_encode(args).unwrap();
        scrypto_decode(&self.call_raw(method, args)).unwrap()
    }

    fn call_raw(&self, method: &str, args: Vec<u8>) -> Vec<u8> {
        match self.handle() {
            ModuleHandle::Own(own) => {
                let output = ScryptoVmV1Api::object_call(own.as_node_id(), method, args);
                output
            }
            ModuleHandle::Attached(address, module_id) => {
                let output = ScryptoVmV1Api::object_call_module(
                    address.as_node_id(),
                    module_id.clone(),
                    method,
                    args,
                );
                output
            }
            ModuleHandle::SELF(module_id) => {
                let id = ScryptoVmV1Api::actor_get_object_id(ACTOR_REF_SELF);
                let output = ScryptoVmV1Api::object_call_module(&id, *module_id, method, args);
                output
            }
        }
    }

    fn call_ignore_rtn<A: ScryptoEncode>(&self, method: &str, args: &A) {
        let args = scrypto_encode(args).unwrap();
        match self.handle() {
            ModuleHandle::Own(own) => {
                ScryptoVmV1Api::object_call(own.as_node_id(), method, args);
            }
            ModuleHandle::Attached(address, module_id) => {
                ScryptoVmV1Api::object_call_module(
                    address.as_node_id(),
                    module_id.clone(),
                    method,
                    args,
                );
            }
            ModuleHandle::SELF(module_id) => {
                let id = ScryptoVmV1Api::actor_get_object_id(ACTOR_REF_SELF);
                ScryptoVmV1Api::object_call_module(&id, *module_id, method, args);
            }
        }
    }
}