use crate::{
object::JsObject,
property::{DescriptorKind, PropertyDescriptor, PropertyKey},
Context, JsResult, JsValue,
};
use super::{InternalObjectMethods, ORDINARY_INTERNAL_METHODS};
pub(crate) static ARGUMENTS_EXOTIC_INTERNAL_METHODS: InternalObjectMethods =
InternalObjectMethods {
__get_own_property__: arguments_exotic_get_own_property,
__define_own_property__: arguments_exotic_define_own_property,
__get__: arguments_exotic_get,
__set__: arguments_exotic_set,
__delete__: arguments_exotic_delete,
..ORDINARY_INTERNAL_METHODS
};
pub(crate) fn arguments_exotic_get_own_property(
obj: &JsObject,
key: &PropertyKey,
context: &mut Context<'_>,
) -> JsResult<Option<PropertyDescriptor>> {
let Some(desc) = super::ordinary_get_own_property(obj, key, context)? else {
return Ok(None);
};
if let PropertyKey::Index(index) = key {
if let Some(value) = obj
.borrow()
.as_mapped_arguments()
.expect("arguments exotic method must only be callable from arguments objects")
.get(*index)
{
return Ok(Some(
PropertyDescriptor::builder()
.value(value)
.maybe_writable(desc.writable())
.maybe_enumerable(desc.enumerable())
.maybe_configurable(desc.configurable())
.build(),
));
}
}
Ok(Some(desc))
}
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn arguments_exotic_define_own_property(
obj: &JsObject,
key: &PropertyKey,
desc: PropertyDescriptor,
context: &mut Context<'_>,
) -> JsResult<bool> {
let mapped = if let &PropertyKey::Index(index) = key {
obj.borrow()
.as_mapped_arguments()
.expect("arguments exotic method must only be callable from arguments objects")
.get(index)
.map(|value| (index, value))
} else {
None
};
let new_arg_desc = match desc.kind() {
DescriptorKind::Data {
writable: Some(false),
value: None,
} =>
{
if let Some((_, value)) = &mapped {
PropertyDescriptor::builder()
.value(value.clone())
.writable(false)
.maybe_enumerable(desc.enumerable())
.maybe_configurable(desc.configurable())
.build()
} else {
desc.clone()
}
}
_ => desc.clone(),
};
if !super::ordinary_define_own_property(obj, key, new_arg_desc, context)? {
return Ok(false);
}
if let Some((index, _)) = mapped {
let mut obj_mut = obj.borrow_mut();
let map = obj_mut
.as_mapped_arguments_mut()
.expect("arguments exotic method must only be callable from arguments objects");
if desc.is_accessor_descriptor() {
map.delete(index);
}
else {
if let Some(value) = desc.value() {
map.set(index, value);
}
if desc.writable() == Some(false) {
map.delete(index);
}
}
}
Ok(true)
}
pub(crate) fn arguments_exotic_get(
obj: &JsObject,
key: &PropertyKey,
receiver: JsValue,
context: &mut Context<'_>,
) -> JsResult<JsValue> {
if let PropertyKey::Index(index) = key {
if let Some(value) = obj
.borrow()
.as_mapped_arguments()
.expect("arguments exotic method must only be callable from arguments objects")
.get(*index)
{
return Ok(value);
}
}
super::ordinary_get(obj, key, receiver, context)
}
pub(crate) fn arguments_exotic_set(
obj: &JsObject,
key: PropertyKey,
value: JsValue,
receiver: JsValue,
context: &mut Context<'_>,
) -> JsResult<bool> {
if let PropertyKey::Index(index) = key {
if JsValue::same_value(&obj.clone().into(), &receiver) {
obj.borrow_mut()
.as_mapped_arguments_mut()
.expect("arguments exotic method must only be callable from arguments objects")
.set(index, &value);
}
}
super::ordinary_set(obj, key, value, receiver, context)
}
pub(crate) fn arguments_exotic_delete(
obj: &JsObject,
key: &PropertyKey,
context: &mut Context<'_>,
) -> JsResult<bool> {
let result = super::ordinary_delete(obj, key, context)?;
if result {
if let PropertyKey::Index(index) = key {
obj.borrow_mut()
.as_mapped_arguments_mut()
.expect("arguments exotic method must only be callable from arguments objects")
.delete(*index);
}
}
Ok(result)
}