From be3c7bd6b28ce38ff505b3ba0894a5e23fb48025 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Sun, 20 Apr 2025 00:08:59 +0200 Subject: [PATCH] feat(instance): utility functions for casting/types --- core/src/error/instance.h | 5 +++++ core/src/objects/base/instance.h | 9 +++++++++ core/src/objects/datamodel.cpp | 25 +++++++++++++++++++++++++ core/src/objects/datamodel.h | 27 +++++++++++---------------- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/core/src/error/instance.h b/core/src/error/instance.h index 202e67f..940b2c0 100644 --- a/core/src/error/instance.h +++ b/core/src/error/instance.h @@ -25,4 +25,9 @@ class MemberNotFound : public Error { class AssignToReadOnlyMember : public Error { public: 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) {} }; \ No newline at end of file diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 4fa97ec..5b04065 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -100,6 +100,15 @@ public: // Returning a list of property names feels kinda janky. Is this really the way to go? std::vector GetProperties(); + template + result, InstanceCastError> CastTo() { + // TODO: Too lazy to implement a manual check + std::shared_ptr result = std::dynamic_pointer_cast(shared_from_this()); + if (result != nullptr) + return InstanceCastError(GetClass()->className, T::TYPE.className); + return result; + } + // Serialization void Serialize(pugi::xml_node parent); static result, NoSuchInstance> Deserialize(pugi::xml_node node); diff --git a/core/src/objects/datamodel.cpp b/core/src/objects/datamodel.cpp index 331ba20..321c1bc 100644 --- a/core/src/objects/datamodel.cpp +++ b/core/src/objects/datamodel.cpp @@ -9,6 +9,7 @@ #include #include #include +#include const InstanceType DataModel::TYPE = { .super = &Instance::TYPE, @@ -120,4 +121,28 @@ std::shared_ptr DataModel::LoadFromFile(std::string path) { newModel->Init(); return newModel; +} + +result, NoSuchService> DataModel::GetService(std::string className) { + if (services.count(className) != 0) + return std::dynamic_pointer_cast(services[className]); + + if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) { + return NoSuchService(className); + } + + services[className] = std::dynamic_pointer_cast(INSTANCE_MAP[className]->constructor()); + AddChild(std::dynamic_pointer_cast(services[className])); + + return std::dynamic_pointer_cast(services[className]); +} + +result>, 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(services[className])); + return (std::optional>)std::nullopt; } \ No newline at end of file diff --git a/core/src/objects/datamodel.h b/core/src/objects/datamodel.h index c94bdcb..0fd1894 100644 --- a/core/src/objects/datamodel.h +++ b/core/src/objects/datamodel.h @@ -1,5 +1,6 @@ #pragma once +#include "error/instance.h" #include "error/result.h" #include "logger.h" #include "objects/base/instance.h" @@ -46,27 +47,21 @@ public: return {}; } + result, NoSuchService> GetService(std::string className); + result>, NoSuchService> FindService(std::string className); + template - result, NoSuchService> GetService(std::string name) { - if (services.count(name) != 0) - return std::dynamic_pointer_cast(services[name]); - - // 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(INSTANCE_MAP[name]->constructor()); - AddChild(std::dynamic_pointer_cast(services[name])); - - return std::dynamic_pointer_cast(services[name]); + result, NoSuchService> GetService() { + auto result = GetService(T::TYPE.className); + if (result.isError()) return result.error().value(); + return std::dynamic_pointer_cast(result.success().value()); } template std::optional> FindService() { - if (services.count(name) != 0) - return std::dynamic_pointer_cast(services[name]); - return std::nullopt; + auto result = FindService(T::TYPE.className); + if (result.isError()) return result.error().value(); + return std::dynamic_pointer_cast(result.success().value()); } // Saving/loading