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 - 2026 (C). Alex Robenko. All rights reserved.
3//
4// SPDX-License-Identifier: MPL-2.0
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
12
13#pragma once
14
15#include "comms/Assert.h"
16#include "comms/details/detect.h"
17#include "comms/details/DispatchMsgPolymorphicHelper.h"
18#include "comms/details/process.h"
19#include "comms/details/tag.h"
20#include "comms/dispatch.h"
21#include "comms/ErrorStatus.h"
23#include "comms/iterator.h"
24#include "comms/Message.h"
25#include "comms/MsgDispatcher.h"
28
29#include <cstddef>
30#include <iterator>
31#include <type_traits>
32#include <utility>
33
34namespace comms
35{
36
37namespace details
38{
39
40struct ProcessHelper
41{
42
43 template <typename TBufIter, typename TFrame, typename TMsg, typename... TExtraValues>
45 TBufIter& bufIter,
46 std::size_t len,
47 TFrame&& frame,
48 TMsg& msg,
49 TExtraValues... extraValues)
50 {
51 std::size_t consumed = 0U;
52 auto onExit =
53 comms::util::makeScopeGuard(
54 [&bufIter, &consumed]()
55 {
56 std::advance(bufIter, consumed);
57 });
58 static_cast<void>(onExit);
59
60 while (consumed < len) {
61 auto begIter = comms::readIteratorFor(msg, bufIter + consumed);
62 auto iter = begIter;
63
64 // Do the read
65 auto es = frame.read(msg, iter, len - consumed, extraValues...);
67 return es;
68 }
69
71 // Something is not right with the data, remove one character and try again
72 ++consumed;
73 continue;
74 }
75
76 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
77 return es;
78 }
79
81 }
82
83 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
85 TBufIter& bufIter,
86 std::size_t len,
87 TFrame&& frame,
88 TMsg& msg,
89 THandler& handler,
90 TExtraValues... extraValues)
91 {
92 using MsgType = typename std::decay<decltype(msg)>::type;
93 using HandlerType = typename std::decay<decltype(handler)>::type;
94 using Tag = DispatchTag<MsgType, HandlerType>;
95 return processSingleWithDispatchInternal(bufIter, len, frame, msg, handler, extraValues..., Tag());
96 }
97
98 template <typename TDispatcher, typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
100 TBufIter& bufIter,
101 std::size_t len,
102 TFrame&& frame,
103 TMsg& msg,
104 THandler& handler,
105 TExtraValues... extraValues)
106 {
107 using MsgType = typename std::decay<decltype(msg)>::type;
108 using FrameType = typename std::decay<decltype(frame)>::type;
109 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
110 "Cannot dispatch with Dispatcher when using pre-allocated message, use regular polymorphic dispatch with "
111 "comms::option::def::Handler option");
112
113 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
114 static_assert(!std::is_void<LocalMsgIdType>(), "Invalid type of msg param");
115
116 LocalMsgIdType id = LocalMsgIdType();
117 std::size_t idx = 0U;
118
119 auto es =
121 bufIter,
122 len,
123 std::forward<TFrame>(frame),
124 msg,
127 extraValues...);
128
129 if (es != comms::ErrorStatus::Success) {
130 return es;
131 }
132
133 using FrameType = typename std::decay<decltype(frame)>::type;
134 using AllMessagesType = typename FrameType::AllMessages;
135 static_assert(
136 comms::isMsgDispatcher<TDispatcher>(),
137 "TDispatcher is expected to be a variant of comms::MsgDispatcher");
138
139 auto& msgObj = details::processMsgCastToMsgObj(msg);
140 TDispatcher::template dispatch<AllMessagesType>(id, idx, msgObj, handler);
141 return es;
142 }
143
144 template <typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
145 static std::size_t processAllWithDispatch(
146 TBufIter bufIter,
147 std::size_t len,
148 TFrame&& frame,
149 THandler& handler)
150 {
151 std::size_t consumed = 0U;
152 using FrameType = typename std::decay<decltype(frame)>::type;
153 using MsgPtr = typename FrameType::MsgPtr;
154 while (consumed < len) {
155 auto begIter = bufIter + consumed;
156 auto iter = begIter;
157
158 MsgPtr msg;
159 auto es = processSingleWithDispatch(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
161 ++consumed;
162 continue;
163 }
164
165 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
167 break;
168 }
169 COMMS_ASSERT(consumed <= len);
170 }
171
172 return consumed;
173 }
174
175 template <typename TDispatcher, typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
176 static std::size_t processAllWithDispatchViaDispatcher(
177 TBufIter bufIter,
178 std::size_t len,
179 TFrame&& frame,
180 THandler& handler)
181 {
182 std::size_t consumed = 0U;
183 using FrameType = typename std::decay<decltype(frame)>::type;
184 using MsgPtr = typename FrameType::MsgPtr;
185 while (consumed < len) {
186 auto begIter = bufIter + consumed;
187 auto iter = begIter;
188
189 MsgPtr msg;
190 auto es = processSingleWithDispatchViaDispatcher<TDispatcher>(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
191 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
193 break;
194 }
195 COMMS_ASSERT(consumed <= len);
196 }
197
198 return consumed;
199 }
200private:
201 template <typename... TParams>
202 using PolymorphicDispatchTag = comms::details::tag::Tag1<>;
203
204 template <typename... TParams>
205 using RegularDispatchTag = comms::details::tag::Tag2<>;
206
207 template <typename TMsg, typename THandler, typename...>
208 using DispatchTagTmp =
209 typename comms::util::LazyShallowConditional<
210 details::dispatchMsgPolymorphicIsCompatibleHandler<TMsg, THandler>()
211 >::template Type<
212 PolymorphicDispatchTag,
213 RegularDispatchTag
214 >;
215
216 template <typename TMsg, typename THandler, typename...>
217 using DispatchTag =
218 typename comms::util::LazyShallowConditional<
219 comms::isMessage<TMsg>()
220 >::template Type<
221 DispatchTagTmp,
222 RegularDispatchTag,
223 TMsg, THandler
224 >;
225
226 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
227 static comms::ErrorStatus processSingleWithDispatchInternal(
228 TBufIter& bufIter,
229 std::size_t len,
230 TFrame&& frame,
231 TMsg& msg,
232 THandler& handler,
233 TExtraValues... extraValues,
234 RegularDispatchTag<>)
235 {
236 using MsgType = typename std::decay<decltype(msg)>::type;
237 using FrameType = typename std::decay<decltype(frame)>::type;
238 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
239 "Cannot process pre-allocated message, impossible to retrieve message index for proper dispatch, "
240 "use comms::option::def::Handler option to support polymorphic dispatch");
241
242 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
243 LocalMsgIdType id = LocalMsgIdType();
244 std::size_t idx = 0U;
245
246 auto es =
248 bufIter,
249 len,
250 std::forward<TFrame>(frame),
251 msg,
254 extraValues...);
255
256 if (es != comms::ErrorStatus::Success) {
257 return es;
258 }
259
260 using FrameType = typename std::decay<decltype(frame)>::type;
261 using AllMessagesType = typename FrameType::AllMessages;
262 auto& msgObj = details::processMsgCastToMsgObj(msg);
263 comms::dispatchMsg<AllMessagesType>(id, idx, msgObj, handler);
264 return es;
265 }
266
267 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
268 static comms::ErrorStatus processSingleWithDispatchInternal(
269 TBufIter& bufIter,
270 std::size_t len,
271 TFrame&& frame,
272 TMsg& msg,
273 THandler& handler,
274 TExtraValues... extraValues,
275 PolymorphicDispatchTag<>)
276 {
277 auto es =
279 bufIter,
280 len,
281 std::forward<TFrame>(frame),
282 msg,
283 extraValues...);
284
285 if (es != comms::ErrorStatus::Success) {
286 return es;
287 }
288
289 auto& msgObj = details::processMsgCastToMsgObj(msg);
290 msgObj.dispatch(handler);
291 return es;
292 }
293
294};
295
296} // namespace details
297
298} // 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:1627
details::MsgIdRetriever< TId > msgId(TId &val)
Add "message ID" output parameter to frame's "read" operation.
Definition FrameLayerBase.h:1590
comms::option::def::MsgType< TMsg > MsgType
Same as comms::option::def::MsgType.
Definition options.h:1500
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:19
@ 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:159
auto readIteratorFor(TIter &&iter) -> decltype(details::ReadIteratorHelper<>::template get< TMessage >(std::forward< TIter >(iter)))
Create and initialise iterator for message read.
Definition iterator.h:29
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:45
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:83
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:125
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:192
Replacement to some types from standard type_traits.