feat(instance): utility functions for casting/types

This commit is contained in:
maelstrom 2025-04-20 00:08:59 +02:00
parent 1617086692
commit be3c7bd6b2
4 changed files with 50 additions and 16 deletions

View file

@ -25,4 +25,9 @@ class MemberNotFound : public Error {
class AssignToReadOnlyMember : public Error { class AssignToReadOnlyMember : public Error {
public: public:
inline AssignToReadOnlyMember(std::string className, std::string memberName) : Error("AssignToReadOnlyMember", "Attempt to assign value to read-only member '" + memberName + "' in class " + className) {} inline AssignToReadOnlyMember(std::string className, std::string memberName) : Error("AssignToReadOnlyMember", "Attempt to assign value to read-only member '" + memberName + "' in class " + className) {}
};
class InstanceCastError : public Error {
public:
inline InstanceCastError(std::string sourceClass, std::string targetClass) : Error("InstanceCastError", "Attempt to cast object of type " + sourceClass + " to incompatible type " + targetClass) {}
}; };

View file

@ -100,6 +100,15 @@ public:
// Returning a list of property names feels kinda janky. Is this really the way to go? // Returning a list of property names feels kinda janky. Is this really the way to go?
std::vector<std::string> GetProperties(); std::vector<std::string> GetProperties();
template <typename T>
result<std::shared_ptr<T>, InstanceCastError> CastTo() {
// TODO: Too lazy to implement a manual check
std::shared_ptr<T> result = std::dynamic_pointer_cast<T>(shared_from_this());
if (result != nullptr)
return InstanceCastError(GetClass()->className, T::TYPE.className);
return result;
}
// Serialization // Serialization
void Serialize(pugi::xml_node parent); void Serialize(pugi::xml_node parent);
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node); static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node);

View file

@ -9,6 +9,7 @@
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <optional>
const InstanceType DataModel::TYPE = { const InstanceType DataModel::TYPE = {
.super = &Instance::TYPE, .super = &Instance::TYPE,
@ -120,4 +121,28 @@ std::shared_ptr<DataModel> DataModel::LoadFromFile(std::string path) {
newModel->Init(); newModel->Init();
return newModel; return newModel;
}
result<std::shared_ptr<Service>, NoSuchService> DataModel::GetService(std::string className) {
if (services.count(className) != 0)
return std::dynamic_pointer_cast<Service>(services[className]);
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
return NoSuchService(className);
}
services[className] = std::dynamic_pointer_cast<Service>(INSTANCE_MAP[className]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[className]));
return std::dynamic_pointer_cast<Service>(services[className]);
}
result<std::optional<std::shared_ptr<Service>>, NoSuchService> DataModel::FindService(std::string className) {
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
return NoSuchService(className);
}
if (services.count(className) != 0)
return std::make_optional(std::dynamic_pointer_cast<Service>(services[className]));
return (std::optional<std::shared_ptr<Service>>)std::nullopt;
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "error/instance.h"
#include "error/result.h" #include "error/result.h"
#include "logger.h" #include "logger.h"
#include "objects/base/instance.h" #include "objects/base/instance.h"
@ -46,27 +47,21 @@ public:
return {}; 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> template <typename T>
result<std::shared_ptr<T>, NoSuchService> GetService(std::string name) { result<std::shared_ptr<T>, NoSuchService> GetService() {
if (services.count(name) != 0) auto result = GetService(T::TYPE.className);
return std::dynamic_pointer_cast<T>(services[name]); if (result.isError()) return result.error().value();
return std::dynamic_pointer_cast<T>(result.success().value());
// TODO: Replace this with a result return type
if (!INSTANCE_MAP[name] || (INSTANCE_MAP[name]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
return NoSuchService(name);
}
services[name] = std::dynamic_pointer_cast<Service>(INSTANCE_MAP[name]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[name]));
return std::dynamic_pointer_cast<T>(services[name]);
} }
template <typename T> template <typename T>
std::optional<std::shared_ptr<T>> FindService() { std::optional<std::shared_ptr<T>> FindService() {
if (services.count(name) != 0) auto result = FindService(T::TYPE.className);
return std::dynamic_pointer_cast<T>(services[name]); if (result.isError()) return result.error().value();
return std::nullopt; return std::dynamic_pointer_cast<T>(result.success().value());
} }
// Saving/loading // Saving/loading