openblocks/core/src/objects/datamodel.h

74 lines
No EOL
2.6 KiB
C++

#pragma once
#include "error/instance.h"
#include "error/result.h"
#include "logger.h"
#include "objects/base/instance.h"
#include "objects/base/refstate.h"
#include "objects/meta.h"
#include "panic.h"
#include <memory>
#include <variant>
class Workspace;
class DataModel;
class Service;
// The root instance to all objects in the hierarchy
class DataModel : public Instance {
private:
void DeserializeService(pugi::xml_node node);
static void cloneService(std::shared_ptr<DataModel> target, std::shared_ptr<Service>, RefState<_RefStatePropertyCell>);
public:
const static InstanceType TYPE;
std::map<std::string, std::shared_ptr<Service>> services;
std::optional<std::string> currentFile;
DataModel();
void Init();
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
virtual const InstanceType* GetClass() override;
// Inserts a service if it doesn't already exist
fallible<ServiceAlreadyExists, NoSuchService> InsertService(std::string name) {
if (services.count(name) != 0)
return fallible<ServiceAlreadyExists, NoSuchService>(ServiceAlreadyExists(name));
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 {};
}
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
result<std::optional<std::shared_ptr<Service>>, NoSuchService> FindService(std::string className);
template <typename T>
result<std::shared_ptr<T>, NoSuchService> GetService() {
auto result = GetService(T::TYPE.className);
if (result.isError()) return result.error().value();
return std::dynamic_pointer_cast<T>(result.success().value());
}
template <typename T>
std::optional<std::shared_ptr<T>> FindService() {
auto result = FindService(T::TYPE.className);
if (result.isError()) return result.error().value();
return std::dynamic_pointer_cast<T>(result.success().value());
}
// Saving/loading
inline bool HasFile() { return this->currentFile.has_value(); }
void SaveToFile(std::optional<std::string> path = std::nullopt);
static std::shared_ptr<DataModel> LoadFromFile(std::string path);
std::shared_ptr<DataModel> CloneModel();
};