26#include <QtCore/QJsonObject>
27#include <QtCore/QJsonDocument>
28#include <QtCore/QByteArray>
30#include "cc_tools_qt/ErrorStatus.h"
31#include "comms/util/ScopeGuard.h"
32#include "comms/util/Tuple.h"
36#include "RawDataMessage.h"
37#include "InvalidMessage.h"
38#include "ExtraInfoMessage.h"
54 typename TTransportMsg,
55 typename TRawDataMsg = RawDataMessage<TProtStack> >
73 static_assert(!std::is_void<ProtocolMsgPtr>::value,
74 "ProtocolStack does not define MsgPtr");
80 using MsgIdType =
typename ProtocolMessage::MsgIdType;
99 !std::is_void<AllMessages>::value,
100 "AllMessages must be a normal type");
103 comms::util::IsTuple<AllMessages>::Value,
104 "AllMessages is expected to be a tuple.");
109 const std::uint8_t* iter = &dataInfo.
m_data[0];
110 auto size = dataInfo.
m_data.size();
113 m_data.reserve(m_data.size() + size);
114 std::copy_n(iter, size, std::back_inserter(m_data));
116 using ReadIterator =
typename ProtocolMessage::ReadIterator;
117 ReadIterator readIterBeg = &m_data[0];
119 auto remainingSizeCalc =
120 [
this](ReadIterator readIter) -> std::size_t
122 ReadIterator
const dataBegin = &m_data[0];
124 static_cast<std::size_t
>(
125 std::distance(dataBegin, readIter));
126 assert(consumed <= m_data.size());
127 return m_data.size() - consumed;
131 comms::util::makeScopeGuard(
132 [
this, &readIterBeg]()
134 ReadIterator dataBegin = &m_data[0];
135 auto dist = std::distance(dataBegin, readIterBeg);
136 m_data.erase(m_data.begin(), m_data.begin() + dist);
139 auto setExtraInfoFunc =
147 QJsonDocument doc(jsonObj);
149 std::unique_ptr<ExtraInfoMsg> extraInfoMsgPtr(
new ExtraInfoMsg());
150 auto& str = std::get<0>(extraInfoMsgPtr->fields());
151 str.value() = doc.toJson().constData();
158 auto checkGarbageFunc =
159 [
this, &allMsgs, &setExtraInfoFunc]()
161 if (!m_garbage.empty()) {
164 std::unique_ptr<RawDataMsg> rawDataMsgPtr(
new RawDataMsg());
165 ReadIterator garbageReadIterator = &m_garbage[0];
166 [[maybe_unused]]
auto esTmp = rawDataMsgPtr->read(garbageReadIterator, m_garbage.size());
167 assert(esTmp == comms::ErrorStatus::Success);
169 setExtraInfoFunc(*invalidMsgPtr);
170 allMsgs.push_back(std::move(invalidMsgPtr));
178 auto readIterCur = readIterBeg;
179 auto remainingSize = remainingSizeCalc(readIterCur);
180 if (remainingSize == 0U) {
190 if (es == comms::ErrorStatus::NotEnoughData) {
194 auto addMsgInfoGuard =
195 comms::util::makeScopeGuard(
196 [
this, &allMsgs, &msgPtr]()
200 allMsgs.push_back(
MessagePtr(std::move(msgPtr)));
204 [readIterBeg, &readIterCur, &msgPtr, &setExtraInfoFunc]()
207 auto dataSize =
static_cast<std::size_t
>(
208 std::distance(readIterBeg, readIterCur));
210 auto readTransportIterBegTmp = readIterBeg;
211 std::unique_ptr<TransportMsg> transportMsgPtr(
new TransportMsg());
212 [[maybe_unused]]
auto esTmp = transportMsgPtr->read(readTransportIterBegTmp, dataSize);
213 assert(esTmp == comms::ErrorStatus::Success);
216 auto readRawIterBegTmp = readIterBeg;
217 std::unique_ptr<RawDataMsg> rawDataMsgPtr(
new RawDataMsg());
218 esTmp = rawDataMsgPtr->read(readRawIterBegTmp, dataSize);
219 assert(esTmp == comms::ErrorStatus::Success);
221 setExtraInfoFunc(*msgPtr);
224 if (es == comms::ErrorStatus::Success) {
228 readIterBeg = readIterCur;
232 if (es == comms::ErrorStatus::InvalidMsgData) {
236 readIterBeg = readIterCur;
240 addMsgInfoGuard.release();
242 if (es == comms::ErrorStatus::MsgAllocFailure) {
243 [[maybe_unused]]
static constexpr bool Must_not_be_happen =
false;
244 assert(Must_not_be_happen);
249 m_garbage.push_back(*readIterBeg);
250 static const std::size_t GarbageLimit = 512;
251 if (GarbageLimit <= m_garbage.size()) {
258 ReadIterator dataBegin = &m_data[0];
259 auto consumed = std::distance(dataBegin, readIterBeg);
260 auto remDataCount =
static_cast<decltype(consumed)
>(m_data.size()) - consumed;
261 m_garbage.insert(m_garbage.end(), m_data.begin() + consumed, m_data.end());
262 std::advance(readIterBeg, remDataCount);
272 auto writeIter = std::back_inserter(data);
278 if (es == comms::ErrorStatus::UpdateRequired) {
279 auto updateIter = &data[0];
280 es = m_protStack.update(
286 if (es != comms::ErrorStatus::Success) {
287 [[maybe_unused]]
static constexpr bool Unexpected_write_update_failure =
false;
288 assert(Unexpected_write_update_failure);
295 dataInfo->m_timestamp = DataInfo::TimestampClock::now();
296 dataInfo->m_data = std::move(data);
308 std::vector<std::uint8_t> data;
310 auto writeIter = std::back_inserter(data);
316 if (es == comms::ErrorStatus::UpdateRequired) {
317 auto updateIter = &data[0];
318 es = m_protStack.update(
324 if (es != comms::ErrorStatus::Success) {
325 [[maybe_unused]]
static constexpr bool Unexpected_write_update_failure =
false;
326 assert(Unexpected_write_update_failure);
330 auto readMessageFunc =
333 typename ProtocolMessage::ReadIterator iter =
nullptr;
338 auto esTmp = msgToRead.read(iter, data.size());
339 if (esTmp != comms::ErrorStatus::Success) {
346 std::unique_ptr<TransportMsg> transportMsgPtr(
new TransportMsg());
347 if (!readMessageFunc(*transportMsgPtr)) {
348 [[maybe_unused]]
static constexpr bool Unexpected_failure_to_read_transport_message =
false;
349 assert(Unexpected_failure_to_read_transport_message);
353 std::unique_ptr<RawDataMsg> rawDataMsgPtr(
new RawDataMsg());
354 if (!readMessageFunc(*rawDataMsgPtr)) {
355 [[maybe_unused]]
static constexpr bool Unexpected_failure_to_read_raw_data =
false;
356 assert(Unexpected_failure_to_read_raw_data);
365 if (extraProps.isEmpty() && (!extraInfoMsgIsForced)) {
370 std::unique_ptr<ExtraInfoMsg> extraInfoMsgPtr(
new ExtraInfoMsg());
371 if (extraProps.isEmpty()) {
376 auto jsonObj = QJsonObject::fromVariantMap(extraProps);
377 QJsonDocument doc(jsonObj);
379 auto& str = std::get<0>(extraInfoMsgPtr->fields());
380 str.value() = doc.toJson().constData();
401 clonedMsg = m_protStack.createMsg(msgId, idx);
406 if (clonedMsg->assign(msg)) {
439 return createAllMessagesInTuple<AllMessages>();
445 return createMessageInternal(idAsString, idx, MsgIdTypeTag());
463 auto msgPtr = m_protStack.createMsg(
id, idx);
473 template <
typename TMsgsTuple>
477 typename std::conditional<
478 std::is_void<MsgFactory>::value,
479 CreateWithTupleIterationTag,
483 return createAllMessagesInTupleInternal<TMsgsTuple>(Tag());
487 struct NumericIdTag {};
488 struct OtherIdTag {};
489 struct HasMsgFactoryTag{};
490 struct HasStaticIdsTag{};
491 struct CreateWithLoopIterationTag{};
492 struct CreateWithTupleIterationTag{};
494 typedef typename std::conditional<
495 (std::is_enum<MsgIdType>::value || std::is_integral<MsgIdType>::value),
498 >::type MsgIdTypeTag;
500 static_assert(std::is_same<MsgIdTypeTag, NumericIdTag>::value,
501 "Non-numeric IDs are not supported properly yet.");
503 class AllMsgsCreateHelper
511 template <
typename TMsg>
521 class MsgCreateHelper
524 MsgCreateHelper(
const QString&
id,
unsigned idx,
MessagePtr& msg)
531 template <
typename TMsg>
539 if (m_id != msgPtr->idAsString()) {
543 if (m_currIdx == m_reqIdx) {
544 m_msg = std::move(msgPtr);
555 unsigned m_currIdx = 0;
558 MessagePtr createMessageInternal(
const QString& idAsString,
unsigned idx, NumericIdTag)
563 std::intmax_t numId =
static_cast<std::intmax_t
>(idAsString.toLongLong(&ok, 10));
565 numId =
static_cast<decltype(numId)
>(idAsString.toLongLong(&ok, 16));
576 MessagePtr createMessageInternal(
const QString& idAsString,
unsigned idx, OtherIdTag)
579 comms::util::tupleForEachType<AllMessages>(MsgCreateHelper(
name(), idAsString, idx, result));
586 template <
typename TMsgsTuple>
587 MessagesList createAllMessagesInTupleInternal(CreateWithTupleIterationTag)
590 comms::util::tupleForEachType<TMsgsTuple>(AllMsgsCreateHelper(allMsgs));
594 template <
typename TMsgsTuple>
595 MessagesList createAllMessagesInTupleInternal(HasMsgFactoryTag)
597 static_assert(std::tuple_size<TMsgsTuple>::value > 0U,
"At least one message is expected to be defined");
598 using FirstType =
typename std::tuple_element<0, TMsgsTuple>::type;
599 using LastType =
typename std::tuple_element<std::tuple_size<TMsgsTuple>::value - 1U, TMsgsTuple>::type;
603 FirstType::hasStaticMsgId() && LastType::hasStaticMsgId(),
605 CreateWithLoopIterationTag
608 return createAllMessagesInTupleInternal<TMsgsTuple>(Tag());
611 template <
typename TMsgsTuple>
612 MessagesList createAllMessagesInTupleInternal(CreateWithLoopIterationTag)
614 static_assert(std::tuple_size<TMsgsTuple>::value > 0U,
"At least one message is expected to be defined");
615 using FirstType =
typename std::tuple_element<0, TMsgsTuple>::type;
616 using LastType =
typename std::tuple_element<std::tuple_size<TMsgsTuple>::value - 1U, TMsgsTuple>::type;
617 auto firstId =
static_cast<std::uintmax_t
>(FirstType::doGetId());
618 auto lastId =
static_cast<std::uintmax_t
>(LastType::doGetId());
622 for (std::uintmax_t
id = firstId;
id <= lastId; ++id) {
623 auto count = factory.msgCount(
static_cast<MsgIdType>(
id));
624 for (
auto idx = 0U; idx < count; ++idx) {
625 auto msgPtr = factory.createMsg(
static_cast<MsgIdType>(
id), idx);
627 allMsgs.push_back(std::move(msgPtr));
635 template <
typename TMsgsTuple>
636 MessagesList createAllMessagesInTupleInternal(HasStaticIdsTag)
638 static_assert(std::tuple_size<TMsgsTuple>::value > 0U,
"At least one message is expected to be defined");
639 using FirstType =
typename std::tuple_element<0, TMsgsTuple>::type;
640 using LastType =
typename std::tuple_element<std::tuple_size<TMsgsTuple>::value - 1U, TMsgsTuple>::type;
641 static_assert(FirstType::hasStaticMsgId(),
"Invalid displatch");
642 static_assert(LastType::hasStaticMsgId(),
"Invalid displatch");
644 static const auto FirstId = FirstType::staticMsgId();
645 static const auto LastId = LastType::staticMsgId();
650 static_cast<std::size_t
>(FirstId - LastId) <= (std::tuple_size<TMsgsTuple>::value * 5),
651 CreateWithLoopIterationTag,
652 CreateWithTupleIterationTag
655 return createAllMessagesInTupleInternal<TMsgsTuple>(Tag());
659 std::vector<std::uint8_t> m_data;
660 std::vector<std::uint8_t> m_garbage;