#pragma once #include "cplt_fwd.hpp" #include #include #include #include #include class SerializationStreamProxy { public: static constexpr bool IsSerializer() { return true; } public: DataStream* Stream; template void Bytes(size_t byteCount, T* buffer) const; template void Value(T t) const; template void Object(T& obj) const; template void ObjectAdapted(TObject& obj, TAdapter&& adapter) const; }; class DeserializationStreamProxy { public: static constexpr bool IsSerializer() { return false; } public: DataStream* Stream; template void Bytes(size_t byteCount, T* buffer) const; template void Value(T& t) const; template void Object(T& obj) const; template void ObjectAdapted(TObject& obj, TAdapter&& adapter) const; }; class DataStream { private: // TODO customizable storage lik QIODevice // TODO move read/write into separate classes, removing need of IOAdapters? std::fstream mBackend; std::endian mEndian; public: DataStream(std::fstream stream); ~DataStream(); std::endian GetEndianness() const; void SetEndianness(std::endian endianness); void WriteBytes(size_t byteCount, const std::byte* buffer); void WriteBytes(size_t byteCount, const char* buffer); void WriteBytes(size_t byteCount, const signed char* buffer); void WriteBytes(size_t byteCount, const unsigned char* buffer); template void WriteBytes(TIterator&& begin, TIterator&& end) { for (; begin != end; ++begin) { uint8_t byte = *begin; Write(byte); } } void ReadBytes(size_t byteCount, std::byte* buffer); void ReadBytes(size_t byteCount, char* buffer); void ReadBytes(size_t byteCount, signed char* buffer); void ReadBytes(size_t byteCount, unsigned char* buffer); template void ReadBytes(size_t byteCount, TInserter&& inserter) { for (size_t i = 0; i < byteCount; ++i) { uint8_t byte; Read(byte); inserter = byte; } } void Write(int8_t n); void Write(int16_t n); void Write(int32_t n); void Write(int64_t n); void Read(int8_t& n); void Read(int16_t& n); void Read(int32_t& n); void Read(int64_t& n); void Write(uint8_t n); void Write(uint16_t n); void Write(uint32_t n); void Write(uint64_t n); void Read(uint8_t& n); void Read(uint16_t& n); void Read(uint32_t& n); void Read(uint64_t& n); void Write(float n); void Write(double n); void Read(float& n); void Read(double& n); template void WriteObject(TObject& obj) { if constexpr (requires(TObject t) { t.WriteToDataStream(std::declval()); }) { obj.WriteToDataStream(*this); } else if constexpr (requires(TObject t) { t.OperateIOProxy(std::declval()); }) { SerializationStreamProxy adapter{ this }; obj.OperateIOProxy(adapter); } else { static_assert(false && sizeof(TObject), "This type does not have integration with DataStream."); } } template void WriteObjectAdapted(TObject& obj, TAdapter&& adapter) { adapter.WriteToDataStream(*this, obj); } template void ReadObject(TObject& obj) { if constexpr (requires(TObject t) { t.ReadFromDataStream(std::declval()); }) { obj.ReadFromDataStream(*this); } else if constexpr (requires(TObject t) { t.OperateIOProxy(std::declval()); }) { DeserializationStreamProxy adapter{ this }; obj.OperateIOProxy(adapter); } else { static_assert(false && sizeof(TObject), "This type does not have integration with DataStream."); } } template void ReadObjectAdapted(TObject& obj, TAdapter&& adapter) { adapter.ReadFromDataStream(*this, obj); } }; template void SerializationStreamProxy::Bytes(size_t byteCount, T* buffer) const { Stream->WriteBytes(byteCount, buffer); } template void SerializationStreamProxy::Value(T t) const { Stream->Write(t); } template void SerializationStreamProxy::Object(T& obj) const { Stream->WriteObject(obj); } template void SerializationStreamProxy::ObjectAdapted(TObject& obj, TAdapter&& adapter) const { Stream->WriteObjectAdapted(obj, adapter); } template void DeserializationStreamProxy::Bytes(size_t byteCount, T* buffer) const { Stream->WriteBytes(byteCount, buffer); } template void DeserializationStreamProxy::Value(T& t) const { Stream->Read(t); } template void DeserializationStreamProxy::Object(T& obj) const { Stream->ReadObject(obj); } template void DeserializationStreamProxy::ObjectAdapted(TObject& obj, TAdapter&& adapter) const { Stream->ReadObjectAdapted(obj, adapter); }