#pragma once #include #include #include #include #include #include #include #include #include #include #include #include "error/instance.h" #include "error/result.h" #include "member.h" #include "objects/base/refstate.h" class Instance; typedef std::shared_ptr(*InstanceConstructor)(); class DataModel; 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 InstanceType { const InstanceType* super; // May be null std::string className; InstanceConstructor constructor; std::string explorerIcon = ""; InstanceFlags flags; }; typedef std::pair, std::string> _RefStatePropertyCell; class DescendantsIterator; // Base class for all instances in the data model // Note: enable_shared_from_this HAS to be public or else its field will not be populated // Maybe this could be replaced with a friendship? But that seems unnecessary. // https://stackoverflow.com/q/56415222/16255372 class Instance : public std::enable_shared_from_this { private: std::weak_ptr parent; std::vector> children; std::optional> cachedMemberList; std::weak_ptr _dataModel; std::weak_ptr _workspace; bool ancestryContinuityCheck(std::optional> newParent); void updateAncestry(std::optional> child, std::optional> newParent); protected: bool parentLocked = false; std::unique_ptr memberMap; Instance(const InstanceType*); virtual ~Instance(); virtual void OnParentUpdated(std::optional> oldParent, std::optional> newParent); virtual void OnAncestryChanged(std::optional> child, std::optional> newParent); virtual void OnWorkspaceAdded(std::optional> oldWorkspace, std::shared_ptr newWorkspace); virtual void OnWorkspaceRemoved(std::shared_ptr oldWorkspace); // The root data model this object is a descendant of std::optional> dataModel(); // The root workspace this object is a descendant of // NOTE: This value is not necessarily present if dataModel is present // Objects under services other than workspace will NOT have this field set std::optional> workspace(); template inline std::shared_ptr shared() { return std::dynamic_pointer_cast(this->shared_from_this()); } public: const static InstanceType TYPE; std::string name; // Instance is abstract, so it should not implement GetClass directly virtual const InstanceType* GetClass() = 0; bool SetParent(std::optional> newParent); std::optional> GetParent(); bool IsParentLocked(); inline const std::vector> GetChildren() { return children; } DescendantsIterator GetDescendantsStart(); DescendantsIterator GetDescendantsEnd(); // Utility functions inline void AddChild(std::shared_ptr object) { object->SetParent(this->shared_from_this()); } // Properties result GetPropertyValue(std::string name); fallible SetPropertyValue(std::string name, Data::Variant value); result GetPropertyMeta(std::string name); // Manually trigger the update of a property. Useful internally when setting properties directly void UpdateProperty(std::string name); // Returning a list of property names feels kinda janky. Is this really the way to go? std::vector GetProperties(); std::vector>> GetReferenceProperties(); 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); std::optional> Clone(RefState<_RefStatePropertyCell> state = std::make_shared<__RefState<_RefStatePropertyCell>>()); }; typedef std::shared_ptr InstanceRef; typedef std::weak_ptr InstanceRefWeak; // https://gist.github.com/jeetsukumaran/307264 class DescendantsIterator { public: typedef DescendantsIterator self_type; typedef std::shared_ptr value_type; typedef std::shared_ptr& reference; typedef std::shared_ptr pointer; typedef std::forward_iterator_tag iterator_category; typedef int difference_type; DescendantsIterator(std::shared_ptr current); inline self_type operator++() { self_type i = *this; ++*this; return i; } inline std::shared_ptr operator*() { return current; } inline std::shared_ptr operator->() { return current; } inline bool operator==(const self_type& rhs) { return current == rhs.current; } inline bool operator!=(const self_type& rhs) { return current != rhs.current; } self_type operator++(int _); private: std::optional> root; std::shared_ptr current; std::vector siblingIndex; };