#ifndef XNA_CONTENT_TYPEREADER_HPP #define XNA_CONTENT_TYPEREADER_HPP #include "../csharp/type.hpp" #include "../default.hpp" #include <algorithm> #include <map> #include <any> namespace xna { //-------------------------------------------------------// // ContentTypeReader // //-------------------------------------------------------// //Worker for reading a specific managed type from a binary format. class ContentTypeReader { public: virtual Int TypeVersion() { return 0; } virtual bool CanDeserializeIntoExistingObject() { return false; } //Retrieves and caches nested type readers. Called by the framework at creation time. virtual void Initialize(sptr<ContentTypeReaderManager> const& manager) {} //Gets the type handled by this reader component. sptr<Type> TargetType() { return _targetType; } //Reads a strongly typed object from the current stream. virtual std::any Read(ContentReader& input, std::any& existingInstance) = 0; protected: ContentTypeReader(sptr<Type> const& targetType) : _targetType(targetType) { } public: //Let's admit that the target is primarily of type value, if not it must be manually set to false bool TargetIsValueType{ true }; private: sptr<Type> _targetType = nullptr; }; //Worker for reading a specific managed type from a binary format. //Derive from this class to add new data types to the content pipeline system. template <class T> class ContentTypeReaderT : public ContentTypeReader { public: //For some reason ListReader<T> needs a default constructor ContentTypeReaderT() : ContentTypeReader(typeof<T>()) {} protected: ContentTypeReaderT(sptr<Type> const& targetType) : ContentTypeReader(targetType) {} public: //Reads a strongly typed object from the current stream. std::any Read(ContentReader& input, std::any& existingInstance) override { if (existingInstance.has_value() && !(existingInstance.type() == typeid(T))) throw std::runtime_error("ContentTypeReader<T>::Read: bad xbn, wrong type."); auto existingInstance1 = XnaHelper::ReturnDefaultOrNull<T>(); auto obj = Read(input, existingInstance1); return obj; } //Reads a strongly typed object from the current stream. virtual T Read(ContentReader& input, T& existingInstance) = 0; }; //-------------------------------------------------------// // ContentTypeReaderActivador // //-------------------------------------------------------// class ContentTypeReaderActivador { public: using Activador = sptr<ContentTypeReader>(*)(); static sptr<ContentTypeReader> CreateInstance(sptr<Type> const& type); static void SetActivador(sptr<Type> const& type, Activador activador); private: inline static auto activators = std::map<size_t, Activador>(); ContentTypeReaderActivador(); ContentTypeReaderActivador(ContentTypeReaderActivador&&); ContentTypeReaderActivador(ContentTypeReaderActivador&); }; using PContentTypeReader = sptr<ContentTypeReader>; using PType = sptr<Type>; //-------------------------------------------------------// // ContentTypeReaderManager // //-------------------------------------------------------// class ContentTypeReaderManager { public: static std::vector<PContentTypeReader> ReadTypeManifest(Int typeCount, sptr<ContentReader>& contentReader, xna_error_nullarg); static sptr<ContentTypeReader> GetTypeReader(sptr<Type> const& targetType, sptr<ContentReader>& contentReader, xna_error_nullarg); inline sptr<ContentTypeReader> GetTypeReader(sptr<Type> const& targetType, xna_error_nullarg) { return ContentTypeReaderManager::GetTypeReader(targetType, this->contentReader, err); } inline static bool ContainsTypeReader(sptr<Type> const& targetType) { return ContentTypeReaderManager::targetTypeToReader.contains(targetType); } private: ContentTypeReaderManager(sptr<ContentReader>& contentReader); static sptr<ContentTypeReader> GetTypeReader(String const& readerTypeName, sptr<ContentReader>& contentReader, std::vector<PContentTypeReader>& newTypeReaders, xna_error_nullarg); static bool InstantiateTypeReader(String const& readerTypeName, sptr<ContentReader>& contentReader, sptr<ContentTypeReader>& reader, xna_error_nullarg); static void AddTypeReader(String const& readerTypeName, sptr<ContentReader>& contentReader, sptr<ContentTypeReader>& reader, xna_error_nullarg); static void RollbackAddReaders(std::vector<sptr<ContentTypeReader>>& newTypeReaders); static void RollbackAddReader(std::map<String, PContentTypeReader>& dictionary, sptr<ContentTypeReader>& reader); static void RollbackAddReader(std::map<PType, PContentTypeReader>& dictionary, sptr<ContentTypeReader>& reader); private: sptr<ContentReader> contentReader = nullptr; inline static auto nameToReader = std::map<String, PContentTypeReader>(); inline static auto targetTypeToReader = std::map<PType, PContentTypeReader>(); inline static auto readerTypeToReader = std::map<PType, PContentTypeReader>(); static void initMaps(); }; } #endif