Replace most manual `Collect` impls with `#[derive(Collect)]`

* Replace most unsafe impls with Collect.
 * Switch to local gc-arena fork.
This commit is contained in:
Aaron Hill 2021-02-17 21:38:55 -05:00 committed by GitHub
parent 809d0a9245
commit 6050dd8204
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 109 additions and 334 deletions

6
Cargo.lock generated
View File

@ -1395,8 +1395,7 @@ dependencies = [
[[package]]
name = "gc-arena"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7262a3f0bd866ed41d13f7a5147d5fe2278f6860aeab66bd72e9f2f770fc3e8"
source = "git+https://github.com/ruffle-rs/gc-arena#4931b3bc25b2b74174ff5eb9c34ae0dda732778b"
dependencies = [
"gc-arena-derive",
]
@ -1404,8 +1403,7 @@ dependencies = [
[[package]]
name = "gc-arena-derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5a1fd9d509709237f7673fe8fa4a2fcf8136bf5bd43b67bab6af267a9850524"
source = "git+https://github.com/ruffle-rs/gc-arena#4931b3bc25b2b74174ff5eb9c34ae0dda732778b"
dependencies = [
"proc-macro2",
"quote",

View File

@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
bitstream-io = "1.0.0"
flate2 = "1.0.20"
fnv = "1.0.7"
gc-arena = "0.2.0"
gc-arena-derive = "0.2.0"
gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" }
gc-arena-derive = { git = "https://github.com/ruffle-rs/gc-arena" }
generational-arena = "0.2.8"
gif = "0.11.1"
indexmap = "1.6.1"

View File

@ -2,7 +2,7 @@ use crate::avm1::globals::create_globals;
use crate::avm1::object::{search_prototype, stage_object};
use crate::context::UpdateContext;
use crate::prelude::*;
use gc_arena::{GcCell, MutationContext};
use gc_arena::{Collect, GcCell, MutationContext};
use swf::avm1::read::Reader;
@ -76,6 +76,8 @@ macro_rules! avm_error {
)
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct Avm1<'gc> {
/// The Flash Player version we're emulating.
player_version: u8,
@ -119,22 +121,6 @@ pub struct Avm1<'gc> {
pub debug_output: bool,
}
unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.globals.trace(cc);
self.constant_pool.trace(cc);
//self.system_listeners.trace(cc);
self.prototypes.trace(cc);
self.display_properties.trace(cc);
self.stack.trace(cc);
for register in &self.registers {
register.trace(cc);
}
}
}
impl<'gc> Avm1<'gc> {
pub fn new(gc_context: MutationContext<'gc, '_>, player_version: u8) -> Self {
let (prototypes, globals, broadcaster_functions) = create_globals(gc_context);

View File

@ -77,18 +77,13 @@ macro_rules! implement_utc_getters {
};
}
#[derive(Collect)]
#[collect(require_static)]
enum YearType {
Full,
Adjust(Box<dyn Fn(i64) -> i64>),
}
unsafe impl Collect for YearType {
#[inline]
fn needs_trace() -> bool {
false
}
}
impl YearType {
fn adjust(&self, year: i64) -> i64 {
match self {

View File

@ -10,20 +10,17 @@ use std::fmt;
#[collect(no_drop)]
pub struct DateObject<'gc>(GcCell<'gc, DateObjectData<'gc>>);
#[derive(Collect)]
#[collect(no_drop)]
pub struct DateObjectData<'gc> {
/// The underlying script object.
base: ScriptObject<'gc>,
/// The DateTime represented by this object
#[collect(require_static)]
date_time: Option<DateTime<Utc>>,
}
unsafe impl<'gc> Collect for DateObjectData<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
self.base.trace(cc);
}
}
impl fmt::Debug for DateObject<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let this = self.0.read();

View File

@ -72,6 +72,8 @@ impl<'gc> Watcher<'gc> {
#[collect(no_drop)]
pub struct ScriptObject<'gc>(GcCell<'gc, ScriptObjectData<'gc>>);
#[derive(Collect)]
#[collect(no_drop)]
pub struct ScriptObjectData<'gc> {
prototype: Option<Object<'gc>>,
values: PropertyMap<Property<'gc>>,
@ -81,16 +83,6 @@ pub struct ScriptObjectData<'gc> {
watchers: PropertyMap<Watcher<'gc>>,
}
unsafe impl<'gc> Collect for ScriptObjectData<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
self.prototype.trace(cc);
self.values.trace(cc);
self.array.trace(cc);
self.interfaces.trace(cc);
self.watchers.trace(cc);
}
}
impl fmt::Debug for ScriptObjectData<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Object")

View File

@ -14,6 +14,8 @@ use std::fmt;
#[collect(no_drop)]
pub struct SoundObject<'gc>(GcCell<'gc, SoundObjectData<'gc>>);
#[derive(Collect)]
#[collect(no_drop)]
pub struct SoundObjectData<'gc> {
/// The underlying script object.
///
@ -22,9 +24,11 @@ pub struct SoundObjectData<'gc> {
base: ScriptObject<'gc>,
/// The sound that is attached to this object.
#[collect(require_static)]
sound: Option<SoundHandle>,
/// The instance of the last played sound on this object.
#[collect(require_static)]
sound_instance: Option<SoundInstanceHandle>,
/// Sounds in AVM1 are tied to a specific movie clip.
@ -37,13 +41,6 @@ pub struct SoundObjectData<'gc> {
duration: u32,
}
unsafe impl<'gc> Collect for SoundObjectData<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
self.base.trace(cc);
self.owner.trace(cc);
}
}
impl fmt::Debug for SoundObject<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let this = self.0.read();

View File

@ -4,10 +4,13 @@ use crate::avm1::object::Object;
use crate::avm1::Value;
use bitflags::bitflags;
use core::fmt;
use gc_arena::Collect;
bitflags! {
/// Attributes of properties in the AVM runtime.
/// The values are significant and should match the order used by `object::as_set_prop_flags`.
#[derive(Collect)]
#[collect(require_static)]
pub struct Attribute: u8 {
const DONT_ENUM = 1 << 0;
const DONT_DELETE = 1 << 1;
@ -16,7 +19,8 @@ bitflags! {
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub enum Property<'gc> {
Virtual {
get: Object<'gc>,
@ -108,18 +112,6 @@ impl<'gc> Property<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for Property<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
match self {
Property::Virtual { get, set, .. } => {
get.trace(cc);
set.trace(cc);
}
Property::Stored { value, .. } => value.trace(cc),
}
}
}
impl fmt::Debug for Property<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {

View File

@ -5,11 +5,12 @@ use crate::avm1::callable_value::CallableValue;
use crate::avm1::error::Error;
use crate::avm1::property::Attribute;
use crate::avm1::{Object, ScriptObject, TObject, Value};
use gc_arena::{GcCell, MutationContext};
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::Ref;
/// Indicates what kind of scope a scope is.
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Collect)]
#[collect(require_static)]
pub enum ScopeClass {
/// Scope represents global scope.
Global,
@ -28,21 +29,14 @@ pub enum ScopeClass {
}
/// Represents a scope chain for an AVM1 activation.
#[derive(Debug)]
#[derive(Debug, Collect)]
#[collect(no_drop)]
pub struct Scope<'gc> {
parent: Option<GcCell<'gc, Scope<'gc>>>,
class: ScopeClass,
values: Object<'gc>,
}
unsafe impl<'gc> gc_arena::Collect for Scope<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.parent.trace(cc);
self.values.trace(cc);
}
}
impl<'gc> Scope<'gc> {
/// Construct a global scope (one without a parent).
pub fn from_global_object(globals: Object<'gc>) -> Scope<'gc> {

View File

@ -6,9 +6,11 @@ use crate::ecma_conversions::{
f64_to_string, f64_to_wrapping_i16, f64_to_wrapping_i32, f64_to_wrapping_u16,
f64_to_wrapping_u32,
};
use gc_arena::Collect;
use std::borrow::Cow;
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Collect)]
#[collect(no_drop)]
#[allow(dead_code)]
pub enum Value<'gc> {
Undefined,
@ -94,16 +96,6 @@ impl<'gc> From<usize> for Value<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for Value<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
match self {
Value::String(string) => string.trace(cc),
Value::Object(object) => object.trace(cc),
_ => {}
}
}
}
impl PartialEq for Value<'_> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {

View File

@ -5,12 +5,14 @@ use crate::avm2::return_value::ReturnValue;
use crate::avm2::value::Value;
use crate::avm2::Error;
use bitflags::bitflags;
use gc_arena::{Collect, CollectionContext};
use gc_arena::Collect;
bitflags! {
/// Attributes of properties in the AVM runtime.
///
/// TODO: Replace with AVM2 properties for traits
#[derive(Collect)]
#[collect(require_static)]
pub struct Attribute: u8 {
const DONT_DELETE = 1 << 0;
const READ_ONLY = 1 << 1;
@ -18,7 +20,8 @@ bitflags! {
}
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub enum Property<'gc> {
Virtual {
get: Option<Object<'gc>>,
@ -35,19 +38,6 @@ pub enum Property<'gc> {
},
}
unsafe impl<'gc> Collect for Property<'gc> {
fn trace(&self, cc: CollectionContext) {
match self {
Property::Virtual { get, set, .. } => {
get.trace(cc);
set.trace(cc);
}
Property::Stored { value, .. } => value.trace(cc),
Property::Slot { .. } => {}
}
}
}
impl<'gc> Property<'gc> {
/// Create a new stored property.
pub fn new_stored(value: impl Into<Value<'gc>>) -> Self {

View File

@ -3,10 +3,11 @@
use crate::avm2::property::Attribute;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::{Collect, CollectionContext};
use gc_arena::Collect;
/// Represents a single slot on an object.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub enum Slot<'gc> {
/// An unoccupied slot.
///
@ -23,15 +24,6 @@ pub enum Slot<'gc> {
},
}
unsafe impl<'gc> Collect for Slot<'gc> {
fn trace(&self, cc: CollectionContext) {
match self {
Self::Unoccupied => {}
Self::Occupied { value, .. } => value.trace(cc),
}
}
}
impl<'gc> Default for Slot<'gc> {
fn default() -> Self {
Self::Unoccupied

View File

@ -6,7 +6,7 @@ use crate::{
},
};
use downcast_rs::Downcast;
use gc_arena::{Collect, CollectionContext};
use gc_arena::Collect;
use generational_arena::{Arena, Index};
pub mod decoders;
@ -165,6 +165,8 @@ impl Default for NullAudioBackend {
}
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct AudioManager<'gc> {
/// The list of actively playing sounds.
sounds: Vec<SoundInstance<'gc>>,
@ -370,20 +372,16 @@ impl<'gc> Default for AudioManager<'gc> {
}
}
unsafe impl<'gc> Collect for AudioManager<'gc> {
fn trace(&self, cc: CollectionContext) {
for sound in &self.sounds {
sound.trace(cc);
}
}
}
#[derive(Clone)]
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub struct SoundInstance<'gc> {
/// The handle to the sound instance in the audio backend.
#[collect(require_static)]
instance: SoundInstanceHandle,
/// The handle to the sound definition in the audio backend.
/// This will be `None` for stream sounds.
#[collect(require_static)]
sound: Option<SoundHandle>,
/// The display object that this sound is playing in, if any.
@ -394,13 +392,6 @@ pub struct SoundInstance<'gc> {
pub avm1_object: Option<SoundObject<'gc>>,
}
unsafe impl<'gc> Collect for SoundInstance<'gc> {
fn trace(&self, cc: CollectionContext) {
self.display_object.trace(cc);
self.avm1_object.trace(cc);
}
}
/// A sound transform for a playing sound, for use by audio backends.
/// This differs from `display_object::SoundTranform` by being
/// already converted to `f32` and having `volume` baked in.

View File

@ -3,8 +3,10 @@ use crate::display_object::{
Bitmap, Button, EditText, Graphic, MorphShape, MovieClip, Text, Video,
};
use crate::font::Font;
use gc_arena::Collect;
#[derive(Clone)]
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub enum Character<'gc> {
EditText(EditText<'gc>),
Graphic(Graphic<'gc>),
@ -14,24 +16,6 @@ pub enum Character<'gc> {
Font(Font<'gc>),
MorphShape(MorphShape<'gc>),
Text(Text<'gc>),
Sound(SoundHandle),
Sound(#[collect(require_static)] SoundHandle),
Video(Video<'gc>),
}
unsafe impl<'gc> gc_arena::Collect for Character<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
match self {
Character::EditText(c) => c.trace(cc),
Character::Graphic(c) => c.trace(cc),
Character::MovieClip(c) => c.trace(cc),
Character::Bitmap(c) => c.trace(cc),
Character::Button(c) => c.trace(cc),
Character::Font(c) => c.trace(cc),
Character::MorphShape(c) => c.trace(cc),
Character::Text(c) => c.trace(cc),
Character::Sound(c) => c.trace(cc),
Character::Video(c) => c.trace(cc),
}
}
}

View File

@ -291,6 +291,8 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
}
/// A queued ActionScript call.
#[derive(Collect)]
#[collect(no_drop)]
pub struct QueuedActions<'gc> {
/// The movie clip this ActionScript is running on.
pub clip: DisplayObject<'gc>,
@ -302,14 +304,6 @@ pub struct QueuedActions<'gc> {
pub is_unload: bool,
}
unsafe impl<'gc> Collect for QueuedActions<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.clip.trace(cc);
self.action_type.trace(cc);
}
}
/// Action and gotos need to be queued up to execute at the end of the frame.
pub struct ActionQueue<'gc> {
/// Each priority is kept in a separate bucket.
@ -400,7 +394,8 @@ pub struct RenderContext<'a, 'gc> {
}
/// The type of action being run.
#[derive(Clone)]
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub enum ActionType<'gc> {
/// Normal frame or event actions.
Normal { bytecode: SwfSlice },
@ -494,22 +489,3 @@ impl fmt::Debug for ActionType<'_> {
}
}
}
unsafe impl<'gc> Collect for ActionType<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
match self {
ActionType::Construct { constructor, .. } => {
constructor.trace(cc);
}
ActionType::Method { object, args, .. } => {
object.trace(cc);
args.trace(cc);
}
ActionType::NotifyListeners { args, .. } => {
args.trace(cc);
}
_ => {}
}
}
}

View File

@ -42,7 +42,8 @@ pub use movie_clip::{MovieClip, Scene};
pub use text::Text;
pub use video::Video;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct DisplayObjectBase<'gc> {
parent: Option<DisplayObject<'gc>>,
place_frame: u16,
@ -105,17 +106,6 @@ impl<'gc> Default for DisplayObjectBase<'gc> {
}
}
unsafe impl<'gc> Collect for DisplayObjectBase<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.parent.trace(cc);
self.prev_sibling.trace(cc);
self.next_sibling.trace(cc);
self.masker.trace(cc);
self.maskee.trace(cc);
}
}
#[allow(dead_code)]
impl<'gc> DisplayObjectBase<'gc> {
/// Reset all properties that would be adjusted by a movie load.
@ -1491,7 +1481,8 @@ bitflags! {
/// Every value is a percentage (0-100), but out of range values are allowed.
/// In AVM1, this is returned by `Sound.getTransform`.
/// In AVM2, this is returned by `Sprite.soundTransform`.
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Eq, Clone, Collect)]
#[collect(require_static)]
pub struct SoundTransform {
pub volume: i32,
pub left_to_left: i32,

View File

@ -18,7 +18,8 @@ use swf::ButtonActionCondition;
#[collect(no_drop)]
pub struct Button<'gc>(GcCell<'gc, ButtonData<'gc>>);
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct ButtonData<'gc> {
base: DisplayObjectBase<'gc>,
static_data: GcCell<'gc, ButtonStatic>,
@ -567,20 +568,8 @@ impl<'gc> ButtonData<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for ButtonData<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.container.trace(cc);
for child in self.hit_area.values() {
child.trace(cc);
}
self.base.trace(cc);
self.static_data.trace(cc);
self.object.trace(cc);
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Collect)]
#[collect(require_static)]
#[allow(dead_code)]
enum ButtonState {
Up,
@ -595,7 +584,8 @@ struct ButtonAction {
key_code: Option<ButtonKeyCode>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Collect)]
#[collect(require_static)]
enum ButtonTracking {
Push,
Menu,
@ -603,7 +593,8 @@ enum ButtonTracking {
/// Static data shared between all instances of a button.
#[allow(dead_code)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
struct ButtonStatic {
swf: Arc<SwfMovie>,
id: CharacterId,
@ -616,10 +607,3 @@ struct ButtonStatic {
down_to_over_sound: Option<swf::ButtonSound>,
over_to_up_sound: Option<swf::ButtonSound>,
}
unsafe impl gc_arena::Collect for ButtonStatic {
#[inline]
fn needs_trace() -> bool {
false
}
}

View File

@ -1625,7 +1625,8 @@ struct EditTextStatic {
swf: Arc<SwfMovie>,
text: EditTextStaticData,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Collect)]
#[collect(require_static)]
struct EditTextStaticData {
id: CharacterId,
bounds: swf::Rectangle,
@ -1649,25 +1650,13 @@ struct EditTextStaticData {
is_device_font: bool,
}
unsafe impl<'gc> Collect for EditTextStaticData {
fn needs_trace() -> bool {
false
}
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Collect)]
#[collect(require_static)]
pub struct TextSelection {
from: usize,
to: usize,
}
unsafe impl Collect for TextSelection {
#[inline]
fn needs_trace() -> bool {
false
}
}
impl TextSelection {
pub fn for_position(position: usize) -> Self {
Self {

View File

@ -11,7 +11,8 @@ use std::sync::Arc;
#[collect(no_drop)]
pub struct Graphic<'gc>(GcCell<'gc, GraphicData<'gc>>);
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct GraphicData<'gc> {
base: DisplayObjectBase<'gc>,
static_data: gc_arena::Gc<'gc, GraphicStatic>,
@ -97,25 +98,13 @@ impl<'gc> TDisplayObject<'gc> for Graphic<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for GraphicData<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
self.base.trace(cc);
self.static_data.trace(cc);
}
}
/// Static data shared between all instances of a graphic.
#[allow(dead_code)]
#[derive(Collect)]
#[collect(require_static)]
struct GraphicStatic {
id: CharacterId,
shape: swf::Shape,
render_handle: ShapeHandle,
bounds: BoundingBox,
}
unsafe impl<'gc> gc_arena::Collect for GraphicStatic {
#[inline]
fn needs_trace() -> bool {
false
}
}

View File

@ -12,7 +12,8 @@ use swf::Twips;
#[collect(no_drop)]
pub struct MorphShape<'gc>(GcCell<'gc, MorphShapeData<'gc>>);
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct MorphShapeData<'gc> {
base: DisplayObjectBase<'gc>,
static_data: Gc<'gc, MorphShapeStatic>,
@ -96,14 +97,6 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for MorphShapeData<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.base.trace(cc);
self.static_data.trace(cc);
}
}
/// A precalculated intermediate frame for a morph shape.
struct Frame {
shape_handle: ShapeHandle,
@ -113,6 +106,8 @@ struct Frame {
/// Static data shared between all instances of a morph shape.
#[allow(dead_code)]
#[derive(Collect)]
#[collect(require_static)]
pub struct MorphShapeStatic {
id: CharacterId,
start: swf::MorphShape,
@ -307,13 +302,6 @@ impl MorphShapeStatic {
}
}
unsafe impl<'gc> gc_arena::Collect for MorphShapeStatic {
#[inline]
fn needs_trace() -> bool {
false
}
}
// Interpolation functions
// These interpolate between two SWF shape structures.
// a + b should = 1.0

View File

@ -47,12 +47,14 @@ type FrameNumber = u16;
#[collect(no_drop)]
pub struct MovieClip<'gc>(GcCell<'gc, MovieClipData<'gc>>);
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct MovieClipData<'gc> {
base: DisplayObjectBase<'gc>,
static_data: Gc<'gc, MovieClipStatic>,
tag_stream_pos: u64,
current_frame: FrameNumber,
#[collect(require_static)]
audio_stream: Option<SoundInstanceHandle>,
container: ChildContainer<'gc>,
object: Option<AvmObject<'gc>>,
@ -68,18 +70,6 @@ pub struct MovieClipData<'gc> {
use_hand_cursor: bool,
}
unsafe impl<'gc> Collect for MovieClipData<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.container.trace(cc);
self.base.trace(cc);
self.static_data.trace(cc);
self.object.trace(cc);
self.avm2_constructor.trace(cc);
self.frame_scripts.trace(cc);
}
}
impl<'gc> MovieClip<'gc> {
#[allow(dead_code)]
pub fn new(swf: SwfSlice, gc_context: MutationContext<'gc, '_>) -> Self {
@ -3204,6 +3194,8 @@ impl<'a> GotoPlaceObject<'a> {
bitflags! {
/// Boolean state flags used by `MovieClip`.
#[derive(Collect)]
#[collect(require_static)]
struct MovieClipFlags: u8 {
/// Whether this `MovieClip` has run its initial frame.
const INITIALIZED = 1 << 0;
@ -3221,7 +3213,8 @@ bitflags! {
/// Actions that are attached to a `MovieClip` event in
/// an `onClipEvent`/`on` handler.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Collect)]
#[collect(require_static)]
pub struct ClipAction {
/// The event that triggers this handler.
event: ClipEvent,

View File

@ -12,7 +12,8 @@ use std::sync::Arc;
#[collect(no_drop)]
pub struct Text<'gc>(GcCell<'gc, TextData<'gc>>);
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(no_drop)]
pub struct TextData<'gc> {
base: DisplayObjectBase<'gc>,
static_data: gc_arena::Gc<'gc, TextStatic>,
@ -194,17 +195,10 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
}
}
unsafe impl<'gc> gc_arena::Collect for TextData<'gc> {
#[inline]
fn trace(&self, cc: gc_arena::CollectionContext) {
self.base.trace(cc);
self.static_data.trace(cc);
}
}
/// Static data shared between all instances of a text object.
#[allow(dead_code)]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Collect)]
#[collect(require_static)]
struct TextStatic {
swf: Arc<SwfMovie>,
id: CharacterId,
@ -212,10 +206,3 @@ struct TextStatic {
text_transform: Matrix,
text_blocks: Vec<swf::TextRecord>,
}
unsafe impl<'gc> gc_arena::Collect for TextStatic {
#[inline]
fn needs_trace() -> bool {
false
}
}

View File

@ -7,7 +7,7 @@ use crate::avm1::{
AvmString as Avm1String, Object as Avm1Object, ScriptObject as Avm1ScriptObject,
};
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext};
use gc_arena::Collect;
use std::collections::BTreeMap;
/// An intermediate format of representing shared data between ActionScript and elsewhere.
@ -252,19 +252,14 @@ where
}
}
#[derive(Default)]
#[derive(Default, Collect)]
#[collect(no_drop)]
pub struct ExternalInterface<'gc> {
#[collect(require_static)]
providers: Vec<Box<dyn ExternalInterfaceProvider>>,
callbacks: BTreeMap<String, Callback<'gc>>,
}
unsafe impl Collect for ExternalInterface<'_> {
#[inline]
fn trace(&self, cc: CollectionContext) {
self.callbacks.trace(cc);
}
}
impl<'gc> ExternalInterface<'gc> {
pub fn new() -> Self {
Self::default()

View File

@ -259,7 +259,8 @@ impl<'gc> Default for LoadManager<'gc> {
}
/// The completion status of a `Loader` loading a movie.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Collect)]
#[collect(require_static)]
pub enum LoaderStatus {
/// The movie hasn't been loaded yet.
Pending,
@ -270,16 +271,20 @@ pub enum LoaderStatus {
}
/// A struct that holds garbage-collected pointers for asynchronous code.
#[derive(Collect)]
#[collect(no_drop)]
pub enum Loader<'gc> {
/// Loader that is loading the root movie of a player.
RootMovie {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<Handle>,
},
/// Loader that is loading a new movie into a movieclip.
Movie {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<Handle>,
/// The target movie clip to load the movie into.
@ -303,6 +308,7 @@ pub enum Loader<'gc> {
/// Loader that is loading form data into an AVM1 object scope.
Form {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<Handle>,
/// The target AVM1 object to load form data into.
@ -312,6 +318,7 @@ pub enum Loader<'gc> {
/// Loader that is loading form data into an AVM1 LoadVars object.
LoadVars {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<Handle>,
/// The target AVM1 object to load form data into.
@ -321,6 +328,7 @@ pub enum Loader<'gc> {
/// Loader that is loading XML data into an XML tree.
Xml {
/// The handle to refer to this loader instance.
#[collect(require_static)]
self_handle: Option<Handle>,
/// The active movie clip at the time of load invocation.
@ -336,25 +344,6 @@ pub enum Loader<'gc> {
},
}
unsafe impl<'gc> Collect for Loader<'gc> {
fn trace(&self, cc: CollectionContext) {
match self {
Loader::RootMovie { .. } => {}
Loader::Movie {
target_clip,
target_broadcaster,
..
} => {
target_clip.trace(cc);
target_broadcaster.trace(cc);
}
Loader::Form { target_object, .. } => target_object.trace(cc),
Loader::LoadVars { target_object, .. } => target_object.trace(cc),
Loader::Xml { target_node, .. } => target_node.trace(cc),
}
}
}
impl<'gc> Loader<'gc> {
/// Set the loader handle for this loader.
///

View File

@ -1491,19 +1491,17 @@ impl Player {
}
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct DragObject<'gc> {
/// The display object being dragged.
pub display_object: DisplayObject<'gc>,
/// The offset from the mouse position to the center of the clip.
#[collect(require_static)]
pub offset: (Twips, Twips),
/// The bounding rectangle where the clip will be maintained.
#[collect(require_static)]
pub constraint: BoundingBox,
}
unsafe impl<'gc> gc_arena::Collect for DragObject<'gc> {
fn trace(&self, cc: gc_arena::CollectionContext) {
self.display_object.trace(cc);
}
}

View File

@ -1,6 +1,6 @@
//! Error types used in XML handling
use gc_arena::{Collect, CollectionContext};
use gc_arena::Collect;
use quick_xml::Error as QXError;
use std::error::Error as StdError;
use std::fmt::Error as FmtError;
@ -77,14 +77,10 @@ impl From<QXError> for Error {
/// We can't clone `quick_xml` errors, nor can we clone several of the error
/// types it wraps over, so this creates an RC boxed version of the error that
/// can then be used elsewhere.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
pub struct ParseError(Rc<QXError>);
unsafe impl Collect for ParseError {
/// ParseError does not contain GC pointers.
fn trace(&self, _cc: CollectionContext<'_>) {}
}
impl ParseError {
///Convert a quick_xml error into a `ParseError`.
pub fn from_quickxml_error(err: QXError) -> Self {