mirror of https://github.com/boa-dev/boa.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.6 KiB
146 lines
4.6 KiB
use boa_gc::{Finalize, Trace}; |
|
use thin_vec::ThinVec; |
|
|
|
use crate::{ |
|
object::{ |
|
shape::slot::SlotAttributes, IndexedProperties, JsObject, NativeObject, Object, PropertyMap, |
|
}, |
|
property::{Attribute, PropertyKey}, |
|
JsValue, |
|
}; |
|
|
|
use super::{SharedShape, TransitionKey}; |
|
|
|
/// Represent a template of an objects properties and prototype. |
|
/// This is used to construct as many objects as needed from a predefined [`SharedShape`]. |
|
#[derive(Debug, Clone, Trace, Finalize)] |
|
pub(crate) struct ObjectTemplate { |
|
shape: SharedShape, |
|
} |
|
|
|
impl ObjectTemplate { |
|
/// Create a new [`ObjectTemplate`] |
|
pub(crate) fn new(shape: &SharedShape) -> Self { |
|
Self { |
|
shape: shape.clone(), |
|
} |
|
} |
|
|
|
/// Create and [`ObjectTemplate`] with a prototype. |
|
pub(crate) fn with_prototype(shape: &SharedShape, prototype: JsObject) -> Self { |
|
let shape = shape.change_prototype_transition(Some(prototype)); |
|
Self { shape } |
|
} |
|
|
|
/// Check if the shape has a specific, prototype. |
|
pub(crate) fn has_prototype(&self, prototype: &JsObject) -> bool { |
|
self.shape.has_prototype(prototype) |
|
} |
|
|
|
/// Set the prototype of the [`ObjectTemplate`]. |
|
/// |
|
/// This assumes that the prototype has not been set yet. |
|
pub(crate) fn set_prototype(&mut self, prototype: JsObject) -> &mut Self { |
|
self.shape = self.shape.change_prototype_transition(Some(prototype)); |
|
self |
|
} |
|
|
|
/// Returns the inner shape of the [`ObjectTemplate`]. |
|
pub(crate) const fn shape(&self) -> &SharedShape { |
|
&self.shape |
|
} |
|
|
|
/// Add a data property to the [`ObjectTemplate`]. |
|
/// |
|
/// This assumes that the property with the given key was not previously set |
|
/// and that it's a string or symbol. |
|
pub(crate) fn property(&mut self, key: PropertyKey, attributes: Attribute) -> &mut Self { |
|
debug_assert!(!matches!(&key, PropertyKey::Index(_))); |
|
|
|
let attributes = SlotAttributes::from_bits_truncate(attributes.bits()); |
|
self.shape = self.shape.insert_property_transition(TransitionKey { |
|
property_key: key, |
|
attributes, |
|
}); |
|
self |
|
} |
|
|
|
/// Add a accessor property to the [`ObjectTemplate`]. |
|
/// |
|
/// This assumes that the property with the given key was not previously set |
|
/// and that it's a string or symbol. |
|
pub(crate) fn accessor( |
|
&mut self, |
|
key: PropertyKey, |
|
get: bool, |
|
set: bool, |
|
attributes: Attribute, |
|
) -> &mut Self { |
|
// TOOD: We don't support indexed keys. |
|
debug_assert!(!matches!(&key, PropertyKey::Index(_))); |
|
|
|
let attributes = { |
|
let mut result = SlotAttributes::empty(); |
|
result.set( |
|
SlotAttributes::CONFIGURABLE, |
|
attributes.contains(Attribute::CONFIGURABLE), |
|
); |
|
result.set( |
|
SlotAttributes::ENUMERABLE, |
|
attributes.contains(Attribute::ENUMERABLE), |
|
); |
|
|
|
result.set(SlotAttributes::GET, get); |
|
result.set(SlotAttributes::SET, set); |
|
|
|
result |
|
}; |
|
|
|
self.shape = self.shape.insert_property_transition(TransitionKey { |
|
property_key: key, |
|
attributes, |
|
}); |
|
self |
|
} |
|
|
|
/// Create an object from the [`ObjectTemplate`] |
|
/// |
|
/// The storage must match the properties provided. |
|
pub(crate) fn create<T: NativeObject>(&self, data: T, storage: Vec<JsValue>) -> JsObject { |
|
let internal_methods = data.internal_methods(); |
|
|
|
let mut object = Object { |
|
data, |
|
extensible: true, |
|
properties: PropertyMap::new(self.shape.clone().into(), IndexedProperties::default()), |
|
private_elements: ThinVec::new(), |
|
}; |
|
|
|
object.properties.storage = storage; |
|
|
|
JsObject::from_object_and_vtable(object, internal_methods) |
|
} |
|
|
|
/// Create an object from the [`ObjectTemplate`] |
|
/// |
|
/// The storage must match the properties provided. It does not apply to |
|
/// the indexed propeties. |
|
pub(crate) fn create_with_indexed_properties<T: NativeObject>( |
|
&self, |
|
data: T, |
|
storage: Vec<JsValue>, |
|
indexed_properties: IndexedProperties, |
|
) -> JsObject { |
|
let internal_methods = data.internal_methods(); |
|
let mut object = Object { |
|
data, |
|
extensible: true, |
|
properties: PropertyMap::new(self.shape.clone().into(), indexed_properties), |
|
private_elements: ThinVec::new(), |
|
}; |
|
|
|
object.properties.storage = storage; |
|
|
|
JsObject::from_object_and_vtable(object, internal_methods) |
|
} |
|
}
|
|
|