#pragma once #include "tl/memory_buffer.h" #include #include #include "tl/result.h" #include "fs/Error.h" #include "fs/Api.h" namespace fs { //Design rationale: // Throw-away objects representing a non-seekable, non-sized data source or sink. // They are not supposed to be reused. // There is only one owner of the source, enforced by the tl::unique_ref wrapper. Due to this, simple sources are NOT thread safe. // There is no open/close for simple sources as the open is done in the constructor and close in the destructor. This is to reinforce the idea of throw-away objects. // If you need a persistent source to be able to reload your data, hold a // path to the source instead of the source. This is to allow the underlying file system to change (due to DLC for example). When you need the source again, request a new one from the file system. class FS_API IStreamSource { public: IStreamSource() = default; virtual ~IStreamSource() = default; IStreamSource(IStreamSource&&) = default; IStreamSource& operator=(IStreamSource&&) = default; //This will return the last generated error AND CLEAR IT AFTERWARDS. virtual tl::optional getLastError() const = 0; //Reads from the source into the buffer size bytes. The source pointer is advanced //Returns the number of bytes successfully read virtual size_t read(tl::span data) = 0; virtual bool isEOS() const = 0; // The preferred buffer size for reads. Use this buffer size for optimal performance // If zero, use whatever you want virtual size_t getPreferredBufferSize() const = 0; }; template struct StreamSourceSerializationHelper_Internal; template struct StreamSourceSerializationHelper_Internal { static IStreamSource& read(IStreamSource& s, T& val) { static_assert(std::is_fundamental_v && !std::is_pointer_v && !std::is_array_v, "You need a specialized read for T"); s.read({ reinterpret_cast(&val), sizeof(T) }); return s; } static IStreamSource& read(IStreamSource& s, tl::memory_buffer& val) { uint32_t count = 0; s.read({ reinterpret_cast(&count), sizeof(count) }); val.resize(count); s.read({ val.data(), count }); return s; } }; // specialization to read enums template struct StreamSourceSerializationHelper_Internal { static IStreamSource& read(IStreamSource& s, EnumType& val) { // first read into the temporary of the underlying type using underlying_t = std::underlying_type_t; underlying_t underlyingValue; IStreamSource& ret = StreamSourceSerializationHelper_Internal::read(s, underlyingValue); // put the read value into the enum val = EnumType(underlyingValue); return ret; } }; template struct SimpleStreamSerializationHelper : StreamSourceSerializationHelper_Internal>> { }; template IStreamSource& operator>>(IStreamSource& s, T& val) { return SimpleStreamSerializationHelper::read(s, val); } inline IStreamSource& operator>>(IStreamSource& s, tl::memory_buffer& val) { return SimpleStreamSerializationHelper::read(s, val); } }