COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
ProcessHelper.h
Go to the documentation of this file.
1//
2// Copyright 2019 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
10
11#pragma once
12
13#include "comms/Assert.h"
14#include "comms/details/detect.h"
15#include "comms/details/DispatchMsgPolymorphicHelper.h"
16#include "comms/details/process.h"
17#include "comms/details/tag.h"
18#include "comms/dispatch.h"
19#include "comms/ErrorStatus.h"
21#include "comms/iterator.h"
22#include "comms/Message.h"
23#include "comms/MsgDispatcher.h"
26
27#include <cstddef>
28#include <iterator>
29#include <type_traits>
30#include <utility>
31
32namespace comms
33{
34
35namespace details
36{
37
38struct ProcessHelper
39{
40
41 template <typename TBufIter, typename TFrame, typename TMsg, typename... TExtraValues>
43 TBufIter& bufIter,
44 std::size_t len,
45 TFrame&& frame,
46 TMsg& msg,
47 TExtraValues... extraValues)
48 {
49 std::size_t consumed = 0U;
50 auto onExit =
51 comms::util::makeScopeGuard(
52 [&bufIter, &consumed]()
53 {
54 std::advance(bufIter, consumed);
55 });
56 static_cast<void>(onExit);
57
58 while (consumed < len) {
59 auto begIter = comms::readIteratorFor(msg, bufIter + consumed);
60 auto iter = begIter;
61
62 // Do the read
63 auto es = frame.read(msg, iter, len - consumed, extraValues...);
65 return es;
66 }
67
69 // Something is not right with the data, remove one character and try again
70 ++consumed;
71 continue;
72 }
73
74 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
75 return es;
76 }
77
79 }
80
81 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
83 TBufIter& bufIter,
84 std::size_t len,
85 TFrame&& frame,
86 TMsg& msg,
87 THandler& handler,
88 TExtraValues... extraValues)
89 {
90 using MsgType = typename std::decay<decltype(msg)>::type;
91 using HandlerType = typename std::decay<decltype(handler)>::type;
92 using Tag = DispatchTag<MsgType, HandlerType>;
93 return processSingleWithDispatchInternal(bufIter, len, frame, msg, handler, extraValues..., Tag());
94 }
95
96 template <typename TDispatcher, typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
98 TBufIter& bufIter,
99 std::size_t len,
100 TFrame&& frame,
101 TMsg& msg,
102 THandler& handler,
103 TExtraValues... extraValues)
104 {
105 using MsgType = typename std::decay<decltype(msg)>::type;
106 using FrameType = typename std::decay<decltype(frame)>::type;
107 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
108 "Cannot dispatch with Dispatcher when using pre-allocated message, use regular polymorphic dispatch with "
109 "comms::option::def::Handler option");
110
111 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
112 static_assert(!std::is_void<LocalMsgIdType>(), "Invalid type of msg param");
113
114 LocalMsgIdType id = LocalMsgIdType();
115 std::size_t idx = 0U;
116
117 auto es =
119 bufIter,
120 len,
121 std::forward<TFrame>(frame),
122 msg,
125 extraValues...);
126
127 if (es != comms::ErrorStatus::Success) {
128 return es;
129 }
130
131 using FrameType = typename std::decay<decltype(frame)>::type;
132 using AllMessagesType = typename FrameType::AllMessages;
133 static_assert(
134 comms::isMsgDispatcher<TDispatcher>(),
135 "TDispatcher is expected to be a variant of comms::MsgDispatcher");
136
137 auto& msgObj = details::processMsgCastToMsgObj(msg);
138 TDispatcher::template dispatch<AllMessagesType>(id, idx, msgObj, handler);
139 return es;
140 }
141
142 template <typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
143 static std::size_t processAllWithDispatch(
144 TBufIter bufIter,
145 std::size_t len,
146 TFrame&& frame,
147 THandler& handler)
148 {
149 std::size_t consumed = 0U;
150 using FrameType = typename std::decay<decltype(frame)>::type;
151 using MsgPtr = typename FrameType::MsgPtr;
152 while (consumed < len) {
153 auto begIter = bufIter + consumed;
154 auto iter = begIter;
155
156 MsgPtr msg;
157 auto es = processSingleWithDispatch(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
159 ++consumed;
160 continue;
161 }
162
163 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
165 break;
166 }
167 COMMS_ASSERT(consumed <= len);
168 }
169
170 return consumed;
171 }
172
173 template <typename TDispatcher, typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
174 static std::size_t processAllWithDispatchViaDispatcher(
175 TBufIter bufIter,
176 std::size_t len,
177 TFrame&& frame,
178 THandler& handler)
179 {
180 std::size_t consumed = 0U;
181 using FrameType = typename std::decay<decltype(frame)>::type;
182 using MsgPtr = typename FrameType::MsgPtr;
183 while (consumed < len) {
184 auto begIter = bufIter + consumed;
185 auto iter = begIter;
186
187 MsgPtr msg;
188 auto es = processSingleWithDispatchViaDispatcher<TDispatcher>(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
189 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
191 break;
192 }
193 COMMS_ASSERT(consumed <= len);
194 }
195
196 return consumed;
197 }
198private:
199 template <typename... TParams>
200 using PolymorphicDispatchTag = comms::details::tag::Tag1<>;
201
202 template <typename... TParams>
203 using RegularDispatchTag = comms::details::tag::Tag2<>;
204
205 template <typename TMsg, typename THandler, typename...>
206 using DispatchTagTmp =
207 typename comms::util::LazyShallowConditional<
208 details::dispatchMsgPolymorphicIsCompatibleHandler<TMsg, THandler>()
209 >::template Type<
210 PolymorphicDispatchTag,
211 RegularDispatchTag
212 >;
213
214 template <typename TMsg, typename THandler, typename...>
215 using DispatchTag =
216 typename comms::util::LazyShallowConditional<
217 comms::isMessage<TMsg>()
218 >::template Type<
219 DispatchTagTmp,
220 RegularDispatchTag,
221 TMsg, THandler
222 >;
223
224 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
225 static comms::ErrorStatus processSingleWithDispatchInternal(
226 TBufIter& bufIter,
227 std::size_t len,
228 TFrame&& frame,
229 TMsg& msg,
230 THandler& handler,
231 TExtraValues... extraValues,
232 RegularDispatchTag<>)
233 {
234 using MsgType = typename std::decay<decltype(msg)>::type;
235 using FrameType = typename std::decay<decltype(frame)>::type;
236 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
237 "Cannot process pre-allocated message, impossible to retrieve message index for proper dispatch, "
238 "use comms::option::def::Handler option to support polymorphic dispatch");
239
240 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
241 LocalMsgIdType id = LocalMsgIdType();
242 std::size_t idx = 0U;
243
244 auto es =
246 bufIter,
247 len,
248 std::forward<TFrame>(frame),
249 msg,
252 extraValues...);
253
254 if (es != comms::ErrorStatus::Success) {
255 return es;
256 }
257
258 using FrameType = typename std::decay<decltype(frame)>::type;
259 using AllMessagesType = typename FrameType::AllMessages;
260 auto& msgObj = details::processMsgCastToMsgObj(msg);
261 comms::dispatchMsg<AllMessagesType>(id, idx, msgObj, handler);
262 return es;
263 }
264
265 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
266 static comms::ErrorStatus processSingleWithDispatchInternal(
267 TBufIter& bufIter,
268 std::size_t len,
269 TFrame&& frame,
270 TMsg& msg,
271 THandler& handler,
272 TExtraValues... extraValues,
273 PolymorphicDispatchTag<>)
274 {
275 auto es =
277 bufIter,
278 len,
279 std::forward<TFrame>(frame),
280 msg,
281 extraValues...);
282
283 if (es != comms::ErrorStatus::Success) {
284 return es;
285 }
286
287 auto& msgObj = details::processMsgCastToMsgObj(msg);
288 msgObj.dispatch(handler);
289 return es;
290 }
291
292};
293
294} // namespace details
295
296} // namespace comms
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:168
This file contain definition of error statuses used by comms module.
Contains definition of comms::frame::FrameLayerBase.
Contains definition of Message object interface and various base classes for custom messages.
Contains definition of MsgDispatcher class which facilitates dispatching of message object to appropr...
Contains definition of the "Scope Guard" idiom, see comms::util::ScopeGuard.
Contains extra logic to help with dispatching message types and objects.
Provides auxiliary functions for retrieving best type of iterator for read/write operations.
details::MsgIndexRetriever msgIndex(std::size_t &val)
Add "message index" output parameter to frame's "read" operation.
Definition FrameLayerBase.h:1623
details::MsgIdRetriever< TId > msgId(TId &val)
Add "message ID" output parameter to frame's "read" operation.
Definition FrameLayerBase.h:1586
comms::option::def::MsgType< TMsg > MsgType
Same as comms::option::def::MsgType.
Definition options.h:1498
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
@ Success
Used to indicate successful outcome of the operation.
std::size_t processAllWithDispatch(TBufIter bufIter, std::size_t len, TFrame &&frame, THandler &handler)
Process all available input and dispatch all created message objects to appropriate handling function...
Definition process.h:157
auto readIteratorFor(TIter &&iter) -> decltype(details::ReadIteratorHelper<>::template get< TMessage >(std::forward< TIter >(iter)))
Create and initialise iterator for message read.
Definition iterator.h:26
comms::ErrorStatus processSingle(TBufIter &bufIter, std::size_t len, TFrame &&frame, TMsg &msg, TExtraValues... extraValues)
Process input until first message is recognized and its object is created or missing data is reported...
Definition process.h:43
comms::ErrorStatus processSingleWithDispatch(TBufIter &bufIter, std::size_t len, TFrame &&frame, TMsg &msg, THandler &handler, TExtraValues... extraValues)
Process input until first message is recognized, its object is created and dispatched to appropriate ...
Definition process.h:81
comms::ErrorStatus processSingleWithDispatchViaDispatcher(TBufIter &bufIter, std::size_t len, TFrame &&frame, TMsg &msg, THandler &handler, TExtraValues... extraValues)
Process input until first message is recognized, its object is created and dispatched to appropriate ...
Definition process.h:123
std::size_t processAllWithDispatchViaDispatcher(TBufIter bufIter, std::size_t len, TFrame &&frame, THandler &handler)
Process all available input and dispatch all created message objects to appropriate handling function...
Definition process.h:190
Replacement to some types from standard type_traits.