boa/property/attribute/mod.rs
1//! This module implements the `Attribute` struct which contains the attibutes for property descriptors.
2
3use crate::gc::{empty_trace, Finalize, Trace};
4use bitflags::bitflags;
5
6#[cfg(test)]
7mod tests;
8
9bitflags! {
10 /// This struct constains the property flags as describen in the ECMAScript specification.
11 ///
12 /// It contains the following flags:
13 /// - `[[Writable]]` (`WRITABLE`) - If `false`, attempts by ECMAScript code to change the property's
14 /// `[[Value]]` attribute using `[[Set]]` will not succeed.
15 /// - `[[Enumerable]]` (`ENUMERABLE`) - If the property will be enumerated by a for-in enumeration.
16 /// - `[[Configurable]]` (`CONFIGURABLE`) - If `false`, attempts to delete the property,
17 /// change the property to be an `accessor property`, or change its attributes (other than `[[Value]]`,
18 /// or changing `[[Writable]]` to `false`) will fail.
19 #[derive(Finalize)]
20 pub struct Attribute: u8 {
21 /// The `Writable` attribute decides whether the value associated with the property can be changed or not, from its initial value.
22 const WRITABLE = 0b0000_0001;
23
24 /// If the property can be enumerated by a `for-in` loop.
25 const ENUMERABLE = 0b0000_0010;
26
27 /// If the property descriptor can be changed later.
28 const CONFIGURABLE = 0b0000_0100;
29
30 /// The property is not writable.
31 const READONLY = 0b0000_0000;
32
33 /// The property can not be enumerated in a `for-in` loop.
34 const NON_ENUMERABLE = 0b0000_0000;
35
36 /// The property descriptor cannot be changed.
37 const PERMANENT = 0b0000_0000;
38 }
39}
40
41// We implement `Trace` manualy rather that wih derive, beacuse `rust-gc`,
42// derive `Trace` does not allow `Copy` and `Trace` to be both implemented.
43//
44// SAFETY: The `Attribute` struct only contains an `u8`
45// and therefore it should be safe to implement an empty trace.
46unsafe impl Trace for Attribute {
47 empty_trace!();
48}
49
50impl Attribute {
51 /// Clear all flags.
52 #[inline]
53 pub fn clear(&mut self) {
54 self.bits = 0;
55 }
56
57 /// Sets the `writable` flag.
58 #[inline]
59 pub fn set_writable(&mut self, value: bool) {
60 if value {
61 *self |= Self::WRITABLE;
62 } else {
63 *self |= *self & !Self::WRITABLE;
64 }
65 }
66
67 /// Gets the `writable` flag.
68 #[inline]
69 pub fn writable(self) -> bool {
70 self.contains(Self::WRITABLE)
71 }
72
73 /// Sets the `enumerable` flag.
74 #[inline]
75 pub fn set_enumerable(&mut self, value: bool) {
76 if value {
77 *self |= Self::ENUMERABLE;
78 } else {
79 *self |= *self & !Self::ENUMERABLE;
80 }
81 }
82
83 /// Gets the `enumerable` flag.
84 #[inline]
85 pub fn enumerable(self) -> bool {
86 self.contains(Self::ENUMERABLE)
87 }
88
89 /// Sets the `configurable` flag.
90 #[inline]
91 pub fn set_configurable(&mut self, value: bool) {
92 if value {
93 *self |= Self::CONFIGURABLE;
94 } else {
95 *self |= *self & !Self::CONFIGURABLE;
96 }
97 }
98
99 /// Gets the `configurable` flag.
100 #[inline]
101 pub fn configurable(self) -> bool {
102 self.contains(Self::CONFIGURABLE)
103 }
104}
105
106impl Default for Attribute {
107 /// Returns the default flags according to the [ECMAScript specification][spec].
108 ///
109 /// [spec]: https://tc39.es/ecma262/#table-default-attribute-values
110 fn default() -> Self {
111 Self::READONLY | Self::NON_ENUMERABLE | Self::PERMANENT
112 }
113}