refactor(service): service instantiation to use instance constructor field
This commit is contained in:
parent
923c1c99b4
commit
36397c1119
7 changed files with 69 additions and 23 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
};
|
};
|
|
@ -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");
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
Loading…
Add table
Reference in a new issue