8 #include "datastream_p_p.h"
10 #include "protocol_p.h"
13 #include <type_traits>
18 #include <QJsonObject>
24 #undef AKONADI_DECLARE_PRIVATE
25 #define AKONADI_DECLARE_PRIVATE(Class) \
26 inline Class##Private *Class::d_func() \
28 return reinterpret_cast<Class##Private *>(d_ptr.data()); \
30 inline const Class##Private *Class::d_func() const \
32 return reinterpret_cast<const Class##Private *>(d_ptr.constData()); \
44 case Command::Invalid:
45 return dbg <<
"Invalid";
48 return dbg <<
"Hello";
50 return dbg <<
"Login";
52 return dbg <<
"Logout";
54 case Command::Transaction:
55 return dbg <<
"Transaction";
57 case Command::CreateItem:
58 return dbg <<
"CreateItem";
59 case Command::CopyItems:
60 return dbg <<
"CopyItems";
61 case Command::DeleteItems:
62 return dbg <<
"DeleteItems";
63 case Command::FetchItems:
64 return dbg <<
"FetchItems";
65 case Command::LinkItems:
66 return dbg <<
"LinkItems";
67 case Command::ModifyItems:
68 return dbg <<
"ModifyItems";
69 case Command::MoveItems:
70 return dbg <<
"MoveItems";
72 case Command::CreateCollection:
73 return dbg <<
"CreateCollection";
74 case Command::CopyCollection:
75 return dbg <<
"CopyCollection";
76 case Command::DeleteCollection:
77 return dbg <<
"DeleteCollection";
78 case Command::FetchCollections:
79 return dbg <<
"FetchCollections";
80 case Command::FetchCollectionStats:
81 return dbg <<
"FetchCollectionStats";
82 case Command::ModifyCollection:
83 return dbg <<
"ModifyCollection";
84 case Command::MoveCollection:
85 return dbg <<
"MoveCollection";
88 return dbg <<
"Search";
89 case Command::SearchResult:
90 return dbg <<
"SearchResult";
91 case Command::StoreSearch:
92 return dbg <<
"StoreSearch";
94 case Command::CreateTag:
95 return dbg <<
"CreateTag";
96 case Command::DeleteTag:
97 return dbg <<
"DeleteTag";
98 case Command::FetchTags:
99 return dbg <<
"FetchTags";
100 case Command::ModifyTag:
101 return dbg <<
"ModifyTag";
103 case Command::FetchRelations:
104 return dbg <<
"FetchRelations";
105 case Command::ModifyRelation:
106 return dbg <<
"ModifyRelation";
107 case Command::RemoveRelations:
108 return dbg <<
"RemoveRelations";
110 case Command::SelectResource:
111 return dbg <<
"SelectResource";
113 case Command::StreamPayload:
114 return dbg <<
"StreamPayload";
115 case Command::ItemChangeNotification:
116 return dbg <<
"ItemChangeNotification";
117 case Command::CollectionChangeNotification:
118 return dbg <<
"CollectionChangeNotification";
119 case Command::TagChangeNotification:
120 return dbg <<
"TagChangeNotification";
121 case Command::RelationChangeNotification:
122 return dbg <<
"RelationChangeNotification";
123 case Command::SubscriptionChangeNotification:
124 return dbg <<
"SubscriptionChangeNotification";
125 case Command::DebugChangeNotification:
126 return dbg <<
"DebugChangeNotification";
127 case Command::CreateSubscription:
128 return dbg <<
"CreateSubscription";
129 case Command::ModifySubscription:
130 return dbg <<
"ModifySubscription";
132 case Command::_ResponseBit:
134 return dbg << static_cast<int>(type);
138 return dbg << static_cast<int>(type);
143 Protocol::serialize(stream, ptr);
149 ptr = Protocol::deserialize(stream.device()).
staticCast<T>();
155 Command::Command(quint8 type)
160 bool Command::operator==(
const Command &other)
const
162 return mType == other.mType;
167 json[QStringLiteral(
"response")] =
static_cast<bool>(mType & Command::_ResponseBit);
169 #define case_label(x) \
171 json[QStringLiteral("type")] = QStringLiteral(#x); \
174 switch (mType & ~Command::_ResponseBit) {
175 case_label(Invalid) case_label(Hello)
177 case_label(Login) case_label(Logout)
179 case_label(Transaction)
181 case_label(CreateItem) case_label(CopyItems) case_label(DeleteItems) case_label(FetchItems) case_label(LinkItems) case_label(ModifyItems)
182 case_label(MoveItems)
184 case_label(CreateCollection) case_label(CopyCollection) case_label(DeleteCollection) case_label(FetchCollections)
185 case_label(FetchCollectionStats) case_label(ModifyCollection) case_label(MoveCollection)
187 case_label(Search) case_label(SearchResult) case_label(StoreSearch)
189 case_label(CreateTag) case_label(DeleteTag) case_label(FetchTags) case_label(ModifyTag)
191 case_label(FetchRelations) case_label(ModifyRelation) case_label(RemoveRelations)
193 case_label(SelectResource)
195 case_label(StreamPayload) case_label(CreateSubscription) case_label(ModifySubscription)
197 case_label(DebugChangeNotification) case_label(ItemChangeNotification)
198 case_label(CollectionChangeNotification) case_label(TagChangeNotification)
199 case_label(RelationChangeNotification) case_label(SubscriptionChangeNotification)
204 DataStream &
operator<<(DataStream &stream,
const Command &cmd)
206 return stream << cmd.mType;
209 DataStream &
operator>>(DataStream &stream, Command &cmd)
211 return stream >> cmd.mType;
216 return dbg.
noquote() << ((cmd.mType & Command::_ResponseBit) ?
"Response:" :
"Command:") <<
static_cast<Command::Type
>(cmd.mType & ~Command::_ResponseBit)
220 void toJson(
const Akonadi::Protocol::Command *command,
QJsonObject &json)
222 #define case_notificationlabel(x, class) \
224 static_cast<const Akonadi::Protocol::class *>(command)->toJson(json); \
226 #define case_commandlabel(x, cmd, resp) \
228 static_cast<const Akonadi::Protocol::cmd *>(command)->toJson(json); \
230 case Command::x | Command::_ResponseBit: { \
231 static_cast<const Akonadi::Protocol::resp *>(command)->toJson(json); \
234 switch (command->mType) {
235 case Command::Invalid:
238 case Command::Hello | Command::_ResponseBit: {
239 static_cast<const Akonadi::Protocol::HelloResponse *
>(command)->toJson(json);
241 case_commandlabel(Login, LoginCommand, LoginResponse) case_commandlabel(Logout, LogoutCommand, LogoutResponse)
243 case_commandlabel(Transaction, TransactionCommand, TransactionResponse)
245 case_commandlabel(CreateItem, CreateItemCommand, CreateItemResponse) case_commandlabel(CopyItems, CopyItemsCommand, CopyItemsResponse)
246 case_commandlabel(DeleteItems, DeleteItemsCommand, DeleteItemsResponse) case_commandlabel(FetchItems, FetchItemsCommand, FetchItemsResponse)
247 case_commandlabel(LinkItems, LinkItemsCommand, LinkItemsResponse) case_commandlabel(
250 ModifyItemsResponse) case_commandlabel(MoveItems, MoveItemsCommand, MoveItemsResponse)
252 case_commandlabel(CreateCollection, CreateCollectionCommand, CreateCollectionResponse) case_commandlabel(
254 CopyCollectionCommand,
255 CopyCollectionResponse) case_commandlabel(DeleteCollection, DeleteCollectionCommand, DeleteCollectionResponse)
256 case_commandlabel(FetchCollections, FetchCollectionsCommand, FetchCollectionsResponse) case_commandlabel(
257 FetchCollectionStats,
258 FetchCollectionStatsCommand,
259 FetchCollectionStatsResponse) case_commandlabel(ModifyCollection, ModifyCollectionCommand, ModifyCollectionResponse)
260 case_commandlabel(MoveCollection, MoveCollectionCommand, MoveCollectionResponse)
262 case_commandlabel(Search, SearchCommand, SearchResponse) case_commandlabel(
265 SearchResultResponse) case_commandlabel(StoreSearch, StoreSearchCommand, StoreSearchResponse)
267 case_commandlabel(CreateTag, CreateTagCommand, CreateTagResponse)
268 case_commandlabel(DeleteTag, DeleteTagCommand, DeleteTagResponse)
269 case_commandlabel(FetchTags, FetchTagsCommand, FetchTagsResponse)
270 case_commandlabel(ModifyTag, ModifyTagCommand, ModifyTagResponse)
272 case_commandlabel(FetchRelations, FetchRelationsCommand, FetchRelationsResponse)
273 case_commandlabel(ModifyRelation, ModifyRelationCommand, ModifyRelationResponse)
274 case_commandlabel(RemoveRelations, RemoveRelationsCommand, RemoveRelationsResponse)
276 case_commandlabel(SelectResource, SelectResourceCommand, SelectResourceResponse)
278 case_commandlabel(StreamPayload, StreamPayloadCommand, StreamPayloadResponse)
281 CreateSubscriptionCommand,
282 CreateSubscriptionResponse) case_commandlabel(ModifySubscription,
283 ModifySubscriptionCommand,
284 ModifySubscriptionResponse)
286 case_notificationlabel(DebugChangeNotification, DebugChangeNotification)
287 case_notificationlabel(ItemChangeNotification, ItemChangeNotification)
288 case_notificationlabel(CollectionChangeNotification,
289 CollectionChangeNotification)
290 case_notificationlabel(TagChangeNotification,
291 TagChangeNotification)
292 case_notificationlabel(RelationChangeNotification,
293 RelationChangeNotification)
294 case_notificationlabel(SubscriptionChangeNotification,
295 SubscriptionChangeNotification)
297 #undef case_notificationlabel
298 #undef case_commandlabel
304 : Command(Command::Invalid | Command::_ResponseBit)
309 Response::Response(Command::Type type)
310 : Command(
type | Command::_ResponseBit)
315 bool Response::operator==(
const Response &other)
const
317 return *
static_cast<const Command *
>(
this) ==
static_cast<const Command &
>(other) && mErrorCode == other.mErrorCode && mErrorMsg == other.mErrorMsg;
322 static_cast<const Command *
>(
this)->toJson(json);
325 error[QStringLiteral(
"code")] = errorCode();
327 json[QStringLiteral(
"error")] =
error;
329 json[QStringLiteral(
"error")] =
false;
333 DataStream &
operator<<(DataStream &stream,
const Response &cmd)
335 return stream << static_cast<const Command &>(cmd) << cmd.mErrorCode << cmd.mErrorMsg;
338 DataStream &
operator>>(DataStream &stream, Response &cmd)
340 return stream >>
static_cast<Command &
>(cmd) >> cmd.mErrorCode >> cmd.mErrorMsg;
345 return dbg.
noquote() <<
static_cast<const Command &
>(resp) <<
"Error code:" << resp.mErrorCode <<
"\n"
346 <<
"Error msg:" << resp.mErrorMsg <<
"\n";
354 typedef CommandPtr (*CommandFactoryFunc)();
355 typedef ResponsePtr (*ResponseFactoryFunc)();
360 registerType<Command::Hello, Command , HelloResponse>();
361 registerType<Command::Login, LoginCommand, LoginResponse>();
362 registerType<Command::Logout, LogoutCommand, LogoutResponse>();
365 registerType<Command::Transaction, TransactionCommand, TransactionResponse>();
368 registerType<Command::CreateItem, CreateItemCommand, CreateItemResponse>();
369 registerType<Command::CopyItems, CopyItemsCommand, CopyItemsResponse>();
370 registerType<Command::DeleteItems, DeleteItemsCommand, DeleteItemsResponse>();
371 registerType<Command::FetchItems, FetchItemsCommand, FetchItemsResponse>();
372 registerType<Command::LinkItems, LinkItemsCommand, LinkItemsResponse>();
373 registerType<Command::ModifyItems, ModifyItemsCommand, ModifyItemsResponse>();
374 registerType<Command::MoveItems, MoveItemsCommand, MoveItemsResponse>();
377 registerType<Command::CreateCollection, CreateCollectionCommand, CreateCollectionResponse>();
378 registerType<Command::CopyCollection, CopyCollectionCommand, CopyCollectionResponse>();
379 registerType<Command::DeleteCollection, DeleteCollectionCommand, DeleteCollectionResponse>();
380 registerType<Command::FetchCollections, FetchCollectionsCommand, FetchCollectionsResponse>();
381 registerType<Command::FetchCollectionStats, FetchCollectionStatsCommand, FetchCollectionStatsResponse>();
382 registerType<Command::ModifyCollection, ModifyCollectionCommand, ModifyCollectionResponse>();
383 registerType<Command::MoveCollection, MoveCollectionCommand, MoveCollectionResponse>();
386 registerType<Command::Search, SearchCommand, SearchResponse>();
387 registerType<Command::SearchResult, SearchResultCommand, SearchResultResponse>();
388 registerType<Command::StoreSearch, StoreSearchCommand, StoreSearchResponse>();
391 registerType<Command::CreateTag, CreateTagCommand, CreateTagResponse>();
392 registerType<Command::DeleteTag, DeleteTagCommand, DeleteTagResponse>();
393 registerType<Command::FetchTags, FetchTagsCommand, FetchTagsResponse>();
394 registerType<Command::ModifyTag, ModifyTagCommand, ModifyTagResponse>();
397 registerType<Command::FetchRelations, FetchRelationsCommand, FetchRelationsResponse>();
398 registerType<Command::ModifyRelation, ModifyRelationCommand, ModifyRelationResponse>();
399 registerType<Command::RemoveRelations, RemoveRelationsCommand, RemoveRelationsResponse>();
402 registerType<Command::SelectResource, SelectResourceCommand, SelectResourceResponse>();
405 registerType<Command::StreamPayload, StreamPayloadCommand, StreamPayloadResponse>();
406 registerType<Command::ItemChangeNotification, ItemChangeNotification, Response >();
407 registerType<Command::CollectionChangeNotification, CollectionChangeNotification, Response >();
408 registerType<Command::TagChangeNotification, TagChangeNotification, Response >();
409 registerType<Command::RelationChangeNotification, RelationChangeNotification, Response >();
410 registerType<Command::SubscriptionChangeNotification, SubscriptionChangeNotification, Response >();
411 registerType<Command::DebugChangeNotification, DebugChangeNotification, Response >();
412 registerType<Command::CreateSubscription, CreateSubscriptionCommand, CreateSubscriptionResponse>();
413 registerType<Command::ModifySubscription, ModifySubscriptionCommand, ModifySubscriptionResponse>();
421 template<
typename T>
static CommandPtr commandFactoryFunc()
425 template<
typename T>
static ResponsePtr responseFactoryFunc()
430 template<Command::Type T,
typename CmdType,
typename RespType>
void registerType()
432 CommandFactoryFunc cmdFunc = &commandFactoryFunc<CmdType>;
433 ResponseFactoryFunc respFunc = &responseFactoryFunc<RespType>;
434 registrar.
insert(T, qMakePair(cmdFunc, respFunc));
440 CommandPtr Factory::command(Command::Type type)
442 auto iter = sFactoryPrivate->registrar.constFind(type);
443 if (iter == sFactoryPrivate->registrar.constEnd()) {
446 return iter->first();
449 ResponsePtr Factory::response(Command::Type type)
451 auto iter = sFactoryPrivate->registrar.constFind(type);
452 if (iter == sFactoryPrivate->registrar.constEnd()) {
455 return iter->second();
462 bool ItemFetchScope::operator==(
const ItemFetchScope &other)
const
464 return mRequestedParts == other.mRequestedParts && mChangedSince == other.mChangedSince && mAncestorDepth == other.mAncestorDepth && mFlags == other.mFlags;
470 std::copy_if(mRequestedParts.begin(), mRequestedParts.end(), std::back_inserter(rv), [](
const QByteArray &ba) {
471 return ba.startsWith(
"PLD:");
476 void ItemFetchScope::setFetch(FetchFlags attributes,
bool fetch)
481 if (!mRequestedParts.contains(AKONADI_PARAM_PLD_RFC822)) {
482 mRequestedParts << AKONADI_PARAM_PLD_RFC822;
490 bool ItemFetchScope::fetch(FetchFlags flags)
const
493 return mFlags ==
None;
495 return mFlags & flags;
499 void ItemFetchScope::toJson(
QJsonObject &json)
const
501 json[QStringLiteral(
"flags")] =
static_cast<int>(mFlags);
502 json[QStringLiteral(
"ChangedSince")] = mChangedSince.toString();
503 json[QStringLiteral(
"AncestorDepth")] =
static_cast<std::underlying_type<AncestorDepth>::type
>(mAncestorDepth);
506 for (
const auto &part : std::as_const(mRequestedParts)) {
509 json[QStringLiteral(
"RequestedParts")] = requestedPartsArray;
515 case ItemFetchScope::NoAncestor:
516 return dbg <<
"No ancestor";
517 case ItemFetchScope::ParentAncestor:
518 return dbg <<
"Parent ancestor";
519 case ItemFetchScope::AllAncestors:
520 return dbg <<
"All ancestors";
525 DataStream &
operator<<(DataStream &stream,
const ItemFetchScope &scope)
527 return stream << scope.mRequestedParts << scope.mChangedSince << scope.mAncestorDepth << scope.mFlags;
530 DataStream &
operator>>(DataStream &stream, ItemFetchScope &scope)
532 return stream >> scope.mRequestedParts >> scope.mChangedSince >> scope.mAncestorDepth >> scope.mFlags;
537 return dbg.
noquote() <<
"FetchScope(\n"
538 <<
"Fetch Flags:" << scope.mFlags <<
"\n"
539 <<
"Changed Since:" << scope.mChangedSince <<
"\n"
540 <<
"Ancestor Depth:" << scope.mAncestorDepth <<
"\n"
541 <<
"Requested Parts:" << scope.mRequestedParts <<
")\n";
546 ScopeContext::ScopeContext(Type type, qint64
id)
548 if (type == ScopeContext::Tag) {
550 }
else if (type == ScopeContext::Collection) {
555 ScopeContext::ScopeContext(Type type,
const QString &ctx)
557 if (type == ScopeContext::Tag) {
559 }
else if (type == ScopeContext::Collection) {
564 bool ScopeContext::operator==(
const ScopeContext &other)
const
566 return mColCtx == other.mColCtx && mTagCtx == other.mTagCtx;
572 json[QStringLiteral(
"scopeContext")] =
false;
573 }
else if (hasContextId(ScopeContext::Tag)) {
574 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"tag");
575 json[QStringLiteral(
"TagID")] = contextId(ScopeContext::Tag);
576 }
else if (hasContextId(ScopeContext::Collection)) {
577 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"collection");
578 json[QStringLiteral(
"ColID")] = contextId(ScopeContext::Collection);
579 }
else if (hasContextRID(ScopeContext::Tag)) {
580 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"tagrid");
581 json[QStringLiteral(
"TagRID")] = contextRID(ScopeContext::Tag);
582 }
else if (hasContextRID(ScopeContext::Collection)) {
583 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"colrid");
584 json[QStringLiteral(
"ColRID")] = contextRID(ScopeContext::Collection);
588 DataStream &
operator<<(DataStream &stream,
const ScopeContext &context)
596 stream << context.mColCtx.toLongLong();
598 stream << context.mColCtx.toString();
601 vType = context.mTagCtx.type();
604 stream << context.mTagCtx.toLongLong();
606 stream << context.mTagCtx.toString();
612 DataStream &
operator>>(DataStream &stream, ScopeContext &context)
618 for (ScopeContext::Type type : {ScopeContext::Collection, ScopeContext::Tag}) {
622 context.setContext(type,
id);
625 context.setContext(type, rid);
635 dbg <<
"ScopeContext(";
638 }
else if (ctx.hasContextId(ScopeContext::Tag)) {
639 dbg <<
"Tag ID:" << ctx.contextId(ScopeContext::Tag);
640 }
else if (ctx.hasContextId(ScopeContext::Collection)) {
641 dbg <<
"Col ID:" << ctx.contextId(ScopeContext::Collection);
642 }
else if (ctx.hasContextRID(ScopeContext::Tag)) {
643 dbg <<
"Tag RID:" << ctx.contextRID(ScopeContext::Tag);
644 }
else if (ctx.hasContextRID(ScopeContext::Collection)) {
645 dbg <<
"Col RID:" << ctx.contextRID(ScopeContext::Collection);
652 ChangeNotification::ChangeNotification(Command::Type type)
657 bool ChangeNotification::operator==(
const ChangeNotification &other)
const
659 return static_cast<const Command &
>(*this) == other && mSessionId == other.mSessionId;
667 std::transform(items.
cbegin(), items.
cend(), std::back_inserter(rv), [](
const FetchItemsResponse &item) {
673 bool ChangeNotification::isRemove()
const
676 case Command::Invalid:
678 case Command::ItemChangeNotification:
679 return static_cast<const class ItemChangeNotification *
>(
this)->operation() == ItemChangeNotification::Remove;
680 case Command::CollectionChangeNotification:
681 return static_cast<const class CollectionChangeNotification *
>(
this)->operation() == CollectionChangeNotification::Remove;
682 case Command::TagChangeNotification:
683 return static_cast<const class TagChangeNotification *
>(
this)->operation() == TagChangeNotification::Remove;
684 case Command::RelationChangeNotification:
685 return static_cast<const class RelationChangeNotification *
>(
this)->operation() == RelationChangeNotification::Remove;
686 case Command::SubscriptionChangeNotification:
687 return static_cast<const class SubscriptionChangeNotification *
>(
this)->operation() == SubscriptionChangeNotification::Remove;
688 case Command::DebugChangeNotification:
691 Q_ASSERT_X(
false, __FUNCTION__,
"Unknown ChangeNotification type");
697 bool ChangeNotification::isMove()
const
700 case Command::Invalid:
702 case Command::ItemChangeNotification:
703 return static_cast<const class ItemChangeNotification *
>(
this)->operation() == ItemChangeNotification::Move;
704 case Command::CollectionChangeNotification:
705 return static_cast<const class CollectionChangeNotification *
>(
this)->operation() == CollectionChangeNotification::Move;
706 case Command::TagChangeNotification:
707 case Command::RelationChangeNotification:
708 case Command::SubscriptionChangeNotification:
709 case Command::DebugChangeNotification:
712 Q_ASSERT_X(
false, __FUNCTION__,
"Unknown ChangeNotification type");
718 bool ChangeNotification::appendAndCompress(ChangeNotificationList &list,
const ChangeNotificationPtr &msg)
721 static const int maxCompressionSearchLength = 10;
722 int searchCounter = 0;
726 if (msg->type() == Command::CollectionChangeNotification) {
727 const auto &cmsg = Protocol::cmdCast<class CollectionChangeNotification>(msg);
728 if (cmsg.operation() == CollectionChangeNotification::Modify) {
733 if ((*iter)->type() == Protocol::Command::CollectionChangeNotification) {
734 auto &it = Protocol::cmdCast<class CollectionChangeNotification>(*iter);
735 const auto &msgCol = cmsg.collection();
736 const auto &itCol = it.collection();
737 if (msgCol.id() == itCol.id() && msgCol.remoteId() == itCol.remoteId() && msgCol.remoteRevision() == itCol.remoteRevision()
738 && msgCol.resource() == itCol.resource() && cmsg.destinationResource() == it.destinationResource()
739 && cmsg.parentCollection() == it.parentCollection() && cmsg.parentDestCollection() == it.parentDestCollection()) {
741 if (cmsg.operation() == CollectionChangeNotification::Modify && it.operation() == CollectionChangeNotification::Modify) {
742 const auto parts = it.changedParts();
743 it.setChangedParts(parts + cmsg.changedParts());
748 if (it.operation() == CollectionChangeNotification::Add) {
754 if (searchCounter >= maxCompressionSearchLength) {
766 void ChangeNotification::toJson(
QJsonObject &json)
const
768 static_cast<const Command *
>(
this)->toJson(json);
772 for (
const auto &m : std::as_const(mMetaData)) {
775 json[QStringLiteral(
"metadata")] = metadata;
778 DataStream &
operator<<(DataStream &stream,
const ChangeNotification &ntf)
780 return stream << static_cast<const Command &>(ntf) << ntf.mSessionId;
783 DataStream &
operator>>(DataStream &stream, ChangeNotification &ntf)
785 return stream >>
static_cast<Command &
>(ntf) >> ntf.mSessionId;
790 return dbg.
noquote() <<
static_cast<const Command &
>(ntf) <<
"Session:" << ntf.mSessionId <<
"\n"
791 <<
"MetaData:" << ntf.mMetaData <<
"\n";
794 DataStream &
operator>>(DataStream &stream, ChangeNotification::Relation &relation)
796 return stream >> relation.type >> relation.leftId >> relation.rightId;
799 DataStream &
operator<<(DataStream &stream,
const ChangeNotification::Relation &relation)
801 return stream << relation.type << relation.leftId << relation.rightId;
807 return dbg <<
"Left: " << rel.leftId <<
", Right:" << rel.rightId <<
", Type: " << rel.type;
818 template<
typename Value,
template<
typename>
class Container>
inline bool containerComparator(
const Container<Value> &c1,
const Container<Value> &c2)
823 template<
typename T,
template<
typename>
class Container>
826 if (c1.size() != c2.size()) {
830 for (
auto it1 = c1.cbegin(), it2 = c2.cbegin(), end1 = c1.cend(); it1 != end1; ++it1, ++it2) {
831 if (**it1 != **it2) {
844 #include "protocol_gen.cpp"