near_primitives_core/gas.rs
1use crate::errors::IntegerOverflowError;
2use near_gas::NearGas;
3
4/// Wrapper type over [`near_gas::NearGas`], which itself is a wrapper type over u64.
5///
6/// This wrapper exists to maintain JSON RPC compatibility. While [`NearGas`]
7/// serializes to a JSON string for precision, we need to continue serializing
8/// Gas values to JSON numbers for backward compatibility with existing clients.
9///
10/// Note: [`NearGas`] deserialization already handles both JSON numbers and JSON
11/// strings, so we don't need to redefine deserialization behavior here.
12#[derive(
13 borsh::BorshDeserialize,
14 borsh::BorshSerialize,
15 derive_more::Display,
16 derive_more::FromStr,
17 serde::Deserialize,
18 Clone,
19 Copy,
20 PartialEq,
21 Eq,
22 PartialOrd,
23 Ord,
24 Default,
25 Hash,
26)]
27#[repr(transparent)]
28pub struct Gas(NearGas);
29
30impl Gas {
31 /// Maximum value for Gas (u64::MAX)
32 pub const MAX: Gas = Gas::from_gas(u64::MAX);
33 /// Zero value for Gas
34 pub const ZERO: Gas = Gas::from_gas(0);
35
36 /// Creates a new `Gas` from the specified number of whole tera Gas.
37 ///
38 /// # Examples
39 /// ```
40 /// use near_primitives_core::gas::Gas;
41 ///
42 /// let tera_gas = Gas::from_teragas(5);
43 ///
44 /// assert_eq!(tera_gas.as_gas(), 5 * 1_000_000_000_000);
45 /// ```
46 pub const fn from_teragas(inner: u64) -> Self {
47 Self(NearGas::from_tgas(inner))
48 }
49
50 /// Creates a new `Gas` from the specified number of whole giga Gas.
51 ///
52 /// # Examples
53 /// ```
54 /// use near_primitives_core::gas::Gas;
55 ///
56 /// let giga_gas = Gas::from_gigagas(5);
57 ///
58 /// assert_eq!(giga_gas.as_gas(), 5 * 1_000_000_000);
59 /// ```
60 pub const fn from_gigagas(inner: u64) -> Self {
61 Self(NearGas::from_ggas(inner))
62 }
63
64 /// Creates a new `Gas` from the specified number of whole Gas.
65 ///
66 /// # Examples
67 /// ```
68 /// use near_primitives_core::gas::Gas;
69 ///
70 /// let gas = Gas::from_gas(5 * 1_000_000_000_000);
71 ///
72 /// assert_eq!(gas.as_teragas(), 5);
73 /// ```
74 pub const fn from_gas(inner: u64) -> Self {
75 Self(NearGas::from_gas(inner))
76 }
77
78 /// Returns the total number of whole Gas contained by this `Gas`.
79 ///
80 /// # Examples
81 /// ```
82 /// use near_primitives_core::gas::Gas;
83 ///
84 /// let gas = Gas::from_gas(12345);
85 /// assert_eq!(gas.as_gas(), 12345);
86 /// ```
87 pub const fn as_gas(self) -> u64 {
88 self.0.as_gas()
89 }
90
91 /// Returns the total number of a whole part of giga Gas contained by this `Gas`.
92 ///
93 /// # Examples
94 /// ```
95 /// use near_primitives_core::gas::Gas;
96 ///
97 /// let gas = Gas::from_gigagas(1);
98 /// assert_eq!(gas.as_gigagas(), 1);
99 /// ```
100 pub const fn as_gigagas(self) -> u64 {
101 self.0.as_ggas()
102 }
103
104 /// Returns the total number of a whole part of tera Gas contained by this `Gas`.
105 ///
106 /// # Examples
107 /// ```
108 /// use near_primitives_core::gas::Gas;
109 ///
110 /// let gas = Gas::from_gas(1 * 1_000_000_000_000);
111 /// assert_eq!(gas.as_teragas(), 1);
112 /// ```
113 pub const fn as_teragas(self) -> u64 {
114 self.0.as_tgas()
115 }
116
117 /// Checked integer addition. Computes self + rhs, returning None if overflow occurred.
118 ///
119 /// # Examples
120 /// ```
121 /// use near_primitives_core::gas::Gas;
122 ///
123 /// assert_eq!(Gas::from_gas(u64::MAX -2).checked_add(Gas::from_gas(2)), Some(Gas::MAX));
124 /// assert_eq!(Gas::from_gas(u64::MAX -2).checked_add(Gas::from_gas(3)), None);
125 /// ```
126 pub const fn checked_add(self, rhs: Gas) -> Option<Self> {
127 if let Some(result) = self.0.checked_add(rhs.0) { Some(Self(result)) } else { None }
128 }
129
130 pub fn checked_add_result(self, rhs: Gas) -> Result<Self, IntegerOverflowError> {
131 self.checked_add(rhs).ok_or(IntegerOverflowError)
132 }
133
134 /// Checked integer subtraction. Computes self - rhs, returning None if overflow occurred.
135 ///
136 /// # Examples
137 /// ```
138 /// use near_primitives_core::gas::Gas;
139 ///
140 /// assert_eq!(Gas::from_gas(2).checked_sub(Gas::from_gas(2)), Some(Gas::ZERO));
141 /// assert_eq!(Gas::from_gas(2).checked_sub(Gas::from_gas(3)), None);
142 /// ```
143 pub const fn checked_sub(self, rhs: Gas) -> Option<Self> {
144 if let Some(result) = self.0.checked_sub(rhs.0) { Some(Self(result)) } else { None }
145 }
146
147 /// Checked integer multiplication. Computes self * rhs, returning None if overflow occurred.
148 ///
149 /// # Examples
150 /// ```
151 /// use near_primitives_core::gas::Gas;
152 ///
153 /// use std::u64;
154 /// assert_eq!(Gas::from_gas(2).checked_mul(2), Some(Gas::from_gas(4)));
155 /// assert_eq!(Gas::MAX.checked_mul(2), None)
156 pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
157 if let Some(result) = self.0.checked_mul(rhs) { Some(Self(result)) } else { None }
158 }
159
160 /// Checked integer division. Computes self / rhs, returning None if rhs == 0.
161 ///
162 /// # Examples
163 /// ```
164 /// use near_primitives_core::gas::Gas;
165 ///
166 /// assert_eq!(Gas::from_gas(10).checked_div(2), Some(Gas::from_gas(5)));
167 /// assert_eq!(Gas::from_gas(2).checked_div(0), None);
168 /// ```
169 pub const fn checked_div(self, rhs: u64) -> Option<Self> {
170 if let Some(result) = self.0.checked_div(rhs) { Some(Self(result)) } else { None }
171 }
172
173 /// Saturating integer addition. Computes self + rhs, saturating at the numeric bounds instead of overflowing.
174 ///
175 /// # Examples
176 /// ```
177 /// use near_primitives_core::gas::Gas;
178 /// assert_eq!(Gas::from_gas(5).saturating_add(Gas::from_gas(5)), Gas::from_gas(10));
179 /// assert_eq!(Gas::MAX.saturating_add(Gas::from_gas(1)), Gas::MAX);
180 /// ```
181 pub const fn saturating_add(self, rhs: Gas) -> Gas {
182 Self(self.0.saturating_add(rhs.0))
183 }
184
185 /// Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.
186 ///
187 /// # Examples
188 /// ```
189 /// use near_primitives_core::gas::Gas;
190 /// assert_eq!(Gas::from_gas(5).saturating_sub(Gas::from_gas(2)), Gas::from_gas(3));
191 /// assert_eq!(Gas::from_gas(1).saturating_sub(Gas::from_gas(2)), Gas::ZERO);
192 /// ```
193 pub const fn saturating_sub(self, rhs: Gas) -> Gas {
194 Self(self.0.saturating_sub(rhs.0))
195 }
196
197 /// Saturating integer multiplication. Computes self * rhs, saturating at the numeric bounds instead of overflowing.
198 ///
199 /// # Examples
200 /// ```
201 /// use near_primitives_core::gas::Gas;
202 /// use std::u64;
203 /// assert_eq!(Gas::from_gas(2).saturating_mul(5), Gas::from_gas(10));
204 /// assert_eq!(Gas::MAX.saturating_mul(2), Gas::MAX);
205 /// ```
206 pub const fn saturating_mul(self, rhs: u64) -> Gas {
207 Self(self.0.saturating_mul(rhs))
208 }
209
210 /// Saturating integer division. Computes self / rhs, saturating at the numeric bounds instead of overflowing.
211 ///
212 /// # Examples
213 /// ```
214 /// use near_primitives_core::gas::Gas;
215 /// assert_eq!(Gas::from_gas(10).saturating_div(2), Gas::from_gas(5));
216 /// assert_eq!(Gas::from_gas(10).saturating_div(0), Gas::ZERO)
217 /// ```
218 pub const fn saturating_div(self, rhs: u64) -> Gas {
219 if rhs == 0 {
220 return Gas::ZERO;
221 }
222 Self(self.0.saturating_div(rhs))
223 }
224}
225
226impl serde::Serialize for Gas {
227 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
228 where
229 S: serde::Serializer,
230 {
231 serializer.serialize_u64(self.as_gas())
232 }
233}
234
235impl core::fmt::Debug for Gas {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 write!(f, "{}", self.as_gas())
238 }
239}
240
241#[cfg(feature = "schemars")]
242impl schemars::JsonSchema for Gas {
243 fn schema_name() -> std::borrow::Cow<'static, str> {
244 "NearGas".to_string().into()
245 }
246
247 fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
248 schemars::json_schema!({
249 "format": "uint64",
250 "minimum": 0,
251 "type": "integer"
252 })
253 }
254}