Skip to content

Commit 905060a

Browse files
committed
Implement new KVP MoQ structure
- Add for parameters - Consolidate uint64_t enum coding - Move parameters to new structure
1 parent ef00f72 commit 905060a

File tree

3 files changed

+149
-113
lines changed

3 files changed

+149
-113
lines changed

include/quicr/detail/ctrl_message_types.h

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,71 @@ namespace quicr::messages {
1919
using GroupId = uint64_t;
2020
using ObjectId = uint64_t;
2121

22+
/// MoQ Key Value Pair.
23+
template<typename T>
24+
concept KeyType =
25+
std::same_as<T, std::uint64_t> || (std::is_enum_v<T> && std::same_as<std::underlying_type_t<T>, std::uint64_t>);
26+
template<KeyType T>
27+
struct KeyValuePair
28+
{
29+
T type;
30+
Bytes value;
31+
};
32+
template<KeyType T>
33+
Bytes& operator<<(Bytes& buffer, const KeyValuePair<T>& param)
34+
{
35+
const auto type = static_cast<std::uint64_t>(param.type);
36+
buffer << UintVar(type);
37+
if (type % 2 == 0) {
38+
// Even, single varint of value.
39+
assert(param.value.size() <= 8);
40+
std::uint64_t val = 0;
41+
std::memcpy(&val, param.value.data(), std::min(param.value.size(), sizeof(std::uint64_t)));
42+
buffer << UintVar(val);
43+
} else {
44+
// Odd, encode bytes.
45+
buffer << UintVar(param.value.size());
46+
buffer.insert(buffer.end(), param.value.begin(), param.value.end());
47+
}
48+
return buffer;
49+
}
50+
template<KeyType T>
51+
BytesSpan operator>>(BytesSpan buffer, KeyValuePair<T>& param)
52+
{
53+
std::uint64_t type;
54+
buffer = buffer >> type;
55+
param.type = static_cast<T>(type);
56+
if (type % 2 == 0) {
57+
// Even, single varint of value.
58+
std::uint64_t val;
59+
buffer = buffer >> val;
60+
param.value.resize(sizeof(std::uint64_t));
61+
std::memcpy(param.value.data(), &val, sizeof(std::uint64_t));
62+
} else {
63+
// Odd, decode bytes.
64+
uint64_t size = 0;
65+
buffer = buffer >> size;
66+
param.value.assign(buffer.begin(), std::next(buffer.begin(), size));
67+
}
68+
return buffer;
69+
}
70+
71+
// Serialization for all uint64_t/enum(uint64_t to varint).
72+
template<KeyType T>
73+
Bytes& operator<<(Bytes& buffer, const T value)
74+
{
75+
buffer << UintVar(static_cast<std::uint64_t>(value));
76+
return buffer;
77+
}
78+
template<KeyType T>
79+
BytesSpan operator>>(BytesSpan buffer, T& value)
80+
{
81+
std::uint64_t uvalue;
82+
buffer = buffer >> uvalue;
83+
value = static_cast<T>(uvalue);
84+
return buffer;
85+
}
86+
2287
enum struct ParameterType : uint64_t
2388
{
2489
kPath = 0x1,
@@ -27,14 +92,7 @@ namespace quicr::messages {
2792
kInvalid = 0xFF, // used internally.
2893
};
2994

30-
struct Parameter
31-
{
32-
ParameterType type{ 0 };
33-
Bytes value;
34-
};
35-
36-
Bytes& operator<<(Bytes& buffer, ParameterType value);
37-
BytesSpan operator>>(BytesSpan buffer, ParameterType& value);
95+
using Parameter = KeyValuePair<ParameterType>;
3896

3997
enum struct GroupOrder : uint8_t
4098
{
@@ -55,9 +113,6 @@ namespace quicr::messages {
55113
kAbsoluteRange
56114
};
57115

58-
Bytes& operator<<(Bytes& buffer, FilterType value);
59-
BytesSpan operator>>(BytesSpan buffer, FilterType& value);
60-
61116
enum class TrackStatusCode : uint64_t
62117
{
63118
kInProgress = 0x00,
@@ -67,9 +122,6 @@ namespace quicr::messages {
67122
kUnknown
68123
};
69124

70-
Bytes& operator<<(Bytes& buffer, TrackStatusCode value);
71-
BytesSpan operator>>(BytesSpan buffer, TrackStatusCode& value);
72-
73125
enum class SubscribeDoneStatusCode : uint64_t
74126
{
75127
kInternalError = 0x00,
@@ -81,9 +133,6 @@ namespace quicr::messages {
81133
kTooFarBehind,
82134
};
83135

84-
Bytes& operator<<(Bytes& buffer, SubscribeDoneStatusCode value);
85-
BytesSpan operator>>(BytesSpan buffer, SubscribeDoneStatusCode& value);
86-
87136
enum class FetchType : uint8_t
88137
{
89138
kStandalone = 0x1,
@@ -104,9 +153,6 @@ namespace quicr::messages {
104153
kGoAwayTimeout = 0x10,
105154
};
106155

107-
Bytes& operator<<(Bytes& buffer, TerminationReason value);
108-
BytesSpan operator>>(BytesSpan buffer, TerminationReason& value);
109-
110156
enum class FetchErrorCode : uint8_t
111157
{
112158
kInternalError = 0x0,
@@ -129,9 +175,6 @@ namespace quicr::messages {
129175
kUninterested
130176
};
131177

132-
Bytes& operator<<(Bytes& buffer, AnnounceErrorCode value);
133-
BytesSpan operator>>(BytesSpan buffer, AnnounceErrorCode& value);
134-
135178
// TODO (Suhas): rename it to StreamMapping
136179
enum ForwardingPreference : uint8_t
137180
{
@@ -158,9 +201,6 @@ namespace quicr::messages {
158201
kTrackNotExist = 0xF0 // Missing in draft
159202
};
160203

161-
Bytes& operator<<(Bytes& buffer, SubscribeErrorCode value);
162-
BytesSpan operator>>(BytesSpan buffer, SubscribeErrorCode& value);
163-
164204
enum class SubscribeAnnouncesErrorCode : uint64_t
165205
{
166206
kInternalError = 0x0,
@@ -169,7 +209,4 @@ namespace quicr::messages {
169209
kNotSupported,
170210
kNamespacePrefixUnknown,
171211
};
172-
173-
Bytes& operator<<(Bytes& buffer, SubscribeAnnouncesErrorCode value);
174-
BytesSpan operator>>(BytesSpan buffer, SubscribeAnnouncesErrorCode& value);
175212
} // namespace

src/ctrl_message_types.cpp

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,6 @@ namespace quicr::messages {
5858
return buffer.subspan(value_uv.size());
5959
}
6060

61-
Bytes& operator<<(Bytes& buffer, ParameterType value)
62-
{
63-
buffer << UintVar(static_cast<std::uint64_t>(value));
64-
return buffer;
65-
}
66-
67-
BytesSpan operator>>(BytesSpan buffer, ParameterType& value)
68-
{
69-
std::uint64_t uvalue;
70-
buffer = buffer >> uvalue;
71-
value = static_cast<ParameterType>(uvalue);
72-
return buffer;
73-
}
74-
7561
Bytes& operator<<(Bytes& buffer, GroupOrder value)
7662
{
7763
buffer << static_cast<std::uint64_t>(value);
@@ -86,20 +72,6 @@ namespace quicr::messages {
8672
return buffer;
8773
}
8874

89-
Bytes& operator<<(Bytes& buffer, FilterType value)
90-
{
91-
buffer << static_cast<std::uint64_t>(value);
92-
return buffer;
93-
}
94-
95-
BytesSpan operator>>(BytesSpan buffer, FilterType& value)
96-
{
97-
std::uint64_t uvalue;
98-
buffer = buffer >> uvalue;
99-
value = static_cast<FilterType>(uvalue);
100-
return buffer;
101-
}
102-
10375
Bytes& operator<<(Bytes& buffer, FetchType value)
10476
{
10577
buffer << static_cast<std::uint64_t>(value);
@@ -114,34 +86,6 @@ namespace quicr::messages {
11486
return buffer;
11587
}
11688

117-
Bytes& operator<<(Bytes& buffer, AnnounceErrorCode value)
118-
{
119-
buffer << static_cast<std::uint64_t>(value);
120-
return buffer;
121-
}
122-
123-
BytesSpan operator>>(BytesSpan buffer, AnnounceErrorCode& value)
124-
{
125-
std::uint64_t uvalue;
126-
buffer = buffer >> uvalue;
127-
value = static_cast<AnnounceErrorCode>(uvalue);
128-
return buffer;
129-
}
130-
131-
Bytes& operator<<(Bytes& buffer, SubscribeAnnouncesErrorCode value)
132-
{
133-
buffer << static_cast<std::uint64_t>(value);
134-
return buffer;
135-
}
136-
137-
BytesSpan operator>>(BytesSpan buffer, SubscribeAnnouncesErrorCode& value)
138-
{
139-
std::uint64_t uvalue;
140-
buffer = buffer >> uvalue;
141-
value = static_cast<SubscribeAnnouncesErrorCode>(uvalue);
142-
return buffer;
143-
}
144-
14589
Bytes& operator<<(Bytes& buffer, FetchErrorCode value)
14690
{
14791
buffer << static_cast<std::uint64_t>(value);
@@ -156,32 +100,4 @@ namespace quicr::messages {
156100
return buffer;
157101
}
158102

159-
Bytes& operator<<(Bytes& buffer, SubscribeDoneStatusCode value)
160-
{
161-
buffer << static_cast<std::uint64_t>(value);
162-
return buffer;
163-
}
164-
165-
BytesSpan operator>>(BytesSpan buffer, SubscribeDoneStatusCode& value)
166-
{
167-
std::uint64_t uvalue;
168-
buffer = buffer >> uvalue;
169-
value = static_cast<SubscribeDoneStatusCode>(uvalue);
170-
return buffer;
171-
}
172-
173-
Bytes& operator<<(Bytes& buffer, SubscribeErrorCode value)
174-
{
175-
buffer << static_cast<std::uint64_t>(value);
176-
return buffer;
177-
}
178-
179-
BytesSpan operator>>(BytesSpan buffer, SubscribeErrorCode& value)
180-
{
181-
std::uint64_t uvalue;
182-
buffer = buffer >> uvalue;
183-
value = static_cast<SubscribeErrorCode>(uvalue);
184-
return buffer;
185-
}
186-
187103
}

test/moq_ctrl_messages.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,3 +896,86 @@ TEST_CASE("Subscribe Announces Error encode/decode")
896896
CHECK_EQ(msg.error_code, msg_out.error_code);
897897
CHECK_EQ(msg.reason_phrase, msg_out.reason_phrase);
898898
}
899+
900+
using TestKVP64 = KeyValuePair<std::uint64_t>;
901+
enum class ExampleEnum : std::uint64_t
902+
{
903+
kOdd = 1,
904+
kEven = 2,
905+
};
906+
using TestKVPEnum = KeyValuePair<ExampleEnum>;
907+
Bytes
908+
kvp64(const std::uint64_t type, const Bytes& value)
909+
{
910+
TestKVP64 test;
911+
test.type = type;
912+
test.value = value;
913+
Bytes buffer;
914+
buffer << test;
915+
return buffer;
916+
}
917+
Bytes
918+
kvpEnum(const ExampleEnum type, const Bytes& value)
919+
{
920+
TestKVPEnum test;
921+
test.type = type;
922+
test.value = value;
923+
Bytes buffer;
924+
buffer << test;
925+
return buffer;
926+
}
927+
928+
TEST_CASE("Key Value Pair encode/decode")
929+
{
930+
auto value = Bytes(sizeof(std::uint64_t));
931+
constexpr std::uint64_t one = 1;
932+
std::memcpy(value.data(), &one, value.size());
933+
{
934+
CAPTURE("UINT64_T");
935+
{
936+
CAPTURE("EVEN");
937+
std::size_t type = 2;
938+
Bytes serialized = kvp64(type, value);
939+
CHECK_EQ(serialized.size(), 2); // Minimal size, 1 byte for type and 1 byte for value.
940+
TestKVP64 out;
941+
serialized >> out;
942+
CHECK_EQ(out.type, type);
943+
CHECK_EQ(out.value, value);
944+
}
945+
{
946+
CAPTURE("ODD");
947+
std::size_t type = 1;
948+
Bytes serialized = kvp64(type, value);
949+
CHECK_EQ(serialized.size(),
950+
value.size() + 1 + 1); // 1 byte for type, 1 byte for length, and the value bytes.
951+
TestKVP64 out;
952+
serialized >> out;
953+
CHECK_EQ(out.type, type);
954+
CHECK_EQ(out.value, value);
955+
}
956+
}
957+
{
958+
CAPTURE("ENUM");
959+
{
960+
CAPTURE("EVEN");
961+
auto type = ExampleEnum::kEven;
962+
Bytes serialized = kvpEnum(type, value);
963+
CHECK_EQ(serialized.size(), 2); // Minimal size, 1 byte for type and 1 byte for value.
964+
TestKVPEnum out;
965+
serialized >> out;
966+
CHECK_EQ(out.type, type);
967+
CHECK_EQ(out.value, value);
968+
}
969+
{
970+
CAPTURE("ODD");
971+
auto type = ExampleEnum::kOdd;
972+
Bytes serialized = kvpEnum(type, value);
973+
CHECK_EQ(serialized.size(),
974+
value.size() + 1 + 1); // 1 byte for type, 1 byte for length, and the value bytes.
975+
TestKVPEnum out;
976+
serialized >> out;
977+
CHECK_EQ(out.type, type);
978+
CHECK_EQ(out.value, value);
979+
}
980+
}
981+
}

0 commit comments

Comments
 (0)