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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// This file is part of Gear.

// Copyright (C) 2021-2024 Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{common::errors::Result, ActorId, MessageId};

/// Provide gas deposit from current message to handle reply message on given
/// message id.
///
/// This message id should be sent within the execution. Once destination actor
/// or system sends reply on it, the gas limit ignores, if the program gave
/// deposit - the only it will be used for execution of `handle_reply`.
///
/// # Examples
///
/// ```
/// use gcore::{exec, msg};
///
/// #[no_mangle]
/// extern "C" fn handle() {
///     let message_id =
///         msg::send(msg::source(), b"Outgoing message", 0).expect("Failed to send message");
///
///     exec::reply_deposit(message_id, 100_000).expect("Failed to deposit reply");
/// }
///
/// #[no_mangle]
/// extern "C" fn handle_reply() {
///     // I will be executed for pre-defined (deposited) 100_000 of gas!
/// }
/// ```
pub fn reply_deposit(message_id: MessageId, amount: u64) -> Result<()> {
    gcore::exec::reply_deposit(message_id.into(), amount).map_err(Into::into)
}

/// Terminate the execution of a program.
///
/// The program and all corresponding data are removed from the storage. It may
/// be called in the `init` method as well. One can consider this function as
/// some analog of `std::process::exit`.
///
/// `inheritor_id` specifies the address to which all available program value
/// should be transferred.
///
/// # Examples
///
/// Terminate the program and transfer the available value to the message
/// sender:
///
/// ```
/// use gstd::{exec, msg};
///
/// #[no_mangle]
/// extern "C" fn handle() {
///     // ...
///     exec::exit(msg::source());
/// }
/// ```
pub fn exit(inheritor_id: ActorId) -> ! {
    gcore::exec::exit(inheritor_id.into())
}

/// Resume previously paused message handling.
///
/// Suppose a message has been paused using the [`crate::exec::wait`] function,
/// it is possible to continue its execution by calling this function.
///
/// `message_id` specifies a particular message to be taken out of the *waiting
/// queue* and put into the *processing queue*.
///
/// # Examples
///
/// ```
/// use gstd::{exec, msg, MessageId};
///
/// static mut MSG_ID: MessageId = MessageId::zero();
///
/// #[no_mangle]
/// extern "C" fn init() {
///     unsafe { MSG_ID = msg::id() };
///     exec::wait();
/// }
///
/// #[no_mangle]
/// extern "C" fn handle() {
///     exec::wake(unsafe { MSG_ID }).expect("Unable to wake");
/// }
/// ```
pub fn wake(message_id: MessageId) -> Result<()> {
    wake_delayed(message_id, 0)
}

/// Same as [`wake`], but executes after the `delay` expressed in block count.
pub fn wake_delayed(message_id: MessageId, delay: u32) -> Result<()> {
    gcore::exec::wake_delayed(message_id.into(), delay).map_err(Into::into)
}

/// Return the identifier of the current program.
///
/// # Examples
///
/// ```
/// use gstd::exec;
///
/// #[no_mangle]
/// extern "C" fn handle() {
///     let whoami = exec::program_id();
/// }
/// ```
pub fn program_id() -> ActorId {
    gcore::exec::program_id().into()
}