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 CapSuspendByMarks = 33,
221
222 CapOmitMasterBlockHistory = 34,
226
227 CapSignatureDomain = 35,
234 }
235}
236
237impl std::ops::BitOr<GlobalCapability> for GlobalCapability {
238 type Output = GlobalCapabilities;
239
240 #[inline]
241 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
242 GlobalCapabilities(self as u64 | rhs as u64)
243 }
244}
245
246impl std::ops::BitOr<GlobalCapability> for u64 {
247 type Output = GlobalCapabilities;
248
249 #[inline]
250 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
251 GlobalCapabilities(self | rhs as u64)
252 }
253}
254
255impl std::ops::BitOrAssign<GlobalCapability> for u64 {
256 #[inline]
257 fn bitor_assign(&mut self, rhs: GlobalCapability) {
258 *self = (*self | rhs).0;
259 }
260}
261
262impl std::ops::BitOr<u64> for GlobalCapability {
263 type Output = GlobalCapabilities;
264
265 #[inline]
266 fn bitor(self, rhs: u64) -> Self::Output {
267 GlobalCapabilities(self as u64 | rhs)
268 }
269}
270
271impl std::ops::BitOr<GlobalCapability> for GlobalCapabilities {
272 type Output = GlobalCapabilities;
273
274 #[inline]
275 fn bitor(self, rhs: GlobalCapability) -> Self::Output {
276 GlobalCapabilities(self.0 | rhs as u64)
277 }
278}
279
280impl std::ops::BitOr<GlobalCapabilities> for GlobalCapability {
281 type Output = GlobalCapabilities;
282
283 #[inline]
284 fn bitor(self, rhs: GlobalCapabilities) -> Self::Output {
285 GlobalCapabilities(self as u64 | rhs.0)
286 }
287}
288
289impl std::ops::BitOrAssign<u64> for GlobalCapabilities {
290 #[inline]
291 fn bitor_assign(&mut self, rhs: u64) {
292 *self = GlobalCapabilities(self.0 | rhs);
293 }
294}
295
296impl std::ops::BitOrAssign<GlobalCapability> for GlobalCapabilities {
297 #[inline]
298 fn bitor_assign(&mut self, rhs: GlobalCapability) {
299 *self = *self | rhs;
300 }
301}
302
303#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
305#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
306#[tlb(tag = "#c4")]
307pub struct GlobalVersion {
308 pub version: u32,
310 pub capabilities: GlobalCapabilities,
312}
313
314#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Store, Load)]
318#[repr(transparent)]
319pub struct GlobalCapabilities(u64);
320
321impl GlobalCapabilities {
322 #[inline]
324 pub const fn new(inner: u64) -> Self {
325 Self(inner)
326 }
327
328 #[inline]
330 pub const fn is_empty(&self) -> bool {
331 self.0 == 0
332 }
333
334 pub const fn len(&self) -> usize {
336 self.0.count_ones() as usize
337 }
338
339 #[inline]
341 pub const fn contains(&self, capability: GlobalCapability) -> bool {
342 (self.0 & (capability as u64)) != 0
343 }
344
345 #[inline]
347 pub const fn into_inner(self) -> u64 {
348 self.0
349 }
350
351 #[inline]
353 pub fn iter(&self) -> GlobalCapabilitiesIter {
354 GlobalCapabilitiesIter(self.0)
355 }
356}
357
358impl From<u64> for GlobalCapabilities {
359 #[inline]
360 fn from(value: u64) -> Self {
361 Self(value)
362 }
363}
364
365impl From<GlobalCapabilities> for u64 {
366 #[inline]
367 fn from(value: GlobalCapabilities) -> Self {
368 value.0
369 }
370}
371
372impl PartialEq<u64> for GlobalCapabilities {
373 #[inline]
374 fn eq(&self, other: &u64) -> bool {
375 self.0 == *other
376 }
377}
378
379impl IntoIterator for GlobalCapabilities {
380 type Item = GlobalCapability;
381 type IntoIter = GlobalCapabilitiesIter;
382
383 #[inline]
384 fn into_iter(self) -> Self::IntoIter {
385 GlobalCapabilitiesIter(self.0)
386 }
387}
388
389impl FromIterator<GlobalCapability> for GlobalCapabilities {
390 fn from_iter<T: IntoIterator<Item = GlobalCapability>>(iter: T) -> Self {
391 let mut res = GlobalCapabilities::default();
392 for item in iter {
393 res |= item;
394 }
395 res
396 }
397}
398
399impl<const N: usize> From<[GlobalCapability; N]> for GlobalCapabilities {
400 fn from(value: [GlobalCapability; N]) -> Self {
401 let mut res = GlobalCapabilities::default();
402 for item in value.iter() {
403 res |= *item;
404 }
405 res
406 }
407}
408
409#[cfg(feature = "serde")]
410impl serde::Serialize for GlobalCapabilities {
411 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
412 where
413 S: serde::Serializer,
414 {
415 use serde::ser::SerializeSeq;
416
417 if serializer.is_human_readable() {
418 let mut seq = serializer.serialize_seq(Some(self.len()))?;
419 for capability in self.iter() {
420 seq.serialize_element(&capability)?;
421 }
422 seq.end()
423 } else {
424 serializer.serialize_u64(self.0)
425 }
426 }
427}
428
429#[cfg(feature = "serde")]
430impl<'de> serde::Deserialize<'de> for GlobalCapabilities {
431 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
432 where
433 D: serde::Deserializer<'de>,
434 {
435 use serde::de::Visitor;
436
437 struct GlobalCapabilitiesVisitor;
438
439 impl<'de> Visitor<'de> for GlobalCapabilitiesVisitor {
440 type Value = GlobalCapabilities;
441
442 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
443 f.write_str("a list of global capabilities")
444 }
445
446 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
447 where
448 A: serde::de::SeqAccess<'de>,
449 {
450 let mut res = GlobalCapabilities::default();
451 while let Some(capacility) = ok!(seq.next_element::<GlobalCapability>()) {
452 res |= capacility;
453 }
454 Ok(res)
455 }
456 }
457
458 if deserializer.is_human_readable() {
459 deserializer.deserialize_seq(GlobalCapabilitiesVisitor)
460 } else {
461 u64::deserialize(deserializer).map(Self)
462 }
463 }
464}
465
466#[derive(Clone)]
473pub struct GlobalCapabilitiesIter(u64);
474
475impl Iterator for GlobalCapabilitiesIter {
476 type Item = GlobalCapability;
477
478 fn next(&mut self) -> Option<Self::Item> {
479 while self.0 != 0 {
480 let mask = self.0 & !(self.0 - 1);
484
485 self.0 &= !mask;
487
488 if let Some(item) = GlobalCapability::from_bit_offset(mask.trailing_zeros()) {
489 return Some(item);
490 }
491 }
492
493 None
494 }
495
496 fn size_hint(&self) -> (usize, Option<usize>) {
497 let len = self.0.count_ones() as usize;
498 (len, Some(len))
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505
506 #[test]
507 fn capabilities_iter() {
508 let capabilities = GlobalCapability::CapCreateStatsEnabled
509 | GlobalCapability::CapBounceMsgBody
510 | GlobalCapability::CapReportVersion
511 | GlobalCapability::CapShortDequeue
512 | GlobalCapability::CapFastStorageStat
513 | GlobalCapability::CapOffHypercube
514 | GlobalCapability::CapMyCode
515 | GlobalCapability::CapFixTupleIndexBug;
516
517 let capabilities = capabilities.into_iter().collect::<Vec<_>>();
518 assert_eq!(capabilities, [
519 GlobalCapability::CapCreateStatsEnabled,
520 GlobalCapability::CapBounceMsgBody,
521 GlobalCapability::CapReportVersion,
522 GlobalCapability::CapShortDequeue,
523 GlobalCapability::CapFastStorageStat,
524 GlobalCapability::CapOffHypercube,
525 GlobalCapability::CapMyCode,
526 GlobalCapability::CapFixTupleIndexBug
527 ]);
528 }
529}