refactor(service): service instantiation to use instance constructor field

This commit is contained in:
maelstrom 2025-04-10 17:33:42 +02:00
parent 923c1c99b4
commit 36397c1119
7 changed files with 69 additions and 23 deletions

View file

@ -23,12 +23,19 @@ typedef std::shared_ptr<Instance>(*InstanceConstructor)();
class DataModel; class DataModel;
class Workspace; 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 describing information about an instance
struct InstanceType { struct InstanceType {
const InstanceType* super; // May be null const InstanceType* super; // May be null
std::string className; std::string className;
InstanceConstructor constructor; InstanceConstructor constructor;
std::string explorerIcon = ""; std::string explorerIcon = "";
InstanceFlags flags;
}; };
class DescendantsIterator; class DescendantsIterator;

View file

@ -1,9 +1,20 @@
#include "service.h" #include "service.h"
#include "logger.h"
#include "panic.h"
#include <memory> #include <memory>
Service::Service(const InstanceType* type, std::weak_ptr<DataModel> 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<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> 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() { void Service::InitService() {
SetParent(dataModel.lock());
parentLocked = true;
} }

View file

@ -6,10 +6,10 @@
#include <memory> #include <memory>
class Service : public Instance { class Service : public Instance {
protected: protected:
std::weak_ptr<DataModel> dataModel; Service(const InstanceType* type);
Service(const InstanceType* type, std::weak_ptr<DataModel> root);
virtual void InitService(); virtual void InitService();
void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override;
friend class DataModel; friend class DataModel;
}; };

View file

@ -2,6 +2,7 @@
#include "base/service.h" #include "base/service.h"
#include "objects/base/instance.h" #include "objects/base/instance.h"
#include "objects/base/service.h" #include "objects/base/service.h"
#include "objects/meta.h"
#include "workspace.h" #include "workspace.h"
#include "logger.h" #include "logger.h"
#include "panic.h" #include "panic.h"
@ -10,12 +11,6 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
// 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::string, std::function<std::shared_ptr<Service>(std::weak_ptr<DataModel>)>> SERVICE_CONSTRUCTORS = {
{ "Workspace", &Workspace::Create },
};
const InstanceType DataModel::TYPE = { const InstanceType DataModel::TYPE = {
.super = &Instance::TYPE, .super = &Instance::TYPE,
.className = "DataModel", .className = "DataModel",
@ -33,8 +28,10 @@ DataModel::DataModel()
void DataModel::Init() { void DataModel::Init() {
// Create the workspace if it doesn't exist // Create the workspace if it doesn't exist
if (this->services.count("Workspace") == 0) if (this->services.count("Workspace") == 0) {
this->services["Workspace"] = std::make_shared<Workspace>(shared<DataModel>()); this->services["Workspace"] = std::make_shared<Workspace>();
AddChild(this->services["Workspace"]);
}
// Init all services // Init all services
for (auto [_, service] : this->services) { for (auto [_, service] : this->services) {
@ -67,7 +64,7 @@ void DataModel::SaveToFile(std::optional<std::string> path) {
void DataModel::DeserializeService(pugi::xml_node* node) { void DataModel::DeserializeService(pugi::xml_node* node) {
std::string className = node->attribute("class").value(); 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()); Logger::fatalErrorf("Unknown service: '%s'", className.c_str());
panic(); 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. // This will error if an abstract instance is used in the file. Oh well, not my prob rn.
InstanceRef object = SERVICE_CONSTRUCTORS[className](shared<DataModel>()); InstanceRef object = INSTANCE_MAP[className]->constructor();
AddChild(object);
// Read properties // Read properties
pugi::xml_node propertiesNode = node->child("Properties"); pugi::xml_node propertiesNode = node->child("Properties");

View file

@ -1,13 +1,16 @@
#pragma once #pragma once
#include "base.h" #include "base.h"
#include "logger.h"
#include "objects/base/instance.h"
#include "objects/meta.h"
#include "panic.h"
#include <memory> #include <memory>
class Workspace; class Workspace;
class DataModel; class DataModel;
class Service; class Service;
extern std::map<std::string, std::function<std::shared_ptr<Service>(std::weak_ptr<DataModel>)>> SERVICE_CONSTRUCTORS;
// The root instance to all objects in the hierarchy // The root instance to all objects in the hierarchy
class DataModel : public Instance { class DataModel : public Instance {
@ -26,12 +29,37 @@ public:
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); }; static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
virtual const InstanceType* GetClass() override; 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<Service>(INSTANCE_MAP[name]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[name]));
return true;
}
template <typename T> template <typename T>
std::shared_ptr<T> GetService(std::string name) { std::shared_ptr<T> GetService(std::string name) {
if (services.count(name) != 0) if (services.count(name) != 0)
return services[name]; return services[name];
// TODO: Validate name
services[name] = SERVICE_CONSTRUCTORS[name](shared<DataModel>()); // 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<Service>(INSTANCE_MAP[name]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[name]));
return services[name];
} }
template <typename T> template <typename T>

View file

@ -1,15 +1,17 @@
#include "workspace.h" #include "workspace.h"
#include "objects/base/instance.h"
const InstanceType Workspace::TYPE = { const InstanceType Workspace::TYPE = {
.super = &Instance::TYPE, .super = &Instance::TYPE,
.className = "Workspace", .className = "Workspace",
// .constructor = &Workspace::Create, .constructor = &Workspace::Create,
.explorerIcon = "workspace", .explorerIcon = "workspace",
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE,
}; };
const InstanceType* Workspace::GetClass() { const InstanceType* Workspace::GetClass() {
return &TYPE; return &TYPE;
} }
Workspace::Workspace(std::weak_ptr<DataModel> dataModel): Service(&TYPE, dataModel) { Workspace::Workspace(): Service(&TYPE) {
} }

View file

@ -9,9 +9,9 @@ class Workspace : public Service {
public: public:
const static InstanceType TYPE; const static InstanceType TYPE;
Workspace(std::weak_ptr<DataModel> dataModel); Workspace();
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); }; // static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
static inline std::shared_ptr<Service> Create(std::weak_ptr<DataModel> parent) { return std::make_shared<Workspace>(parent); }; static inline std::shared_ptr<Instance> Create() { return std::make_shared<Workspace>(); };
virtual const InstanceType* GetClass() override; virtual const InstanceType* GetClass() override;
}; };