11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
26PROMEKI_NAMESPACE_BEGIN
50enum DataTypeID : uint16_t {
51 DataTypeInvalid = 0x00,
57 DataTypeUInt16 = 0x04,
59 DataTypeUInt32 = 0x06,
61 DataTypeUInt64 = 0x08,
63 DataTypeDouble = 0x0A,
65 DataTypeString = 0x0C,
66 DataTypeBuffer = 0x0D,
67 DataTypeNoValue = 0x0E,
71 DataTypeDateTime = 0x11,
72 DataTypeTimeStamp = 0x12,
73 DataTypeSize2D = 0x13,
74 DataTypeRational = 0x14,
75 DataTypeFrameRate = 0x15,
76 DataTypeTimecode = 0x16,
78 DataTypeColorModel = 0x18,
79 DataTypeMemSpace = 0x19,
80 DataTypePixelMemLayout = 0x1A,
81 DataTypePixelFormat = 0x1B,
83 DataTypeStringList = 0x1D,
91 DataTypeHashMap = 0x23,
92 DataTypeHashSet = 0x24,
95 DataTypeJsonObject = 0x30,
96 DataTypeJsonArray = 0x31,
97 DataTypeXYZColor = 0x32,
98 DataTypeAudioDesc = 0x33,
99 DataTypeImageDesc = 0x34,
100 DataTypeMediaDesc = 0x35,
102 DataTypeEnumList = 0x37,
103 DataTypeMediaTimeStamp = 0x38,
104 DataTypeMacAddress = 0x39,
105 DataTypeEUI64 = 0x3A,
106 DataTypeMediaPipelineStage = 0x3B,
107 DataTypeMediaPipelineRoute = 0x3C,
108 DataTypeMediaPipelineConfig = 0x3D,
109 DataTypeMediaPipelineStats = 0x3E,
110 DataTypeVideoFormat = 0x3F,
113 DataTypeMasteringDisplay = 0x40,
114 DataTypeContentLightLevel = 0x41,
117 DataTypeMediaIODescription = 0x42,
120 DataTypeFrameNumber = 0x43,
121 DataTypeFrameCount = 0x44,
122 DataTypeMediaDuration = 0x45,
124 DataTypeAudioFormat = 0x47,
125 DataTypeMediaPayload = 0x48,
126 DataTypeDuration = 0x49,
127 DataTypeSocketAddress = 0x4A,
128 DataTypeSdpSession = 0x4B,
129 DataTypeVideoCodec = 0x4C,
130 DataTypeAudioCodec = 0x4D,
131 DataTypeAudioChannelMap = 0x4E,
132 DataTypeAudioStreamDesc = 0x4F,
133 DataTypeWindowedStat = 0x50,
134 DataTypeWindowedStatsBundle = 0x51,
135 DataTypeAudioMarkerList = 0x52,
136 DataTypeVariantList = 0x53,
137 DataTypeVariantMap = 0x54,
138 DataTypeXmlDocument = 0x55,
139 DataTypeXmlElement = 0x56,
140 DataTypeSslContext = 0x57,
141 DataTypeAncFormat = 0x58,
142 DataTypeAncPacket = 0x59,
143 DataTypeAncDesc = 0x5A,
144 DataTypeCea708Cdp = 0x5B,
145 DataTypeSubtitle = 0x5C,
146 DataTypeSubtitleSpan = 0x5D,
148 DataTypeCea608 = 0x5F,
149 DataTypeCea708Service = 0x60,
150 DataTypeCea708DtvccPacket = 0x61,
151 DataTypeHdrStaticMetadata = 0x62,
152 DataTypeHdrDynamic2094_40 = 0x63,
155 DataTypeVideoPortRef = 0x64,
156 DataTypeSdiSignalConfig = 0x65,
157 DataTypeHdmiSignalConfig = 0x66,
158 DataTypeVideoReferenceConfig = 0x67,
159 DataTypeSdiOutputFanoutConfig = 0x68,
160 DataTypeSdiVpid = 0x69,
161 DataTypeAncAtc = 0x6A,
162 DataTypeAncAfd = 0x6B,
163 DataTypeAncOp47Sdp = 0x6C,
164 DataTypeSt2020Audio = 0x6D,
165 DataTypeTimecodeUserbits = 0x6E,
169inline constexpr DataTypeID DataTypeUserBegin =
static_cast<DataTypeID
>(0x4000);
171inline constexpr DataTypeID DataTypeUserEnd =
static_cast<DataTypeID
>(0xFFFF);
187void registerBuiltinDataTypes();
277 void (*defaultConstruct)(
void *p) =
nullptr;
278 void (*copyConstruct)(
void *dst,
const void *src) =
nullptr;
279 void (*moveConstruct)(
void *dst,
void *src) =
nullptr;
280 void (*destroy)(
void *p) =
nullptr;
281 bool (*equal)(
const void *a,
const void *b) =
nullptr;
282 String (*toString)(
const void *p, Error *err) =
nullptr;
283 bool (*fromString)(
const String &s,
void *out, Error *err) =
nullptr;
284 int64_t (*toInt)(
const void *p, Error *err) =
nullptr;
285 bool (*fromInt)(int64_t v,
void *out, Error *err) =
nullptr;
286 double (*toFloat)(
const void *p, Error *err) =
nullptr;
287 bool (*fromFloat)(
double v,
void *out, Error *err) =
nullptr;
288 JsonObject (*toJson)(
const void *p, Error *err) =
nullptr;
289 bool (*fromJson)(
const JsonObject &j,
void *out, Error *err) =
nullptr;
290 void (*writeStream)(DataStream &s,
const void *p) =
nullptr;
291 void (*readStream)(DataStream &s,
void *p) =
nullptr;
302 DataTypeID
id = DataTypeInvalid;
303 const char *name =
"Invalid";
304 uint32_t version = 0;
307 std::type_index cppType = std::type_index(
typeid(
void));
312 DataType() =
default;
315 explicit DataType(
const Data *d) : _data(d) {
return; }
327 DataType(DataTypeID
id);
330 bool isValid()
const {
return _data !=
nullptr; }
333 DataTypeID id()
const {
return _data !=
nullptr ? _data->id : DataTypeInvalid; }
336 const char *name()
const {
return _data !=
nullptr ? _data->name :
"Invalid"; }
339 uint32_t version()
const {
return _data !=
nullptr ? _data->version : 0; }
342 size_t size()
const {
return _data !=
nullptr ? _data->size : 0; }
345 size_t alignment()
const {
return _data !=
nullptr ? _data->align : 1; }
348 std::type_index cppType()
const {
349 return _data !=
nullptr ? _data->cppType : std::type_index(
typeid(
void));
359 const Ops &ops()
const;
362 const Data *data()
const {
return _data; }
365 bool operator==(
const DataType &o)
const {
return _data == o._data; }
366 bool operator!=(
const DataType &o)
const {
return _data != o._data; }
390 static DataType registerType(DataTypeID
id,
const char *name, uint32_t version,
391 std::type_index ti,
size_t size,
size_t align, Ops ops);
394 static List<DataTypeID> registeredIds();
397 static DataType byId(DataTypeID
id);
400 static DataType byName(
const char *name);
419 template <
typename T>
static DataType of();
422 static DataType byCppType(std::type_index ti);
425 const Data *_data =
nullptr;
432concept HasEqualityOp =
requires(
const T &a,
const T &b) {
433 { a == b } -> std::convertible_to<bool>;
437concept HasMemberToString =
requires(
const T &t) {
438 { t.toString() } -> std::convertible_to<String>;
448concept HasResultFromString =
requires(
const String &s) {
449 { T::fromString(s) } -> std::convertible_to<Result<T>>;
459concept HasMemberValueInt =
requires(
const T &t) {
460 { t.value() } -> std::integral;
470concept HasMemberIdInt = (!HasMemberValueInt<T>) &&
requires(
const T &t) {
471 requires std::integral<
decltype(t.id())> || std::is_enum_v<
decltype(t.id())>;
483concept HasMemberToDouble =
requires(
const T &t) {
484 { t.toDouble() } -> std::convertible_to<double>;
495concept HasResultFromDouble =
requires(
double d) {
496 { T::fromDouble(d) } -> std::convertible_to<Result<T>>;
510concept HasMemberToJson =
requires(
const T &t) {
523concept HasResultFromJson =
requires(JsonObject *jp) {
535concept HasIdCtor =
requires {
typename T::ID; } && std::is_constructible_v<T, typename T::ID>;
545concept HasInt64Ctor = std::is_constructible_v<T, int64_t> && !HasIdCtor<T>;
552concept HasPromekiDataType =
requires {
553 { T::promekiDataType::id } -> std::convertible_to<DataTypeID>;
554 { T::promekiDataType::name } -> std::convertible_to<const char *>;
555 { T::promekiDataType::version } -> std::convertible_to<uint32_t>;
578template <
typename T>
struct HasFreeDataStreamWrite : std::false_type {};
581template <
typename T>
struct HasFreeDataStreamRead : std::false_type {};
590template <
typename T, u
int32_t MaxV, u
int32_t CurV = MaxV>
591struct VersionedReader {
592 static Result<T> read(DataStream &s, uint32_t version) {
593 if (version == CurV)
return T::template readFromStream<CurV>(s);
594 if constexpr (CurV > 1)
return VersionedReader<T, MaxV, CurV - 1>::read(s, version);
595 else return makeError<T>(Error::CorruptData);
605template <
typename T,
typename =
void>
606struct ExactDataStreamWrite : std::false_type {};
608template <
typename T,
typename =
void>
609struct ExactDataStreamRead : std::false_type {};
612inline constexpr bool ExactDataStreamWriteV = ExactDataStreamWrite<T>::value;
615inline constexpr bool ExactDataStreamReadV = ExactDataStreamRead<T>::value;
619inline constexpr bool HasDataStreamWriteV = ExactDataStreamWriteV<T> || HasFreeDataStreamWrite<T>::value;
623inline constexpr bool HasDataStreamReadV = ExactDataStreamReadV<T> || HasFreeDataStreamRead<T>::value;
630DataType::Ops makeDefaultOps();
644template <
typename T>
void registerAutoConverters(
const DataType &dt);
667template <
typename T> DataType registerDataType();
682template <
typename T> DataType registerDataType(DataTypeID
id,
const char *name, uint32_t version = 1);
692template <
typename T> DataType DataType::of() {
693 registerBuiltinDataTypes();
694 if constexpr (Detail::HasPromekiDataType<T>) {
695 static const DataType once = registerDataType<T>();
698 return DataType::byCppType(std::type_index(
typeid(T)));
702template <
typename T> DataType registerDataType() {
703 static_assert(Detail::HasPromekiDataType<T>,
704 "registerDataType<T>() with no arguments requires PROMEKI_DATATYPE on T; "
705 "use registerDataType<T>(id, name, version) for primitives and template "
706 "instantiations that cannot host the macro.");
707 DataType existing = DataType::byCppType(std::type_index(
typeid(T)));
708 if (existing.isValid())
return existing;
709 DataType dt = DataType::registerType(
710 T::promekiDataType::id, T::promekiDataType::name, T::promekiDataType::version,
711 std::type_index(
typeid(T)),
sizeof(T),
alignof(T),
712 Detail::makeDefaultOps<T>());
713 if (dt.isValid()) Detail::registerAutoConverters<T>(dt);
717template <
typename T> DataType registerDataType(DataTypeID
id,
const char *name, uint32_t version) {
718 DataType existing = DataType::byCppType(std::type_index(
typeid(T)));
719 if (existing.isValid())
return existing;
720 DataType dt = DataType::registerType(
721 id, name, version, std::type_index(
typeid(T)),
sizeof(T),
alignof(T),
722 Detail::makeDefaultOps<T>());
723 if (dt.isValid()) Detail::registerAutoConverters<T>(dt);
763#define PROMEKI_DATATYPE(TYPE, ID, VERSION) \
764 struct promekiDataType { \
766 static constexpr ::promeki::DataTypeID id = static_cast<::promeki::DataTypeID>(ID); \
767 static constexpr const char *name = #TYPE; \
768 static constexpr uint32_t version = (VERSION); \
769 static ::promeki::Result<Self> dispatchRead(::promeki::DataStream &s, uint32_t v) { \
770 return ::promeki::Detail::VersionedReader<Self, (VERSION)>::read(s, v); \