First
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "tl/memory_buffer.h"
|
||||
#include <tl/optional.h>
|
||||
#include <tl/span.h>
|
||||
#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<Error> 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<uint8_t> 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<typename T, bool isEnum>
|
||||
struct StreamSourceSerializationHelper_Internal;
|
||||
|
||||
template<typename T>
|
||||
struct StreamSourceSerializationHelper_Internal<T, false>
|
||||
{
|
||||
static IStreamSource& read(IStreamSource& s, T& val)
|
||||
{
|
||||
static_assert(std::is_fundamental_v<T> && !std::is_pointer_v<T> && !std::is_array_v<T>, "You need a specialized read for T");
|
||||
s.read({ reinterpret_cast<uint8_t*>(&val), sizeof(T) });
|
||||
return s;
|
||||
}
|
||||
|
||||
static IStreamSource& read(IStreamSource& s, tl::memory_buffer& val)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
s.read({ reinterpret_cast<uint8_t*>(&count), sizeof(count) });
|
||||
val.resize(count);
|
||||
s.read({ val.data(), count });
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// specialization to read enums
|
||||
template<typename EnumType>
|
||||
struct StreamSourceSerializationHelper_Internal<EnumType, true>
|
||||
{
|
||||
static IStreamSource& read(IStreamSource& s, EnumType& val)
|
||||
{
|
||||
// first read into the temporary of the underlying type
|
||||
using underlying_t = std::underlying_type_t<EnumType>;
|
||||
underlying_t underlyingValue;
|
||||
|
||||
IStreamSource& ret = StreamSourceSerializationHelper_Internal<underlying_t, false>::read(s, underlyingValue);
|
||||
// put the read value into the enum
|
||||
val = EnumType(underlyingValue);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SimpleStreamSerializationHelper : StreamSourceSerializationHelper_Internal<T, std::is_enum_v<std::remove_reference_t<T>>>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
IStreamSource& operator>>(IStreamSource& s, T& val)
|
||||
{
|
||||
return SimpleStreamSerializationHelper<T>::read(s, val);
|
||||
}
|
||||
|
||||
inline IStreamSource& operator>>(IStreamSource& s, tl::memory_buffer& val)
|
||||
{
|
||||
return SimpleStreamSerializationHelper<uint8_t>::read(s, val);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user