2020-07-21 04:24:02 +00:00
|
|
|
//! Any-AVM object references
|
|
|
|
|
|
|
|
use crate::avm1::Object as Avm1Object;
|
|
|
|
use crate::avm2::Object as Avm2Object;
|
|
|
|
use gc_arena::Collect;
|
|
|
|
|
|
|
|
/// The VM (or lack thereof) that created a given object.
|
|
|
|
///
|
|
|
|
/// This primary purpose of this type is to communicate if a movie clip is
|
|
|
|
/// being created on an AVM stack, and if so, which type. If it is on-stack,
|
|
|
|
/// then it needs to be constructed immediately before user code can continue
|
2020-11-11 09:55:46 +00:00
|
|
|
/// running. Otherwise, its constructor should be queued to run later.
|
2020-07-21 04:24:02 +00:00
|
|
|
///
|
|
|
|
/// A secondary purpose of this type is to flag which VM is creating an object,
|
|
|
|
/// which can be used to ensure the object is instantiated as tied to the
|
|
|
|
/// correct VM.
|
|
|
|
#[derive(Copy, Clone, Debug, Collect)]
|
|
|
|
#[collect(require_static)]
|
|
|
|
pub enum Instantiator {
|
|
|
|
/// This object was instantiated by a tag in a given SWF movie, or by a VM
|
|
|
|
/// action which does not implicitly instantiate a given object. Acceptable
|
|
|
|
/// situations in which one might flag a VM action as movie-triggered
|
|
|
|
/// includes:
|
|
|
|
///
|
|
|
|
/// * When the object instantiation is a side effect of the command (e.g.
|
|
|
|
/// `ActionGoto` needs to recreate movie clips that fell off the
|
|
|
|
/// timeline)
|
|
|
|
/// * When the VM is creating objects that it does not expect to have a
|
|
|
|
/// custom constructor for. (e.g. top-level movie layers that it needs
|
|
|
|
/// to load into)
|
|
|
|
///
|
|
|
|
/// TODO: This should actually link the movie so we can inspect it for a
|
|
|
|
/// file attributes tag.
|
|
|
|
Movie,
|
|
|
|
|
|
|
|
/// This object was instantiated by AVM1 code constructing the object. All
|
|
|
|
/// objects should be created as AVM1 objects and any custom constructors
|
|
|
|
/// should resolve on-stack.
|
|
|
|
Avm1,
|
|
|
|
|
|
|
|
/// This object was instantiated by AVM2 code constructing the object. All
|
|
|
|
/// objects should be created as AVM1 objects and any custom constructors
|
|
|
|
/// should resolve on-stack.
|
|
|
|
Avm2,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Instantiator {
|
|
|
|
/// Returns true if the instantiation happened on an AVM stack (either kind).
|
|
|
|
///
|
|
|
|
/// If that is the case, then any constructor calls necessary to finish the
|
|
|
|
/// object must happen on-stack.
|
|
|
|
pub fn is_avm(self) -> bool {
|
2020-11-09 09:52:39 +00:00
|
|
|
matches!(self, Self::Avm1 | Self::Avm2)
|
2020-07-21 04:24:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 20:39:59 +00:00
|
|
|
impl From<Instantiator> for Option<AvmType> {
|
|
|
|
fn from(instantiator: Instantiator) -> Option<AvmType> {
|
|
|
|
match instantiator {
|
|
|
|
Instantiator::Avm1 => Some(AvmType::Avm1),
|
|
|
|
Instantiator::Avm2 => Some(AvmType::Avm2),
|
2020-08-08 00:39:15 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-21 04:24:02 +00:00
|
|
|
/// Represents an error generated due to a failure to convert or claim an
|
|
|
|
/// object for a given VM.
|
|
|
|
#[derive(Copy, Clone, Debug, Collect)]
|
|
|
|
#[collect(require_static)]
|
|
|
|
pub struct ClaimError();
|
|
|
|
|
2020-08-07 02:46:53 +00:00
|
|
|
/// Denotes an AVM type.
|
|
|
|
#[derive(Copy, Clone, Debug, Collect, PartialEq, Eq)]
|
|
|
|
#[collect(no_drop)]
|
|
|
|
pub enum AvmType {
|
|
|
|
Avm1,
|
|
|
|
Avm2,
|
|
|
|
}
|
|
|
|
|
2020-08-08 00:39:15 +00:00
|
|
|
impl From<AvmObject<'_>> for AvmType {
|
|
|
|
fn from(vmo: AvmObject<'_>) -> Self {
|
|
|
|
match vmo {
|
|
|
|
AvmObject::Avm1(_) => AvmType::Avm1,
|
|
|
|
AvmObject::Avm2(_) => AvmType::Avm2,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-20 03:12:45 +00:00
|
|
|
impl AvmType {
|
|
|
|
pub fn into_avm2_loader_version(self) -> u32 {
|
|
|
|
match self {
|
|
|
|
AvmType::Avm1 => 2,
|
|
|
|
AvmType::Avm2 => 3,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-21 04:24:02 +00:00
|
|
|
/// A reference to either an AVM1 or AVM2 object.
|
|
|
|
///
|
|
|
|
/// Used by non-AVM code to retain VM objects that may have been customized or
|
|
|
|
/// altered by user code. Non-AVM structures may be held by either VM, and thus
|
|
|
|
/// those structures must also hold the VM side of themselves as well.
|
|
|
|
///
|
|
|
|
/// This structure is specifically designed to only store one VM's
|
|
|
|
/// representation of the object. Objects cannot be shared across multiple VMs
|
|
|
|
/// and attempting to do so will generate a runtime error. Dual-representation
|
|
|
|
/// objects are prohibited.
|
|
|
|
#[derive(Copy, Clone, Debug, Collect)]
|
|
|
|
#[collect(no_drop)]
|
|
|
|
pub enum AvmObject<'gc> {
|
|
|
|
/// An object that is exclusively represented as an AVM1 object. Attempts
|
|
|
|
/// to access it from AVM2 will fail.
|
|
|
|
Avm1(Avm1Object<'gc>),
|
|
|
|
|
|
|
|
/// An object that is exclusively represented as an AVM2 object. Attempts
|
|
|
|
/// to access it from AVM1 will fail.
|
|
|
|
Avm2(Avm2Object<'gc>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'gc> AvmObject<'gc> {
|
|
|
|
/// Determine if this object is an AVM1 object.
|
|
|
|
pub fn is_avm1_object(&self) -> bool {
|
2021-03-30 20:18:18 +00:00
|
|
|
matches!(self, Self::Avm1(_))
|
2020-07-21 04:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Attempt to access the AVM1 claim to this object, generating an error if
|
|
|
|
/// the object cannot be accessed by the VM.
|
|
|
|
pub fn as_avm1_object(&self) -> Result<Avm1Object<'gc>, ClaimError> {
|
|
|
|
match self {
|
|
|
|
Self::Avm1(o) => Ok(*o),
|
|
|
|
Self::Avm2(_) => Err(ClaimError()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Determine if this object is an AVM2 object.
|
|
|
|
pub fn is_avm2_object(&self) -> bool {
|
2021-03-30 20:18:18 +00:00
|
|
|
matches!(self, Self::Avm2(_))
|
2020-07-21 04:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Attempt to access the AVM2 claim to this object, generating an error if
|
|
|
|
/// the object cannot be accessed by the VM.
|
|
|
|
pub fn as_avm2_object(&self) -> Result<Avm2Object<'gc>, ClaimError> {
|
|
|
|
match self {
|
|
|
|
Self::Avm1(_) => Err(ClaimError()),
|
|
|
|
Self::Avm2(o) => Ok(*o),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'gc> From<Avm1Object<'gc>> for AvmObject<'gc> {
|
|
|
|
fn from(t: Avm1Object<'gc>) -> Self {
|
|
|
|
Self::Avm1(t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'gc> From<Avm2Object<'gc>> for AvmObject<'gc> {
|
|
|
|
fn from(t: Avm2Object<'gc>) -> Self {
|
|
|
|
Self::Avm2(t)
|
|
|
|
}
|
|
|
|
}
|