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
31namespace comms
32{
33
34namespace details
35{
36
37struct ProcessHelper
38{
39
40 template <typename TBufIter, typename TFrame, typename TMsg, typename... TExtraValues>
42 TBufIter& bufIter,
43 std::size_t len,
44 TFrame&& frame,
45 TMsg& msg,
46 TExtraValues... extraValues)
47 {
48 std::size_t consumed = 0U;
49 auto onExit =
50 comms::util::makeScopeGuard(
51 [&bufIter, &consumed]()
52 {
53 std::advance(bufIter, consumed);
54 });
55 static_cast<void>(onExit);
56
57 while (consumed < len) {
58 auto begIter = comms::readIteratorFor(msg, bufIter + consumed);
59 auto iter = begIter;
60
61 // Do the read
62 auto es = frame.read(msg, iter, len - consumed, extraValues...);
64 return es;
65 }
66
68 // Something is not right with the data, remove one character and try again
69 ++consumed;
70 continue;
71 }
72
73 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
74 return es;
75 }
76
78 }
79
80 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
82 TBufIter& bufIter,
83 std::size_t len,
84 TFrame&& frame,
85 TMsg& msg,
86 THandler& handler,
87 TExtraValues... extraValues)
88 {
89 using MsgType = typename std::decay<decltype(msg)>::type;
90 using HandlerType = typename std::decay<decltype(handler)>::type;
91 using Tag = DispatchTag<MsgType, HandlerType>;
92 return processSingleWithDispatchInternal(bufIter, len, frame, msg, handler, extraValues..., Tag());
93 }
94
95 template <typename TDispatcher, typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
97 TBufIter& bufIter,
98 std::size_t len,
99 TFrame&& frame,
100 TMsg& msg,
101 THandler& handler,
102 TExtraValues... extraValues)
103 {
104 using MsgType = typename std::decay<decltype(msg)>::type;
105 using FrameType = typename std::decay<decltype(frame)>::type;
106 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
107 "Cannot dispatch with Dispatcher when using pre-allocated message, use regular polymorphic dispatch with "
108 "comms::option::def::Handler option");
109
110 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
111 static_assert(!std::is_void<LocalMsgIdType>(), "Invalid type of msg param");
112
113 LocalMsgIdType id = LocalMsgIdType();
114 std::size_t idx = 0U;
115
116 auto es =
118 bufIter,
119 len,
120 std::forward<TFrame>(frame),
121 msg,
124 extraValues...);
125
126 if (es != comms::ErrorStatus::Success) {
127 return es;
128 }
129
130 using FrameType = typename std::decay<decltype(frame)>::type;
131 using AllMessagesType = typename FrameType::AllMessages;
132 static_assert(
133 comms::isMsgDispatcher<TDispatcher>(),
134 "TDispatcher is expected to be a variant of comms::MsgDispatcher");
135
136 auto& msgObj = details::processMsgCastToMsgObj(msg);
137 TDispatcher::template dispatch<AllMessagesType>(id, idx, msgObj, handler);
138 return es;
139 }
140
141 template <typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
142 static std::size_t processAllWithDispatch(
143 TBufIter bufIter,
144 std::size_t len,
145 TFrame&& frame,
146 THandler& handler)
147 {
148 std::size_t consumed = 0U;
149 using FrameType = typename std::decay<decltype(frame)>::type;
150 using MsgPtr = typename FrameType::MsgPtr;
151 while (consumed < len) {
152 auto begIter = bufIter + consumed;
153 auto iter = begIter;
154
155 MsgPtr msg;
156 auto es = processSingleWithDispatch(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
157 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
159 break;
160 }
161 COMMS_ASSERT(consumed <= len);
162 }
163
164 return consumed;
165 }
166
167 template <typename TDispatcher, typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
168 static std::size_t processAllWithDispatchViaDispatcher(
169 TBufIter bufIter,
170 std::size_t len,
171 TFrame&& frame,
172 THandler& handler)
173 {
174 std::size_t consumed = 0U;
175 using FrameType = typename std::decay<decltype(frame)>::type;
176 using MsgPtr = typename FrameType::MsgPtr;
177 while (consumed < len) {
178 auto begIter = bufIter + consumed;
179 auto iter = begIter;
180
181 MsgPtr msg;
182 auto es = processSingleWithDispatchViaDispatcher<TDispatcher>(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
183 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
185 break;
186 }
187 COMMS_ASSERT(consumed <= len);
188 }
189
190 return consumed;
191 }
192private:
193 template <typename... TParams>
194 using PolymorphicDispatchTag = comms::details::tag::Tag1<>;
195
196 template <typename... TParams>
197 using RegularDispatchTag = comms::details::tag::Tag2<>;
198
199 template <typename TMsg, typename THandler, typename...>
200 using DispatchTagTmp =
201 typename comms::util::LazyShallowConditional<
202 details::dispatchMsgPolymorphicIsCompatibleHandler<TMsg, THandler>()
203 >::template Type<
204 PolymorphicDispatchTag,
205 RegularDispatchTag
206 >;
207
208 template <typename TMsg, typename THandler, typename...>
209 using DispatchTag =
210 typename comms::util::LazyShallowConditional<
211 comms::isMessage<TMsg>()
212 >::template Type<
213 DispatchTagTmp,
214 RegularDispatchTag,
215 TMsg, THandler
216 >;
217
218 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
219 static comms::ErrorStatus processSingleWithDispatchInternal(
220 TBufIter& bufIter,
221 std::size_t len,
222 TFrame&& frame,
223 TMsg& msg,
224 THandler& handler,
225 TExtraValues... extraValues,
226 RegularDispatchTag<>)
227 {
228 using MsgType = typename std::decay<decltype(msg)>::type;
229 using FrameType = typename std::decay<decltype(frame)>::type;
230 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
231 "Cannot process pre-allocated message, impossible to retrieve message index for proper dispatch, "
232 "use comms::option::def::Handler option to support polymorphic dispatch");
233
234 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
235 LocalMsgIdType id = LocalMsgIdType();
236 std::size_t idx = 0U;
237
238 auto es =
240 bufIter,
241 len,
242 std::forward<TFrame>(frame),
243 msg,
246 extraValues...);
247
248 if (es != comms::ErrorStatus::Success) {
249 return es;
250 }
251
252 using FrameType = typename std::decay<decltype(frame)>::type;
253 using AllMessagesType = typename FrameType::AllMessages;
254 auto& msgObj = details::processMsgCastToMsgObj(msg);
255 comms::dispatchMsg<AllMessagesType>(id, idx, msgObj, handler);
256 return es;
257 }
258
259 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
260 static comms::ErrorStatus processSingleWithDispatchInternal(
261 TBufIter& bufIter,
262 std::size_t len,
263 TFrame&& frame,
264 TMsg& msg,
265 THandler& handler,
266 TExtraValues... extraValues,
267 PolymorphicDispatchTag<>)
268 {
269 auto es =
271 bufIter,
272 len,
273 std::forward<TFrame>(frame),
274 msg,
275 extraValues...);
276
277 if (es != comms::ErrorStatus::Success) {
278 return es;
279 }
280
281 auto& msgObj = details::processMsgCastToMsgObj(msg);
282 msgObj.dispatch(handler);
283 return es;
284 }
285
286};
287
288} // namespace details
289
290} // namespace comms
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
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:1622
details::MsgIdRetriever< TId > msgId(TId &val)
Add "message ID" output parameter to frame's "read" operation.
Definition FrameLayerBase.h:1585
comms::option::def::MsgType< TMsg > MsgType
Same as comms::option::def::MsgType.
Definition options.h:1487
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:156
auto readIteratorFor(TIter &&iter) -> decltype(details::ReadIteratorHelper<>::template get< TMessage >(std::forward< TIter >(iter)))
Create and initialise iterator for message read.
Definition iterator.h:24
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:42
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:80
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:122
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:189
Replacement to some types from standard type_traits.