ruffle/core/src/avm2/script_object.rs

119 lines
3.0 KiB
Rust
Raw Normal View History

//! Default AVM2 object impl
use crate::avm2::names::QName;
2020-02-10 19:54:55 +00:00
use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::return_value::ReturnValue;
use crate::avm2::value::Value;
use crate::avm2::{Avm2, Error};
use crate::context::UpdateContext;
2020-02-10 19:54:55 +00:00
use gc_arena::{Collect, GcCell, MutationContext};
use std::collections::HashMap;
use std::fmt::Debug;
/// Default implementation of `avm2::Object`.
#[derive(Clone, Collect, Debug, Copy)]
#[collect(no_drop)]
pub struct ScriptObject<'gc>(GcCell<'gc, ScriptObjectData<'gc>>);
#[derive(Clone, Collect, Debug)]
#[collect(no_drop)]
pub struct ScriptObjectData<'gc> {
/// Properties stored on this object.
values: HashMap<QName, Value<'gc>>,
2020-02-13 03:47:56 +00:00
/// Implicit prototype (or declared base class) of this script object.
proto: Option<Object<'gc>>,
}
impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn get_property(
self,
name: &QName,
avm: &mut Avm2<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> {
self.0.read().get_property(name, avm, context)
}
fn set_property(
self,
name: &QName,
value: Value<'gc>,
avm: &mut Avm2<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> {
self.0
.write(context.gc_context)
.set_property(name, value, avm, context)
}
2020-02-12 00:42:47 +00:00
fn has_property(self, name: &QName) -> bool {
self.0.read().has_property(name)
}
2020-02-13 03:47:56 +00:00
fn proto(&self) -> Option<Object<'gc>> {
self.0.read().proto
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
}
2020-02-10 19:54:55 +00:00
impl<'gc> ScriptObject<'gc> {
2020-02-13 03:47:56 +00:00
/// Construct a bare object with no base class.
///
/// This is *not* the same thing as an object literal, which actually does
/// have a base class: `Object`.
2020-02-10 19:54:55 +00:00
pub fn bare_object(mc: MutationContext<'gc, '_>) -> Object<'gc> {
ScriptObject(GcCell::allocate(
mc,
ScriptObjectData {
values: HashMap::new(),
2020-02-13 03:47:56 +00:00
proto: None,
2020-02-10 19:54:55 +00:00
},
))
.into()
}
}
impl<'gc> ScriptObjectData<'gc> {
pub fn get_property(
&self,
name: &QName,
avm: &mut Avm2<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> {
Ok(self
.values
.get(name)
.cloned()
.unwrap_or(Value::Undefined)
.into())
}
pub fn set_property(
&mut self,
name: &QName,
value: Value<'gc>,
avm: &mut Avm2<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> {
if let Some(slot) = self.values.get_mut(name) {
*slot = value;
} else {
self.values.insert(name.clone(), value);
}
Ok(())
}
2020-02-12 00:42:47 +00:00
pub fn has_property(&self, name: &QName) -> bool {
self.values.get(name).is_some()
}
2020-02-13 03:47:56 +00:00
pub fn proto(&self) -> Option<Object<'gc>> {
self.proto
}
}