1use crate::cell::{Load, Store};
4use crate::error::ParseGlobalCapabilityError;
5
6macro_rules! decl_global_capability {
7 ($(#[doc = $doc:expr])* $vis:vis enum $ident:ident {$(
8 $(#[doc = $var_doc:expr])*
9 $field:ident = $descr:literal
10 ),*$(,)?}) => {
11 $(#[doc = $doc])*
12 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
13 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14 #[repr(u64)]
15 $vis enum $ident {$(
16 $(#[doc = $var_doc])*
17 $field = 1u64 << $descr
18 ),*,}
19
20 impl GlobalCapability {
21 const fn from_bit_offset(bit_offset: u32) -> Option<Self> {
22 Some(match bit_offset {
23 $($descr => Self::$field),*,
24 _ => return None,
25 })
26 }
27 }
28
29 impl std::fmt::Display for GlobalCapability {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.write_str(match self {
32 $(Self::$field => stringify!($field),)*
33 })
34 }
35 }
36
37 impl std::str::FromStr for GlobalCapability {
38 type Err = ParseGlobalCapabilityError;
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 Ok(match s {
42 $(stringify!($field) => Self::$field,)*
43 _ => return Err(ParseGlobalCapabilityError::UnknownCapability),
44 })
45 }
46 }
47 };
48}
49
50decl_global_capability! {
51 pub enum GlobalCapability {
53 CapIhrEnabled = 0,
57
58 CapCreateStatsEnabled = 1,
62
63 CapBounceMsgBody = 2,
67
68 CapReportVersion = 3,
74
75 CapSplitMergeTransactions = 4,
79
80 CapShortDequeue = 5,
84
85 CapMbppEnabled = 6,
89
90 CapFastStorageStat = 7,
95
96 CapInitCodeHash = 8,
100
101 CapOffHypercube = 9,
105
106 CapMyCode = 10,
110
111 CapSetLibCode = 11,
115
116 CapFixTupleIndexBug = 12,
120
121 CapRemp = 13,
125
126 CapDelections = 14,
130
131 CapFullBodyInBounced = 16,
136
137 CapStorageFeeToTvm = 17,
141
142 CapCopyleft = 18,
146
147 CapIndexAccounts = 19,
151
152 CapDiff = 20,
156
157 CapsTvmBugfixes2022 = 21,
161
162 CapWorkchains = 22,
166
167 CapStcontNewFormat = 23,
171
172 CapFastStorageStatBugfix = 24,
176
177 CapResolveMerkleCell = 25,
181
182 CapSignatureWithId = 26,
186
187 CapBounceAfterFailedAction = 27,
191
192 CapGroth16 = 28,
196
197 CapFeeInGasUnits = 29,
201
202 CapBigCells = 30,
206
207 CapSuspendedList = 31,
211
212 CapFastFinality = 32,
216 }
217}
218
219impl std::ops::BitOr<GlobalCapability> for GlobalCapability {
220 type Output = GlobalCapabilities;
221
222 #[inline]
223 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
224 GlobalCapabilities(self as u64 | rhs as u64)
225 }
226}
227
228impl std::ops::BitOr<GlobalCapability> for u64 {
229 type Output = GlobalCapabilities;
230
231 #[inline]
232 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
233 GlobalCapabilities(self | rhs as u64)
234 }
235}
236
237impl std::ops::BitOrAssign<GlobalCapability> for u64 {
238 #[inline]
239 fn bitor_assign(&mut self, rhs: GlobalCapability) {
240 *self = (*self | rhs).0;
241 }
242}
243
244impl std::ops::BitOr<u64> for GlobalCapability {
245 type Output = GlobalCapabilities;
246
247 #[inline]
248 fn bitor(self, rhs: u64) -> Self::Output {
249 GlobalCapabilities(self as u64 | rhs)
250 }
251}
252
253impl std::ops::BitOr<GlobalCapability> for GlobalCapabilities {
254 type Output = GlobalCapabilities;
255
256 #[inline]
257 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
258 GlobalCapabilities(self.0 | rhs as u64)
259 }
260}
261
262impl std::ops::BitOr<GlobalCapabilities> for GlobalCapability {
263 type Output = GlobalCapabilities;
264
265 #[inline]
266 fn bitor(self, rhs: GlobalCapabilities) -> Self::Output {
267 GlobalCapabilities(self as u64 | rhs.0)
268 }
269}
270
271impl std::ops::BitOrAssign<u64> for GlobalCapabilities {
272 #[inline]
273 fn bitor_assign(&mut self, rhs: u64) {
274 *self = GlobalCapabilities(self.0 | rhs);
275 }
276}
277
278impl std::ops::BitOrAssign<GlobalCapability> for GlobalCapabilities {
279 #[inline]
280 fn bitor_assign(&mut self, rhs: GlobalCapability) {
281 *self = *self | rhs;
282 }
283}
284
285#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
287#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
288#[tlb(tag = "#c4")]
289pub struct GlobalVersion {
290 pub version: u32,
292 pub capabilities: GlobalCapabilities,
294}
295
296#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Store, Load)]
300#[repr(transparent)]
301pub struct GlobalCapabilities(u64);
302
303impl GlobalCapabilities {
304 #[inline]
306 pub const fn new(inner: u64) -> Self {
307 Self(inner)
308 }
309
310 #[inline]
312 pub const fn is_empty(&self) -> bool {
313 self.0 == 0
314 }
315
316 pub const fn len(&self) -> usize {
318 self.0.count_ones() as usize
319 }
320
321 #[inline]
323 pub const fn contains(&self, capability: GlobalCapability) -> bool {
324 (self.0 & (capability as u64)) != 0
325 }
326
327 #[inline]
329 pub const fn into_inner(self) -> u64 {
330 self.0
331 }
332
333 #[inline]
335 pub fn iter(&self) -> GlobalCapabilitiesIter {
336 GlobalCapabilitiesIter(self.0)
337 }
338}
339
340impl From<u64> for GlobalCapabilities {
341 #[inline]
342 fn from(value: u64) -> Self {
343 Self(value)
344 }
345}
346
347impl From<GlobalCapabilities> for u64 {
348 #[inline]
349 fn from(value: GlobalCapabilities) -> Self {
350 value.0
351 }
352}
353
354impl PartialEq<u64> for GlobalCapabilities {
355 #[inline]
356 fn eq(&self, other: &u64) -> bool {
357 self.0 == *other
358 }
359}
360
361impl IntoIterator for GlobalCapabilities {
362 type Item = GlobalCapability;
363 type IntoIter = GlobalCapabilitiesIter;
364
365 #[inline]
366 fn into_iter(self) -> Self::IntoIter {
367 GlobalCapabilitiesIter(self.0)
368 }
369}
370
371impl FromIterator<GlobalCapability> for GlobalCapabilities {
372 fn from_iter<T: IntoIterator<Item = GlobalCapability>>(iter: T) -> Self {
373 let mut res = GlobalCapabilities::default();
374 for item in iter {
375 res |= item;
376 }
377 res
378 }
379}
380
381impl<const N: usize> From<[GlobalCapability; N]> for GlobalCapabilities {
382 fn from(value: [GlobalCapability; N]) -> Self {
383 let mut res = GlobalCapabilities::default();
384 for item in value.iter() {
385 res |= *item;
386 }
387 res
388 }
389}
390
391#[cfg(feature = "serde")]
392impl serde::Serialize for GlobalCapabilities {
393 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
394 where
395 S: serde::Serializer,
396 {
397 use serde::ser::SerializeSeq;
398
399 if serializer.is_human_readable() {
400 let mut seq = serializer.serialize_seq(Some(self.len()))?;
401 for capability in self.iter() {
402 seq.serialize_element(&capability)?;
403 }
404 seq.end()
405 } else {
406 serializer.serialize_u64(self.0)
407 }
408 }
409}
410
411#[cfg(feature = "serde")]
412impl<'de> serde::Deserialize<'de> for GlobalCapabilities {
413 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
414 where
415 D: serde::Deserializer<'de>,
416 {
417 use serde::de::Visitor;
418
419 struct GlobalCapabilitiesVisitor;
420
421 impl<'de> Visitor<'de> for GlobalCapabilitiesVisitor {
422 type Value = GlobalCapabilities;
423
424 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
425 f.write_str("a list of global capabilities")
426 }
427
428 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
429 where
430 A: serde::de::SeqAccess<'de>,
431 {
432 let mut res = GlobalCapabilities::default();
433 while let Some(capacility) = ok!(seq.next_element::<GlobalCapability>()) {
434 res |= capacility;
435 }
436 Ok(res)
437 }
438 }
439
440 if deserializer.is_human_readable() {
441 deserializer.deserialize_seq(GlobalCapabilitiesVisitor)
442 } else {
443 u64::deserialize(deserializer).map(Self)
444 }
445 }
446}
447
448#[derive(Clone)]
455pub struct GlobalCapabilitiesIter(u64);
456
457impl Iterator for GlobalCapabilitiesIter {
458 type Item = GlobalCapability;
459
460 fn next(&mut self) -> Option<Self::Item> {
461 while self.0 != 0 {
462 let mask = self.0 & !(self.0 - 1);
466
467 self.0 &= !mask;
469
470 if let Some(item) = GlobalCapability::from_bit_offset(mask.trailing_zeros()) {
471 return Some(item);
472 }
473 }
474
475 None
476 }
477
478 fn size_hint(&self) -> (usize, Option<usize>) {
479 let len = self.0.count_ones() as usize;
480 (len, Some(len))
481 }
482}
483
484#[cfg(test)]
485mod tests {
486 use super::*;
487
488 #[test]
489 fn capabilities_iter() {
490 let capabilities = GlobalCapability::CapCreateStatsEnabled
491 | GlobalCapability::CapBounceMsgBody
492 | GlobalCapability::CapReportVersion
493 | GlobalCapability::CapShortDequeue
494 | GlobalCapability::CapFastStorageStat
495 | GlobalCapability::CapOffHypercube
496 | GlobalCapability::CapMyCode
497 | GlobalCapability::CapFixTupleIndexBug;
498
499 let capabilities = capabilities.into_iter().collect::<Vec<_>>();
500 assert_eq!(capabilities, [
501 GlobalCapability::CapCreateStatsEnabled,
502 GlobalCapability::CapBounceMsgBody,
503 GlobalCapability::CapReportVersion,
504 GlobalCapability::CapShortDequeue,
505 GlobalCapability::CapFastStorageStat,
506 GlobalCapability::CapOffHypercube,
507 GlobalCapability::CapMyCode,
508 GlobalCapability::CapFixTupleIndexBug
509 ]);
510 }
511}