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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// 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/>.

//! Declares modules, attributes, public re-exports.
//! Gear libs are `#![no_std]`, which makes them lightweight.

//! This module is for configuring `gstd` inside gear programs.
use crate::{
    errors::{Error, Result, UsageError},
    BlockCount,
};

/// Constant declaring default `Config::system_reserve()` in case of not
/// "ethexe" feature.
pub const SYSTEM_RESERVE: u64 = 1_000_000_000;

/// Wait types.
#[derive(Clone, Copy, Default)]
pub(crate) enum WaitType {
    WaitFor,
    #[default]
    WaitUpTo,
}

/// The set of broadly used internal parameters.
///
/// These parameters have various predefined values that the program developer
/// can override.
pub struct Config {
    /// Default wait duration for `wait_up_to` messages expressed in block
    /// count.
    ///
    /// Initial value: **100 blocks**
    pub wait_up_to: BlockCount,

    /// Default wait duration for `wait_for` messages expressed in block count.
    ///
    /// Initial value: **100 blocks**
    pub wait_for: BlockCount,

    /// Default amount of blocks a mutex lock can be owned for by a message.
    ///
    /// Initial value: **100 blocks**
    pub mx_lock_duration: BlockCount,

    /// Default gas amount reserved for system purposes.
    ///
    /// Initial value: **1_000_000_000**
    #[cfg(not(feature = "ethexe"))]
    pub system_reserve: u64,

    pub(crate) wait_type: WaitType,
}

impl Config {
    const fn default() -> Self {
        Self {
            wait_up_to: 100,
            wait_for: 100,
            mx_lock_duration: 100,
            #[cfg(not(feature = "ethexe"))]
            system_reserve: SYSTEM_RESERVE,
            wait_type: WaitType::WaitUpTo,
        }
    }

    pub(crate) fn wait_type() -> WaitType {
        unsafe { CONFIG.wait_type }
    }

    /// Get the `wait_for` duration (in blocks).
    pub fn wait_for() -> BlockCount {
        unsafe { CONFIG.wait_for }
    }

    /// Get the `wait_up_to` duration (in blocks).
    pub fn wait_up_to() -> BlockCount {
        unsafe { CONFIG.wait_up_to }
    }

    /// Get the `mx_lock_duration` duration (in blocks).
    pub fn mx_lock_duration() -> BlockCount {
        unsafe { CONFIG.mx_lock_duration }
    }

    /// Get the `system_reserve` gas amount.
    #[cfg(not(feature = "ethexe"))]
    pub fn system_reserve() -> u64 {
        unsafe { CONFIG.system_reserve }
    }

    /// Set `wait_for` duration (in blocks).
    pub fn set_wait_for(duration: BlockCount) -> Result<()> {
        if duration == 0 {
            return Err(Error::Gstd(UsageError::EmptyWaitDuration));
        }

        unsafe { CONFIG.wait_for = duration };
        Ok(())
    }

    /// Set `wait_for` as the default wait type with duration.
    ///
    /// Calling this function forces all async functions that wait for some
    /// condition to wait exactly for `duration` blocks.
    pub fn set_default_wait_for(duration: BlockCount) -> Result<()> {
        Self::set_wait_for(duration)?;
        unsafe { CONFIG.wait_type = WaitType::WaitFor };

        Ok(())
    }

    /// Set the `wait_up_to` duration (in blocks).
    pub fn set_wait_up_to(duration: BlockCount) -> Result<()> {
        if duration == 0 {
            return Err(Error::Gstd(UsageError::EmptyWaitDuration));
        }

        unsafe { CONFIG.wait_up_to = duration };
        Ok(())
    }

    /// Set `wait_up_to` as the default wait type with duration.
    ///
    /// Calling this function forces all async functions that wait for some
    /// condition to wait not more than `duration` blocks.
    pub fn set_default_wait_up_to(duration: BlockCount) -> Result<()> {
        Self::set_wait_up_to(duration)?;
        unsafe { CONFIG.wait_type = WaitType::WaitUpTo };

        Ok(())
    }

    /// Set `mx_lock_duration_max` duration (in blocks).
    pub fn set_mx_lock_duration(duration: BlockCount) -> Result<()> {
        if duration == 0 {
            return Err(Error::Gstd(UsageError::ZeroMxLockDuration));
        }

        unsafe { CONFIG.mx_lock_duration = duration };
        Ok(())
    }

    /// Set `system_reserve` gas amount.
    #[cfg(not(feature = "ethexe"))]
    pub fn set_system_reserve(amount: u64) -> Result<()> {
        if amount == 0 {
            return Err(Error::Gstd(UsageError::ZeroSystemReservationAmount));
        }

        unsafe { CONFIG.system_reserve = amount };
        Ok(())
    }
}

// Private `gstd` configuration, only could be modified
// with the public interfaces of `Config`.
static mut CONFIG: Config = Config::default();