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 {
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) {}
};

View file

@ -100,6 +100,15 @@ public:
// Returning a list of property names feels kinda janky. Is this really the way to go?
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
void Serialize(pugi::xml_node parent);
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node);

View file

@ -9,6 +9,7 @@
#include <cstdio>
#include <fstream>
#include <memory>
#include <optional>
const InstanceType DataModel::TYPE = {
.super = &Instance::TYPE,
@ -120,4 +121,28 @@ std::shared_ptr<DataModel> DataModel::LoadFromFile(std::string path) {
newModel->Init();
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
#include "error/instance.h"
#include "error/result.h"
#include "logger.h"
#include "objects/base/instance.h"
@ -46,27 +47,21 @@ public:
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(std::string name) {
if (services.count(name) != 0)
return std::dynamic_pointer_cast<T>(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<Service>(INSTANCE_MAP[name]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[name]));
return std::dynamic_pointer_cast<T>(services[name]);
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() {
if (services.count(name) != 0)
return std::dynamic_pointer_cast<T>(services[name]);
return std::nullopt;
auto result = FindService(T::TYPE.className);
if (result.isError()) return result.error().value();
return std::dynamic_pointer_cast<T>(result.success().value());
}
// Saving/loading