use boa_gc::{Finalize, Trace};
use thin_vec::ThinVec;
use crate::{
object::{shape::slot::SlotAttributes, JsObject, Object, ObjectData, PropertyMap},
property::{Attribute, PropertyKey},
JsValue,
};
use super::{SharedShape, TransitionKey};
#[derive(Debug, Clone, Trace, Finalize)]
pub(crate) struct ObjectTemplate {
shape: SharedShape,
}
impl ObjectTemplate {
pub(crate) fn new(shape: &SharedShape) -> Self {
Self {
shape: shape.clone(),
}
}
pub(crate) fn with_prototype(shape: &SharedShape, prototype: JsObject) -> Self {
let shape = shape.change_prototype_transition(Some(prototype));
Self { shape }
}
pub(crate) fn has_prototype(&self, prototype: &JsObject) -> bool {
self.shape.has_prototype(prototype)
}
pub(crate) fn set_prototype(&mut self, prototype: JsObject) -> &mut Self {
self.shape = self.shape.change_prototype_transition(Some(prototype));
self
}
pub(crate) const fn shape(&self) -> &SharedShape {
&self.shape
}
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
}
pub(crate) fn accessor(
&mut self,
key: PropertyKey,
get: bool,
set: bool,
attributes: Attribute,
) -> &mut Self {
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
}
pub(crate) fn create(&self, data: ObjectData, storage: Vec<JsValue>) -> JsObject {
let mut object = Object {
kind: data.kind,
extensible: true,
properties: PropertyMap::new(self.shape.clone().into(), ThinVec::default()),
private_elements: ThinVec::new(),
};
object.properties.storage = storage;
JsObject::from_object_and_vtable(object, data.internal_methods)
}
pub(crate) fn create_with_indexed_properties(
&self,
data: ObjectData,
storage: Vec<JsValue>,
elements: ThinVec<JsValue>,
) -> JsObject {
let mut object = Object {
kind: data.kind,
extensible: true,
properties: PropertyMap::new(self.shape.clone().into(), elements),
private_elements: ThinVec::new(),
};
object.properties.storage = storage;
JsObject::from_object_and_vtable(object, data.internal_methods)
}
}