11#if PROMEKI_ENABLE_CORE
14#include <promeki/config.h>
30PROMEKI_NAMESPACE_BEGIN
41enum DataTypeID : uint16_t;
150 static constexpr uint16_t CurrentVersion = 3;
153 static constexpr size_t HeaderSize = 16;
157 static constexpr size_t FrameHeaderSize = 8;
163 static constexpr uint32_t MaxFrameBodySize = 1u << 30;
166 static constexpr uint8_t Magic[4] = {0x50, 0x4D, 0x44, 0x53};
179 static DataStream createWriter(IODevice *device, ByteOrder order = BigEndian);
190 static DataStream createReader(IODevice *device);
202 explicit DataStream(IODevice *device);
205 ~DataStream() =
default;
212 void setByteOrder(ByteOrder order) { _byteOrder = order; }
215 ByteOrder byteOrder()
const {
return _byteOrder; }
228 uint16_t version()
const {
return _version; }
235 Status status()
const {
return _status; }
240 const String &errorContext()
const {
return _errorContext; }
245 Error toError()
const;
258 IODevice *device()
const {
return _device; }
265 DataStream &operator<<(int8_t val);
267 DataStream &operator<<(uint8_t val);
269 DataStream &operator<<(int16_t val);
271 DataStream &operator<<(uint16_t val);
273 DataStream &operator<<(int32_t val);
275 DataStream &operator<<(uint32_t val);
277 DataStream &operator<<(int64_t val);
279 DataStream &operator<<(uint64_t val);
281 DataStream &operator<<(
float val);
283 DataStream &operator<<(
double val);
285 DataStream &operator<<(
bool val);
287 DataStream &operator<<(
const String &val);
289 DataStream &operator<<(
const Buffer &val);
299 DataStream &operator<<(
const Variant &val);
306 DataStream &operator>>(int8_t &val);
308 DataStream &operator>>(uint8_t &val);
310 DataStream &operator>>(int16_t &val);
312 DataStream &operator>>(uint16_t &val);
314 DataStream &operator>>(int32_t &val);
316 DataStream &operator>>(uint32_t &val);
318 DataStream &operator>>(int64_t &val);
320 DataStream &operator>>(uint64_t &val);
322 DataStream &operator>>(
float &val);
324 DataStream &operator>>(
double &val);
326 DataStream &operator>>(
bool &val);
328 DataStream &operator>>(String &val);
330 DataStream &operator>>(Buffer &val);
340 DataStream &operator>>(Variant &val);
351 template <
typename T> Result<T> read() {
354 if (_status != Ok)
return makeError<T>(toError());
355 return makeResult(std::move(val));
380 void beginFrame(DataTypeID
id, uint16_t version);
410 bool readFrame(DataTypeID expected, uint16_t maxVersion = 1,
411 uint16_t *outVersion =
nullptr, uint32_t *outSize =
nullptr);
421 bool readFrameHeader(DataTypeID &outTag, uint16_t &outVersion, uint32_t &outSize);
447 bool peekFrameHeader(DataTypeID &outTag, uint16_t &outVersion, uint32_t &outSize);
470 void setError(Status s, String ctx);
477 ssize_t readRawData(
void *buf,
size_t len);
487 ssize_t writeRawData(
const void *buf,
size_t len);
490 ssize_t skipRawData(
size_t len);
500 bool readBytes(
void *buf,
size_t len);
506 bool skipFrameBody(uint32_t sz);
512 bool writeBytes(
const void *buf,
size_t len);
517 template <
typename T>
void swapIfNeeded(T &val)
const {
518 if constexpr (
sizeof(T) == 1)
return;
519 if (_byteOrder == nativeByteOrder())
return;
520 uint8_t *p =
reinterpret_cast<uint8_t *
>(&val);
521 if constexpr (
sizeof(T) == 2) {
522 std::swap(p[0], p[1]);
523 }
else if constexpr (
sizeof(T) == 4) {
524 std::swap(p[0], p[3]);
525 std::swap(p[1], p[2]);
526 }
else if constexpr (
sizeof(T) == 8) {
527 std::swap(p[0], p[7]);
528 std::swap(p[1], p[6]);
529 std::swap(p[2], p[5]);
530 std::swap(p[3], p[4]);
535 static ByteOrder nativeByteOrder() {
536 static const uint16_t val = 1;
537 return (*
reinterpret_cast<const uint8_t *
>(&val) == 1) ? LittleEndian : BigEndian;
543 struct PendingFrame {
549 IODevice * _device =
nullptr;
550 ByteOrder _byteOrder = BigEndian;
551 uint16_t _version = 0;
553 String _errorContext;
554 List<PendingFrame> _frameStack;
560 bool _peekedHeaderValid =
false;
561 DataTypeID _peekedTag;
562 uint16_t _peekedVersion = 0;
563 uint32_t _peekedSize = 0;
578 inline constexpr uint32_t DataStreamMaxContainerCount = 256u * 1024u * 1024u;
603PROMEKI_NAMESPACE_BEGIN
619template <
typename T>
struct HasFreeDataStreamWrite<Size2DTemplate<T>> : std::true_type {};
620template <
typename T>
struct HasFreeDataStreamRead<Size2DTemplate<T>> : std::true_type {};
621template <
typename T>
struct HasFreeDataStreamWrite<Rational<T>> : std::true_type {};
622template <
typename T>
struct HasFreeDataStreamRead<Rational<T>> : std::true_type {};
639template <
typename T> DataStream &operator<<(DataStream &stream,
const Size2DTemplate<T> &sz) {
640 stream.beginFrame(DataTypeSize2D, 1);
641 stream << sz.width() << sz.height();
649template <
typename T> DataStream &operator>>(DataStream &stream, Size2DTemplate<T> &sz) {
650 if (!stream.readFrame(DataTypeSize2D)) {
651 sz = Size2DTemplate<T>();
656 if (stream.status() != DataStream::Ok) {
657 sz = Size2DTemplate<T>();
660 sz = Size2DTemplate<T>(w, h);
667template <
typename T> DataStream &operator<<(DataStream &stream,
const Rational<T> &r) {
668 stream.beginFrame(DataTypeRational, 1);
669 stream << r.numerator() << r.denominator();
677template <
typename T> DataStream &operator>>(DataStream &stream, Rational<T> &r) {
678 if (!stream.readFrame(DataTypeRational)) {
683 stream >> num >> den;
684 if (stream.status() != DataStream::Ok) {
688 r = Rational<T>(num, den);
695template <
typename T> DataStream &operator<<(DataStream &stream,
const Rect<T> &rect) {
696 stream.beginFrame(DataTypeRect, 1);
697 stream << rect.x() << rect.y() << rect.width() << rect.height();
705template <
typename T> DataStream &operator>>(DataStream &stream, Rect<T> &rect) {
706 if (!stream.readFrame(DataTypeRect)) {
710 T x{}, y{}, w{}, h{};
711 stream >> x >> y >> w >> h;
712 if (stream.status() != DataStream::Ok) {
716 rect = Rect<T>(x, y, w, h);
723template <
typename T,
size_t N> DataStream &operator<<(DataStream &stream,
const Point<T, N> &point) {
724 stream.beginFrame(DataTypePoint, 1);
725 stream << static_cast<uint32_t>(N);
726 const Array<T, N> &arr = point;
727 for (
size_t i = 0; i < N; ++i) stream << arr[i];
735template <
typename T,
size_t N> DataStream &operator>>(DataStream &stream, Point<T, N> &point) {
736 if (!stream.readFrame(DataTypePoint)) {
737 point = Point<T, N>();
742 if (stream.status() != DataStream::Ok) {
743 point = Point<T, N>();
747 stream.setError(DataStream::ReadCorruptData,
748 String::sprintf(
"Point dimension mismatch: expected %zu, got %u", N,
749 static_cast<unsigned>(dims)));
750 point = Point<T, N>();
754 for (
size_t i = 0; i < N; ++i) {
757 if (stream.status() != DataStream::Ok) {
758 point = Point<T, N>();
763 point = Point<T, N>(arr);
770template <
typename T> DataStream &operator<<(DataStream &stream,
const List<T> &list) {
771 stream.beginFrame(DataTypeList, 1);
772 stream << static_cast<uint32_t>(list.size());
773 for (
const auto &item : list) stream << item;
781template <
typename T> DataStream &operator>>(DataStream &stream, List<T> &list) {
783 if (!stream.readFrame(DataTypeList))
return stream;
786 if (stream.status() != DataStream::Ok)
return stream;
787 if (count > detail::DataStreamMaxContainerCount) {
788 stream.setError(DataStream::ReadCorruptData, String(
"List element count exceeds sanity limit"));
792 for (uint32_t i = 0; i < count; ++i) {
795 if (stream.status() != DataStream::Ok)
return stream;
796 list.pushToBack(std::move(item));
804template <
typename K,
typename V> DataStream &operator<<(DataStream &stream,
const Map<K, V> &map) {
805 stream.beginFrame(DataTypeMap, 1);
806 stream << static_cast<uint32_t>(map.size());
807 for (
auto it = map.cbegin(); it != map.cend(); ++it) {
808 stream << it->first << it->second;
817template <
typename K,
typename V> DataStream &operator>>(DataStream &stream, Map<K, V> &map) {
819 if (!stream.readFrame(DataTypeMap))
return stream;
822 if (stream.status() != DataStream::Ok)
return stream;
823 if (count > detail::DataStreamMaxContainerCount) {
824 stream.setError(DataStream::ReadCorruptData, String(
"Map entry count exceeds sanity limit"));
827 for (uint32_t i = 0; i < count; ++i) {
830 stream >> key >> value;
831 if (stream.status() != DataStream::Ok)
return stream;
832 map.insert(std::move(key), std::move(value));
840template <
typename T> DataStream &operator<<(DataStream &stream,
const Set<T> &set) {
841 stream.beginFrame(DataTypeSet, 1);
842 stream << static_cast<uint32_t>(set.size());
843 for (
const auto &item : set) stream << item;
851template <
typename T> DataStream &operator>>(DataStream &stream, Set<T> &set) {
853 if (!stream.readFrame(DataTypeSet))
return stream;
856 if (stream.status() != DataStream::Ok)
return stream;
857 if (count > detail::DataStreamMaxContainerCount) {
858 stream.setError(DataStream::ReadCorruptData, String(
"Set element count exceeds sanity limit"));
861 for (uint32_t i = 0; i < count; ++i) {
864 if (stream.status() != DataStream::Ok)
return stream;
865 set.insert(std::move(item));
873template <
typename K,
typename V> DataStream &operator<<(DataStream &stream,
const HashMap<K, V> &map) {
874 stream.beginFrame(DataTypeHashMap, 1);
875 stream << static_cast<uint32_t>(map.size());
876 for (
auto it = map.cbegin(); it != map.cend(); ++it) {
877 stream << it->first << it->second;
890template <
typename K,
typename V> DataStream &operator>>(DataStream &stream, HashMap<K, V> &map) {
892 if (!stream.readFrame(DataTypeHashMap))
return stream;
895 if (stream.status() != DataStream::Ok)
return stream;
896 if (count > detail::DataStreamMaxContainerCount) {
897 stream.setError(DataStream::ReadCorruptData, String(
"HashMap entry count exceeds sanity limit"));
900 for (uint32_t i = 0; i < count; ++i) {
903 stream >> key >> value;
904 if (stream.status() != DataStream::Ok)
return stream;
905 map.insert(std::move(key), std::move(value));
913template <
typename T> DataStream &operator<<(DataStream &stream,
const HashSet<T> &set) {
914 stream.beginFrame(DataTypeHashSet, 1);
915 stream << static_cast<uint32_t>(set.size());
916 for (
const auto &item : set) stream << item;
924template <
typename T> DataStream &operator>>(DataStream &stream, HashSet<T> &set) {
926 if (!stream.readFrame(DataTypeHashSet))
return stream;
929 if (stream.status() != DataStream::Ok)
return stream;
930 if (count > detail::DataStreamMaxContainerCount) {
931 stream.setError(DataStream::ReadCorruptData, String(
"HashSet element count exceeds sanity limit"));
934 for (uint32_t i = 0; i < count; ++i) {
937 if (stream.status() != DataStream::Ok)
return stream;
938 set.insert(std::move(item));
956inline DataStream &operator<<(DataStream &stream,
const JsonObject &obj) {
957 stream.beginFrame(DataTypeJsonObject, 1);
958 stream << obj.toString(0);
963inline DataStream &operator>>(DataStream &stream, JsonObject &obj) {
964 if (!stream.readFrame(DataTypeJsonObject)) {
970 if (stream.status() != DataStream::Ok) {
975 obj = JsonObject::parse(text, &err);
977 stream.setError(DataStream::ReadCorruptData, String(
"JsonObject::parse failed"));
982inline DataStream &operator<<(DataStream &stream,
const JsonArray &arr) {
983 stream.beginFrame(DataTypeJsonArray, 1);
984 stream << arr.toString(0);
989inline DataStream &operator>>(DataStream &stream, JsonArray &arr) {
990 if (!stream.readFrame(DataTypeJsonArray)) {
996 if (stream.status() != DataStream::Ok) {
1001 arr = JsonArray::parse(text, &err);
1002 if (err.isError()) {
1003 stream.setError(DataStream::ReadCorruptData, String(
"JsonArray::parse failed"));
1009template <>
struct HasFreeDataStreamWrite<JsonObject> : std::true_type {};
1010template <>
struct HasFreeDataStreamRead<JsonObject> : std::true_type {};
1011template <>
struct HasFreeDataStreamWrite<JsonArray> : std::true_type {};
1012template <>
struct HasFreeDataStreamRead<JsonArray> : std::true_type {};
1031template <
typename T>
1032concept HasMemberWriteToStream =
requires(
const T &t, DataStream &s) {
1033 { t.writeToStream(s) } -> std::convertible_to<Error>;
1039template <
typename T>
1040concept HasMemberReadFromStream =
requires(DataStream &s) {
1041 { T::template readFromStream<1>(s) } -> std::convertible_to<Result<T>>;
1050template <
typename T>
1051struct ExactDataStreamWrite<T, std::void_t<decltype(static_cast<DataStream &(DataStream::*)(const T &)>(
1052 &DataStream::operator<<))>> : std::true_type {};
1054template <typename T>
1055struct ExactDataStreamWrite<T, std::void_t<decltype(static_cast<DataStream &(DataStream::*)(T)>(
1056 &DataStream::operator<<))>> : std::true_type {};
1061template <typename T>
1062struct ExactDataStreamRead<T, std::void_t<decltype(static_cast<DataStream &(DataStream::*)(T &)>(
1063 &DataStream::operator>>))>> : std::true_type {};
1069template <typename T>
1070DataType::Ops makeDefaultOps() {
1072 if constexpr (std::is_default_constructible_v<T>) {
1073 ops.defaultConstruct = [](void *p) {
1078 ops.copyConstruct = [](void *dst, const void *src) {
1079 ::new (dst) T(*static_cast<const T *>(src));
1082 ops.moveConstruct = [](void *dst, void *src) {
1083 ::new (dst) T(std::move(*static_cast<T *>(src)));
1086 ops.destroy = [](void *p) {
1087 static_cast<T *>(p)->~T();
1090 if constexpr (HasEqualityOp<T>) {
1091 ops.equal = [](
const void *a,
const void *b) ->
bool {
1092 return *
static_cast<const T *
>(a) == *
static_cast<const T *
>(b);
1095 if constexpr (HasMemberToString<T>) {
1096 ops.toString = [](
const void *p, Error *err) -> String {
1097 if (err !=
nullptr) *err = Error::Ok;
1098 return static_cast<const T *
>(p)->toString();
1101 if constexpr (HasResultFromString<T>) {
1102 ops.fromString = [](
const String &s,
void *out, Error *err) ->
bool {
1103 auto r = T::fromString(s);
1104 if (r.second().isError()) {
1105 if (err !=
nullptr) *err = r.second();
1108 *
static_cast<T *
>(out) = r.first();
1109 if (err !=
nullptr) *err = Error::Ok;
1113 if constexpr (HasMemberValueInt<T>) {
1117 ops.toInt = [](
const void *p, Error *err) -> int64_t {
1118 if (err !=
nullptr) *err = Error::Ok;
1119 return static_cast<int64_t
>(
static_cast<const T *
>(p)->value());
1121 }
else if constexpr (HasMemberIdInt<T>) {
1125 ops.toInt = [](
const void *p, Error *err) -> int64_t {
1126 if (err !=
nullptr) *err = Error::Ok;
1127 return static_cast<int64_t
>(
static_cast<const T *
>(p)->
id());
1130 if constexpr (HasIdCtor<T>) {
1131 ops.fromInt = [](int64_t v,
void *out, Error *err) ->
bool {
1132 if (err !=
nullptr) *err = Error::Ok;
1133 *
static_cast<T *
>(out) = T(
static_cast<typename T::ID
>(v));
1136 }
else if constexpr (HasInt64Ctor<T>) {
1137 ops.fromInt = [](int64_t v,
void *out, Error *err) ->
bool {
1138 if (err !=
nullptr) *err = Error::Ok;
1139 *
static_cast<T *
>(out) = T(v);
1143 if constexpr (HasMemberToDouble<T>) {
1144 ops.toFloat = [](
const void *p, Error *err) ->
double {
1145 if (err !=
nullptr) *err = Error::Ok;
1146 return static_cast<const T *
>(p)->toDouble();
1149 if constexpr (HasResultFromDouble<T>) {
1150 ops.fromFloat = [](
double v,
void *out, Error *err) ->
bool {
1151 auto r = T::fromDouble(v);
1152 if (r.second().isError()) {
1153 if (err !=
nullptr) *err = r.second();
1156 *
static_cast<T *
>(out) = r.first();
1157 if (err !=
nullptr) *err = Error::Ok;
1161 if constexpr (HasMemberToJson<T>) {
1162 ops.toJson = +[](
const void *p, Error *err) -> JsonObject {
1163 if (err !=
nullptr) *err = Error::Ok;
1164 return static_cast<const T *
>(p)->toJson();
1167 if constexpr (HasResultFromJson<T>) {
1168 ops.fromJson = +[](
const JsonObject &j,
void *out, Error *err) ->
bool {
1169 auto r = T::fromJson(j);
1170 if (r.second().isError()) {
1171 if (err !=
nullptr) *err = r.second();
1174 *
static_cast<T *
>(out) = r.first();
1175 if (err !=
nullptr) *err = Error::Ok;
1179 if constexpr (HasMemberWriteToStream<T> && HasPromekiDataType<T>) {
1182 ops.writeStream = [](DataStream &s,
const void *p) {
1183 const T &val = *
static_cast<const T *
>(p);
1184 s.beginFrame(T::promekiDataType::id, T::promekiDataType::version);
1185 Error err = val.writeToStream(s);
1187 if (err.isError()) {
1188 if (s.status() == DataStream::Ok) {
1189 s.setError(DataStream::WriteFailed,
1190 String(
"writeToStream returned ") + err.name());
1195 }
else if constexpr (HasDataStreamWriteV<T>) {
1198 ops.writeStream = [](DataStream &s,
const void *p) {
1199 s << *static_cast<const T *>(p);
1203 if constexpr (HasMemberReadFromStream<T> && HasPromekiDataType<T>) {
1207 ops.readStream = [](DataStream &s,
void *p) {
1209 if (!s.readFrame(T::promekiDataType::id, T::promekiDataType::version, &ver,
1211 *
static_cast<T *
>(p) = T();
1214 Result<T> r = T::promekiDataType::dispatchRead(s, ver);
1215 if (r.second().isError()) {
1216 if (s.status() == DataStream::Ok) {
1217 s.setError(DataStream::ReadCorruptData,
1218 String(
"readFromStream returned ") + r.second().name());
1220 *
static_cast<T *
>(p) = T();
1223 *
static_cast<T *
>(p) = std::move(r.first());
1226 }
else if constexpr (HasDataStreamReadV<T>) {
1227 ops.readStream = [](DataStream &s,
void *p) {
1228 s >> *
static_cast<T *
>(p);
1248template <
typename T>
1249concept IsTypedEnumSubclass = std::is_base_of_v<Enum, T> && !std::is_same_v<T, Enum>;
1256template <
typename T>
1257 requires Detail::HasPromekiDataType<T> && Detail::HasMemberWriteToStream<T> &&
1258 (!Detail::IsTypedEnumSubclass<T>)
1259inline DataStream &
operator<<(DataStream &stream,
const T &val) {
1260 stream.beginFrame(T::promekiDataType::id, T::promekiDataType::version);
1261 Error err = val.writeToStream(stream);
1263 if (err.isError() && stream.status() == DataStream::Ok) {
1264 stream.setError(DataStream::WriteFailed,
1265 String(
"writeToStream returned ") + err.name());
1273template <
typename T>
1274 requires Detail::HasPromekiDataType<T> && Detail::HasMemberReadFromStream<T> &&
1275 (!Detail::IsTypedEnumSubclass<T>)
1276inline DataStream &
operator>>(DataStream &stream, T &val) {
1278 if (!stream.readFrame(T::promekiDataType::id, T::promekiDataType::version, &ver,
nullptr)) {
1282 Result<T> r = T::promekiDataType::dispatchRead(stream, ver);
1283 if (r.second().isError()) {
1284 if (stream.status() == DataStream::Ok) {
1285 stream.setError(DataStream::ReadCorruptData,
1286 String(
"readFromStream returned ") + r.second().name());
1291 val = std::move(r.first());
1305template <
typename T>
1306 requires Detail::IsTypedEnumSubclass<T>
1307inline DataStream &operator<<(DataStream &stream,
const T &val) {
1308 const Enum &base = val;
1309 return stream << base;
1312template <
typename T>
1313 requires Detail::IsTypedEnumSubclass<T>
1314inline DataStream &operator>>(DataStream &stream, T &val) {
1316 return stream >> base;
1319PROMEKI_NAMESPACE_END