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
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.

#[repr(C)]
#[derive(Debug, Eq, PartialEq)]
pub struct PropertyHandlerFlags(u32);

impl PropertyHandlerFlags {
  /// None.
  pub const NONE: Self = Self(0);

  /// See ALL_CAN_READ above.
  pub const ALL_CAN_READ: Self = Self(1 << 0);

  /// Will not call into interceptor for properties on the receiver or prototype
  /// chain, i.e., only call into interceptor for properties that do not exist.
  /// Currently only valid for named interceptors.
  pub const NON_MASKING: Self = Self(1 << 1);

  /// Will not call into interceptor for symbol lookup.  Only meaningful for
  /// named interceptors.
  pub const ONLY_INTERCEPT_STRINGS: Self = Self(1 << 2);

  /// The getter, query, enumerator callbacks do not produce side effects.
  pub const HAS_NO_SIDE_EFFECT: Self = Self(1 << 3);

  /// Test if no property handler flags are set.
  #[inline(always)]
  pub fn is_none(&self) -> bool {
    *self == Self::NONE
  }

  /// Test if the all-can-read property handler flag is set.
  #[inline(always)]
  pub fn is_all_can_read(&self) -> bool {
    self.has(Self::ALL_CAN_READ)
  }

  /// Test if the non-masking property handler flag is set.
  #[inline(always)]
  pub fn is_non_masking(&self) -> bool {
    self.has(Self::NON_MASKING)
  }

  /// Test if the only-intercept-strings property handler flag is set.
  #[inline(always)]
  pub fn is_only_intercept_strings(&self) -> bool {
    self.has(Self::ONLY_INTERCEPT_STRINGS)
  }

  /// Test if the has-no-side-effect property handler flag is set.
  #[inline(always)]
  pub fn is_has_no_side_effect(&self) -> bool {
    self.has(Self::HAS_NO_SIDE_EFFECT)
  }

  #[inline(always)]
  fn has(&self, that: Self) -> bool {
    let Self(lhs) = self;
    let Self(rhs) = that;
    0 != lhs & rhs
  }
}

// Identical to #[derive(Default)] but arguably clearer when made explicit.
impl Default for PropertyHandlerFlags {
  fn default() -> Self {
    Self::NONE
  }
}

impl std::ops::BitOr for PropertyHandlerFlags {
  type Output = Self;

  fn bitor(self, Self(rhs): Self) -> Self {
    let Self(lhs) = self;
    Self(lhs | rhs)
  }
}

#[test]
fn test_attr() {
  assert!(PropertyHandlerFlags::NONE.is_none());
  assert!(!PropertyHandlerFlags::NONE.is_all_can_read());
  assert!(!PropertyHandlerFlags::NONE.is_non_masking());
  assert!(!PropertyHandlerFlags::NONE.is_only_intercept_strings());
  assert!(!PropertyHandlerFlags::NONE.is_has_no_side_effect());

  assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_none());
  assert!(PropertyHandlerFlags::ALL_CAN_READ.is_all_can_read());
  assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_non_masking());
  assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_only_intercept_strings());
  assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_has_no_side_effect());

  assert!(!PropertyHandlerFlags::NON_MASKING.is_none());
  assert!(!PropertyHandlerFlags::NON_MASKING.is_all_can_read());
  assert!(PropertyHandlerFlags::NON_MASKING.is_non_masking());
  assert!(!PropertyHandlerFlags::NON_MASKING.is_only_intercept_strings());
  assert!(!PropertyHandlerFlags::NON_MASKING.is_has_no_side_effect());

  assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_none());
  assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_all_can_read());
  assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_non_masking());
  assert!(
    PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_only_intercept_strings()
  );
  assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_has_no_side_effect());

  assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_none());
  assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_all_can_read());
  assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_non_masking());
  assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_only_intercept_strings());
  assert!(PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_has_no_side_effect());

  assert_eq!(PropertyHandlerFlags::NONE, Default::default());
  assert_eq!(
    PropertyHandlerFlags::ALL_CAN_READ,
    PropertyHandlerFlags::NONE | PropertyHandlerFlags::ALL_CAN_READ
  );

  let attr =
    PropertyHandlerFlags::ALL_CAN_READ | PropertyHandlerFlags::NON_MASKING;
  assert!(!attr.is_none());
  assert!(attr.is_all_can_read());
  assert!(attr.is_non_masking());
  assert!(!attr.is_only_intercept_strings());
  assert!(!attr.is_has_no_side_effect());

  let attr = PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS
    | PropertyHandlerFlags::HAS_NO_SIDE_EFFECT
    | PropertyHandlerFlags::NON_MASKING;
  assert!(!attr.is_none());
  assert!(!attr.is_all_can_read());
  assert!(attr.is_non_masking());
  assert!(attr.is_only_intercept_strings());
  assert!(attr.is_has_no_side_effect());
}