-
-
Notifications
You must be signed in to change notification settings - Fork 408
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
317 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
//! This module implements the `Attribute` struct which contains the attibutes for `Property`. | ||
use bitflags::bitflags; | ||
use gc::{unsafe_empty_trace, Finalize, Trace}; | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
bitflags! { | ||
/// This struct constains the property flags as describen in the [`ECMAScript specification`][spec]. | ||
/// | ||
/// It contains the following flags: | ||
/// - `[[Writable]]` (`WRITABLE`) - If `false`, attempts by ECMAScript code to change the property's `[[Value]]` attribute using `[[Set]]` will not succeed. | ||
/// - `[[Enumerable]]` (`ENUMERABLE`) - If the property will be enumerated by a for-in enumeration. | ||
/// - `[[Configurable]]` (`CONFIGURABLE`) - If `false`, attempts to delete the property, change the property to be an `accessor property`, or change its attributes (other than `[[Value]]`, or changing `[[Writable]]` to `false`) will fail. | ||
/// | ||
/// Additionaly there are flags for when the flags are defined. | ||
#[derive(Finalize)] | ||
pub struct Attribute: u8 { | ||
/// None of the flags are present. | ||
const NONE = 0b0000_0000; | ||
|
||
/// The `Writable` attribute decides whether the value associated with the property can be changed or not, from its initial value. | ||
const WRITABLE = 0b0000_0011; | ||
|
||
/// The property is not writable. | ||
const READONLY = 0b0000_0010; | ||
|
||
/// Is the `Writable` flag defined. | ||
const HAS_WRITABLE = 0b0000_0010; | ||
|
||
/// If the property can be enumerated by a `for-in` loop. | ||
const ENUMERABLE = 0b0000_1100; | ||
|
||
/// The property can not be enumerated in a `for-in`. | ||
const NON_ENUMERABLE = 0b0000_1000; | ||
|
||
/// Is the `Enumerable` flag defined. | ||
const HAS_ENUMERABLE = 0b0000_1000; | ||
|
||
/// If the property descriptor can be changed later. | ||
const CONFIGURABLE = 0b0011_0000; | ||
|
||
/// The property descriptor cannot be changed. | ||
const PERMANENT = 0b0010_0000; | ||
|
||
/// Is the `Configurable` flag defined. | ||
const HAS_CONFIGURABLE = 0b0010_0000; | ||
} | ||
} | ||
|
||
// We implement `Trace` manualy rather that wih derive, beacuse `rust-gc`, | ||
// derive `Trace` does not allow `Copy` and `Trace` to be both implemented. | ||
// | ||
// SAFETY: The `Attribute` struct only contains an `u8` | ||
// and therefore it should be safe to implement an empty trace. | ||
unsafe impl Trace for Attribute { | ||
unsafe_empty_trace!(); | ||
} | ||
|
||
impl Attribute { | ||
/// Clear all flags. | ||
#[inline] | ||
pub fn clear(&mut self) { | ||
self.bits = 0; | ||
} | ||
|
||
/// Is the `writable` flag defined. | ||
#[inline] | ||
pub fn has_writable(self) -> bool { | ||
self.contains(Self::HAS_WRITABLE) | ||
} | ||
|
||
/// Sets the `writable` flag. | ||
#[inline] | ||
pub fn set_writable(&mut self, value: bool) { | ||
if value { | ||
*self |= Self::WRITABLE; | ||
} else { | ||
*self |= *self & !Self::WRITABLE; | ||
} | ||
} | ||
|
||
/// Gets the `writable` flag. | ||
#[inline] | ||
pub fn writable(self) -> bool { | ||
debug_assert!(self.has_writable()); | ||
self.contains(Self::WRITABLE) | ||
} | ||
|
||
/// Is the `enumerable` flag defined. | ||
#[inline] | ||
pub fn has_enumerable(self) -> bool { | ||
self.contains(Self::HAS_ENUMERABLE) | ||
} | ||
|
||
/// Sets the `enumerable` flag. | ||
#[inline] | ||
pub fn set_enumerable(&mut self, value: bool) { | ||
if value { | ||
*self |= Self::ENUMERABLE; | ||
} else { | ||
*self |= *self & !Self::ENUMERABLE; | ||
} | ||
} | ||
|
||
/// Gets the `enumerable` flag. | ||
#[inline] | ||
pub fn enumerable(self) -> bool { | ||
debug_assert!(self.has_enumerable()); | ||
self.contains(Self::ENUMERABLE) | ||
} | ||
|
||
/// Is the `configurable` flag defined. | ||
#[inline] | ||
pub fn has_configurable(self) -> bool { | ||
self.contains(Self::HAS_CONFIGURABLE) | ||
} | ||
|
||
/// Sets the `configurable` flag. | ||
#[inline] | ||
pub fn set_configurable(&mut self, value: bool) { | ||
if value { | ||
*self |= Self::CONFIGURABLE; | ||
} else { | ||
*self |= *self & !Self::CONFIGURABLE; | ||
} | ||
} | ||
|
||
/// Gets the `configurable` flag. | ||
#[inline] | ||
pub fn configurable(self) -> bool { | ||
debug_assert!(self.has_configurable()); | ||
self.contains(Self::CONFIGURABLE) | ||
} | ||
} | ||
|
||
impl Default for Attribute { | ||
/// Returns the default flags according to the [ECMAScript specification][spec]. | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#table-default-attribute-values | ||
fn default() -> Self { | ||
Self::READONLY | Self::NON_ENUMERABLE | Self::PERMANENT | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
|
||
use super::Attribute; | ||
|
||
#[test] | ||
fn writable() { | ||
let attribute = Attribute::WRITABLE; | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(attribute.writable()); | ||
} | ||
|
||
#[test] | ||
fn enumerable() { | ||
let attribute = Attribute::ENUMERABLE; | ||
|
||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.enumerable()); | ||
} | ||
|
||
#[test] | ||
fn configurable() { | ||
let attribute = Attribute::CONFIGURABLE; | ||
|
||
assert!(attribute.has_configurable()); | ||
assert!(attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn writable_and_enumerable() { | ||
let attribute = Attribute::WRITABLE | Attribute::ENUMERABLE; | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.enumerable()); | ||
|
||
assert!(!attribute.has_configurable()); | ||
} | ||
|
||
#[test] | ||
fn enumerable_configurable() { | ||
let attribute = Attribute::ENUMERABLE | Attribute::CONFIGURABLE; | ||
|
||
assert!(!attribute.has_writable()); | ||
|
||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn writable_enumerable_configurable() { | ||
let attribute = Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE; | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn default() { | ||
let attribute = Attribute::default(); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.has_configurable()); | ||
} | ||
|
||
#[test] | ||
fn clear() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.clear(); | ||
|
||
assert!(!attribute.has_writable()); | ||
assert!(!attribute.has_enumerable()); | ||
assert!(!attribute.has_configurable()); | ||
|
||
assert!(attribute.is_empty()); | ||
} | ||
|
||
#[test] | ||
fn set_writable_to_true() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_writable(true); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(!attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(!attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn set_writable_to_false() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_writable(false); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(!attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(!attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(!attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn set_enumerable_to_true() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_enumerable(true); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(!attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(!attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn set_enumerable_to_false() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_enumerable(false); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(!attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(!attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(!attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn set_configurable_to_true() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_configurable(true); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(!attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(!attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(attribute.configurable()); | ||
} | ||
|
||
#[test] | ||
fn set_configurable_to_false() { | ||
let mut attribute = Attribute::default(); | ||
|
||
attribute.set_configurable(false); | ||
|
||
assert!(attribute.has_writable()); | ||
assert!(!attribute.writable()); | ||
assert!(attribute.has_enumerable()); | ||
assert!(!attribute.enumerable()); | ||
assert!(attribute.has_configurable()); | ||
assert!(!attribute.configurable()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters