diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 9194baa..8df267b 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -23,12 +23,19 @@ typedef std::shared_ptr(*InstanceConstructor)(); class DataModel; class Workspace; +typedef int InstanceFlags; +// This instance should only be instantiated in special circumstances (i.e. by DataModel) and should be creatable directly via any API +const InstanceFlags INSTANCE_NOTCREATABLE = (InstanceFlags)0x1; +// This instance is a service +const InstanceFlags INSTANCE_SERVICE = (InstanceFlags)0x2; + // Struct describing information about an instance struct InstanceType { const InstanceType* super; // May be null std::string className; InstanceConstructor constructor; std::string explorerIcon = ""; + InstanceFlags flags; }; class DescendantsIterator; diff --git a/core/src/objects/base/service.cpp b/core/src/objects/base/service.cpp index ecabbfb..3343569 100644 --- a/core/src/objects/base/service.cpp +++ b/core/src/objects/base/service.cpp @@ -1,9 +1,20 @@ #include "service.h" +#include "logger.h" +#include "panic.h" #include -Service::Service(const InstanceType* type, std::weak_ptr root) : Instance(type), dataModel(root) {} +Service::Service(const InstanceType* type) : Instance(type){} + +// Fail if parented to non-datamodel, otherwise lock parent +void Service::OnParentUpdated(std::optional> oldParent, std::optional> newParent) { + if (!newParent || newParent.value()->GetClass() != &DataModel::TYPE) { + Logger::fatalErrorf("Service %s was parented to object of type %s", GetClass()->className, newParent ? newParent.value()->GetClass()->className : "NULL"); + panic(); + } + + // Prevent parent from being updated + parentLocked = true; +} void Service::InitService() { - SetParent(dataModel.lock()); - parentLocked = true; } \ No newline at end of file diff --git a/core/src/objects/base/service.h b/core/src/objects/base/service.h index 592596f..2b7f5ac 100644 --- a/core/src/objects/base/service.h +++ b/core/src/objects/base/service.h @@ -6,10 +6,10 @@ #include class Service : public Instance { protected: - std::weak_ptr dataModel; - - Service(const InstanceType* type, std::weak_ptr root); + Service(const InstanceType* type); virtual void InitService(); + void OnParentUpdated(std::optional> oldParent, std::optional> newParent) override; + friend class DataModel; }; \ No newline at end of file diff --git a/core/src/objects/datamodel.cpp b/core/src/objects/datamodel.cpp index ed381b6..a110e96 100644 --- a/core/src/objects/datamodel.cpp +++ b/core/src/objects/datamodel.cpp @@ -2,6 +2,7 @@ #include "base/service.h" #include "objects/base/instance.h" #include "objects/base/service.h" +#include "objects/meta.h" #include "workspace.h" #include "logger.h" #include "panic.h" @@ -10,12 +11,6 @@ #include #include -// TODO: Move this to a different file -// ONLY add services here, all types are expected to inherit from Service, or errors WILL occur -std::map(std::weak_ptr)>> SERVICE_CONSTRUCTORS = { - { "Workspace", &Workspace::Create }, -}; - const InstanceType DataModel::TYPE = { .super = &Instance::TYPE, .className = "DataModel", @@ -33,8 +28,10 @@ DataModel::DataModel() void DataModel::Init() { // Create the workspace if it doesn't exist - if (this->services.count("Workspace") == 0) - this->services["Workspace"] = std::make_shared(shared()); + if (this->services.count("Workspace") == 0) { + this->services["Workspace"] = std::make_shared(); + AddChild(this->services["Workspace"]); + } // Init all services for (auto [_, service] : this->services) { @@ -67,7 +64,7 @@ void DataModel::SaveToFile(std::optional path) { void DataModel::DeserializeService(pugi::xml_node* node) { std::string className = node->attribute("class").value(); - if (SERVICE_CONSTRUCTORS.count(className) == 0) { + if (INSTANCE_MAP.count(className) == 0) { Logger::fatalErrorf("Unknown service: '%s'", className.c_str()); panic(); } @@ -78,7 +75,8 @@ void DataModel::DeserializeService(pugi::xml_node* node) { } // This will error if an abstract instance is used in the file. Oh well, not my prob rn. - InstanceRef object = SERVICE_CONSTRUCTORS[className](shared()); + InstanceRef object = INSTANCE_MAP[className]->constructor(); + AddChild(object); // Read properties pugi::xml_node propertiesNode = node->child("Properties"); diff --git a/core/src/objects/datamodel.h b/core/src/objects/datamodel.h index 28e41b8..49cf237 100644 --- a/core/src/objects/datamodel.h +++ b/core/src/objects/datamodel.h @@ -1,13 +1,16 @@ #pragma once #include "base.h" +#include "logger.h" +#include "objects/base/instance.h" +#include "objects/meta.h" +#include "panic.h" #include class Workspace; class DataModel; class Service; -extern std::map(std::weak_ptr)>> SERVICE_CONSTRUCTORS; // The root instance to all objects in the hierarchy class DataModel : public Instance { @@ -26,12 +29,37 @@ public: static inline std::shared_ptr New() { return std::make_shared(); }; virtual const InstanceType* GetClass() override; + // Inserts a service if it doesn't already exist + bool InsertService(std::string name) { + if (services.count(name) != 0) + return false; + + if (!INSTANCE_MAP[name] || (INSTANCE_MAP[name]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) { + Logger::fatalErrorf("Attempt to create instance of unknown type %s", name); + panic(); + } + + services[name] = std::dynamic_pointer_cast(INSTANCE_MAP[name]->constructor()); + AddChild(std::dynamic_pointer_cast(services[name])); + + return true; + } + template std::shared_ptr GetService(std::string name) { if (services.count(name) != 0) return services[name]; - // TODO: Validate name - services[name] = SERVICE_CONSTRUCTORS[name](shared()); + + // TODO: Replace this with a result return type + if (!INSTANCE_MAP[name] || (INSTANCE_MAP[name]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) { + Logger::fatalErrorf("Attempt to create instance of unknown type %s", name); + panic(); + } + + services[name] = std::dynamic_pointer_cast(INSTANCE_MAP[name]->constructor()); + AddChild(std::dynamic_pointer_cast(services[name])); + + return services[name]; } template diff --git a/core/src/objects/workspace.cpp b/core/src/objects/workspace.cpp index 3fbfa8e..d28e7ce 100644 --- a/core/src/objects/workspace.cpp +++ b/core/src/objects/workspace.cpp @@ -1,15 +1,17 @@ #include "workspace.h" +#include "objects/base/instance.h" const InstanceType Workspace::TYPE = { .super = &Instance::TYPE, .className = "Workspace", - // .constructor = &Workspace::Create, + .constructor = &Workspace::Create, .explorerIcon = "workspace", + .flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE, }; const InstanceType* Workspace::GetClass() { return &TYPE; } -Workspace::Workspace(std::weak_ptr dataModel): Service(&TYPE, dataModel) { +Workspace::Workspace(): Service(&TYPE) { } diff --git a/core/src/objects/workspace.h b/core/src/objects/workspace.h index 5870ecc..ba216f0 100644 --- a/core/src/objects/workspace.h +++ b/core/src/objects/workspace.h @@ -9,9 +9,9 @@ class Workspace : public Service { public: const static InstanceType TYPE; - Workspace(std::weak_ptr dataModel); + Workspace(); // static inline std::shared_ptr New() { return std::make_shared(); }; - static inline std::shared_ptr Create(std::weak_ptr parent) { return std::make_shared(parent); }; + static inline std::shared_ptr Create() { return std::make_shared(); }; virtual const InstanceType* GetClass() override; }; \ No newline at end of file