WIP: use rcp for instances
diff --git a/include/rive/animation/linear_animation_instance.hpp b/include/rive/animation/linear_animation_instance.hpp
index 4c02e0b..b1ff906 100644
--- a/include/rive/animation/linear_animation_instance.hpp
+++ b/include/rive/animation/linear_animation_instance.hpp
@@ -19,7 +19,7 @@
         int m_LoopValue = -1;
 
     public:
-        LinearAnimationInstance(const LinearAnimation*, ArtboardInstance*);
+        LinearAnimationInstance(const LinearAnimation*, rcp<ArtboardInstance>);
 
         // Advance the animation by the specified time. Returns true if the
         // animation will continue to animate after this advance.
@@ -52,7 +52,7 @@
         // between 0 and 1) is the strength at which the animation is mixed with
         // other animations applied to the artboard.
         void apply(float mix = 1.0f) const {
-            m_Animation->apply(m_ArtboardInstance, m_Time, mix);
+            m_Animation->apply(m_ArtboardInstance.get(), m_Time, mix);
         }
 
         // Set when the animation is advanced, true if the animation has stopped
diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp
index fa8fe6f..16044a5 100644
--- a/include/rive/animation/state_machine_instance.hpp
+++ b/include/rive/animation/state_machine_instance.hpp
@@ -45,7 +45,7 @@
         InstType* getNamedInput(const std::string& name) const;
 
     public:
-        StateMachineInstance(const StateMachine* machine, ArtboardInstance* instance);
+        StateMachineInstance(const StateMachine* machine, rcp<ArtboardInstance>);
         ~StateMachineInstance() override;
 
         // Advance the state machine by the specified time. Returns true if the
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index f7cb07b..86fd8af 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -32,6 +32,7 @@
         friend class Component;
 
     private:
+        File* m_File;
         std::vector<Core*> m_Objects;
         std::vector<LinearAnimation*> m_Animations;
         std::vector<StateMachine*> m_StateMachines;
@@ -63,7 +64,7 @@
         void addNestedArtboard(NestedArtboard* object);
 
     public:
-        Artboard() {}
+        Artboard(File* file) : m_File(file) {}
         ~Artboard();
         StatusCode initialize();
 
@@ -158,9 +159,11 @@
         StatusCode import(ImportStack& importStack) override;
     };
 
-    class ArtboardInstance : public Artboard {
+    class ArtboardInstance : public Artboard, public RefCnt {
+        rcp<File> m_File;
+    
     public:
-        ArtboardInstance() {}
+        ArtboardInstance(rcp<File> file);
 
         std::unique_ptr<LinearAnimationInstance> animationAt(size_t index);
         std::unique_ptr<LinearAnimationInstance> animationNamed(const std::string& name);
diff --git a/include/rive/file.hpp b/include/rive/file.hpp
index 9d2ea3f..4fb579e 100644
--- a/include/rive/file.hpp
+++ b/include/rive/file.hpp
@@ -1,6 +1,7 @@
 #ifndef _RIVE_FILE_HPP_
 #define _RIVE_FILE_HPP_
 
+#include "rive/refcnt.hpp"
 #include "rive/artboard.hpp"
 #include "rive/backboard.hpp"
 #include "rive/factory.hpp"
@@ -30,7 +31,7 @@
     ///
     /// A Rive file.
     ///
-    class File {
+    class File : public RefCnt {
     public:
         /// Major version number supported by the runtime.
         static const int majorVersion = 7;
diff --git a/include/rive/refcnt.hpp b/include/rive/refcnt.hpp
index 67bbcfb..c61390a 100644
--- a/include/rive/refcnt.hpp
+++ b/include/rive/refcnt.hpp
@@ -161,6 +161,14 @@
         return a.get() != b.get();
     }
 
+    template <typename T> rcp<T> rive_ref_sp(T* obj) {
+        return rcp<T>(safe_ref(obj));
+    }
+
+    template <typename T> rcp<T> rive_ref_sp(const T* obj) {
+        return rcp<T>(const_cast<T*>(safe_ref(obj)));
+}
+
 } // namespace rive
 
 #endif
diff --git a/include/rive/scene.hpp b/include/rive/scene.hpp
index 90de466..58c2f17 100644
--- a/include/rive/scene.hpp
+++ b/include/rive/scene.hpp
@@ -1,6 +1,7 @@
 #ifndef _RIVE_SCENE_HPP_
 #define _RIVE_SCENE_HPP_
 
+#include "rive/refcnt.hpp"
 #include "rive/animation/loop.hpp"
 #include "rive/math/aabb.hpp"
 #include "rive/math/vec2d.hpp"
@@ -17,12 +18,12 @@
 
     class Scene {    
     protected:
-        ArtboardInstance* m_ArtboardInstance;
+        rcp<ArtboardInstance> m_ArtboardInstance;
 
-        Scene(ArtboardInstance*);
+        Scene(rcp<ArtboardInstance>);
 
     public:
-        virtual ~Scene() {}
+        virtual ~Scene();
     
         float width() const;
         float height() const;
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 0a099ba..8c501cc 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -7,6 +7,7 @@
 #include "rive/draw_target.hpp"
 #include "rive/draw_target_placement.hpp"
 #include "rive/drawable.hpp"
+#include "rive/file.hpp"
 #include "rive/animation/keyed_object.hpp"
 #include "rive/node.hpp"
 #include "rive/renderer.hpp"
@@ -522,7 +523,7 @@
 }
 
 std::unique_ptr<ArtboardInstance> Artboard::instance() const {
-    std::unique_ptr<ArtboardInstance> artboardClone(new ArtboardInstance);
+    std::unique_ptr<ArtboardInstance> artboardClone(new ArtboardInstance(rive_ref_sp(m_File)));
     artboardClone->copy(*this);
 
     artboardClone->m_Factory = m_Factory;
@@ -584,24 +585,29 @@
 #include "rive/animation/linear_animation_instance.hpp"
 #include "rive/animation/state_machine_instance.hpp"
 
+ArtboardInstance::ArtboardInstance(rcp<File> file) :
+    Artboard(file.get()),
+    m_File(std::move(file))
+{}
+
 std::unique_ptr<LinearAnimationInstance> ArtboardInstance::animationAt(size_t index) {
     auto la = this->animation(index);
-    return la ? std::make_unique<LinearAnimationInstance>(la, this) : nullptr;
+    return la ? std::make_unique<LinearAnimationInstance>(la, rive_ref_sp(this)) : nullptr;
 }
 
 std::unique_ptr<LinearAnimationInstance> ArtboardInstance::animationNamed(const std::string& name) {
     auto la = this->animation(name);
-    return la ? std::make_unique<LinearAnimationInstance>(la, this) : nullptr;
+    return la ? std::make_unique<LinearAnimationInstance>(la, rive_ref_sp(this)) : nullptr;
 }
 
 std::unique_ptr<StateMachineInstance> ArtboardInstance::stateMachineAt(size_t index) {
     auto sm = this->stateMachine(index);
-    return sm ? std::make_unique<StateMachineInstance>(sm, this) : nullptr;
+    return sm ? std::make_unique<StateMachineInstance>(sm, rive_ref_sp(this)) : nullptr;
 }
 
 std::unique_ptr<StateMachineInstance> ArtboardInstance::stateMachineNamed(const std::string& name) {
     auto sm = this->stateMachine(name);
-    return sm ? std::make_unique<StateMachineInstance>(sm, this) : nullptr;
+    return sm ? std::make_unique<StateMachineInstance>(sm, rive_ref_sp(this)) : nullptr;
 }
 
 std::unique_ptr<StateMachineInstance> ArtboardInstance::defaultStateMachine() {
diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp
index bbd543d..458b81d 100644
--- a/src/nested_artboard.cpp
+++ b/src/nested_artboard.cpp
@@ -1,6 +1,7 @@
 #include "rive/nested_artboard.hpp"
 #include "rive/artboard.hpp"
 #include "rive/backboard.hpp"
+#include "rive/file.hpp"
 #include "rive/importers/import_stack.hpp"
 #include "rive/importers/backboard_importer.hpp"
 #include "rive/nested_animation.hpp"
diff --git a/test/file_test.cpp b/test/file_test.cpp
index b8cd48b..1440881 100644
--- a/test/file_test.cpp
+++ b/test/file_test.cpp
@@ -124,6 +124,53 @@
     REQUIRE(artboard->objects().size() == 7);
 }
 
+const char* gRivFileNames[] = {
+    "blend_test.riv",
+    "bullet_man.riv",
+    "circle_clips.riv",
+    "complex_ik_dependency.riv",
+    "dependency_test.riv",
+    "distance_constraint.riv",
+    "draw_rule_cycle.riv",
+    "entry.riv",
+    "fix_rectangle.riv",
+    "juice.riv",
+    "light_switch.riv",
+    "long_name.riv",
+    "multiple_state_machines.riv",
+    "off_road_car.riv",
+    "out_of_band",
+    "rocket.riv",
+    "rotation_constraint.riv",
+    "scale_constraint.riv",
+    "shapetest.riv",
+    "stroke_name_test.riv",
+    "tape.riv",
+    "transform_constraint.riv",
+    "translation_constraint.riv",
+    "trim_path_linear.riv",
+    "two_artboards.riv",
+    "two_bone_ik.riv",
+    "walle.riv",
+};
+
+TEST_CASE("bookkeeping for files and artboard instances", "[file]") {
+    for (auto name : gRivFileNames) {
+        std::string path("../../test/assets/") + name;
+        auto file = ReadRiveFile(path.c_str());
+        auto abi = file->artboardAt(0);
+        file = nullptr; // unref the file, but abi should still be an owner
+
+        auto anim = abi->animationAt(0);
+        abi = nillptr;  // unref the artboardinstance, but anim should still be an owner
+        
+        anim->advanceAndApply(0);
+
+        rive::NoOpRenderer renderer;
+        anim->draw(&renderer);
+    }
+}
+
 // TODO:
 // ShapePaint (fill/stroke) needs to be implemented in WASM (jsFill/jsStroke) in
 // order to create Paint objects as necessary.
diff --git a/test/files.txt b/test/files.txt
new file mode 100644
index 0000000..9a44337
--- /dev/null
+++ b/test/files.txt
@@ -0,0 +1,27 @@
+blend_test.riv
+bullet_man.riv
+circle_clips.riv
+complex_ik_dependency.riv
+dependency_test.riv
+distance_constraint.riv
+draw_rule_cycle.riv
+entry.riv
+fix_rectangle.riv
+juice.riv
+light_switch.riv
+long_name.riv
+multiple_state_machines.riv
+off_road_car.riv
+out_of_band
+rocket.riv
+rotation_constraint.riv
+scale_constraint.riv
+shapetest.riv
+stroke_name_test.riv
+tape.riv
+transform_constraint.riv
+translation_constraint.riv
+trim_path_linear.riv
+two_artboards.riv
+two_bone_ik.riv
+walle.riv