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);
158 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
160 break;
161 }
162 COMMS_ASSERT(consumed <= len);
163 }
164
165 return consumed;
166 }
167
168 template <typename TDispatcher, typename TBufIter, typename TFrame, typename THandler, typename... TExtraValues>
169 static std::size_t processAllWithDispatchViaDispatcher(
170 TBufIter bufIter,
171 std::size_t len,
172 TFrame&& frame,
173 THandler& handler)
174 {
175 std::size_t consumed = 0U;
176 using FrameType = typename std::decay<decltype(frame)>::type;
177 using MsgPtr = typename FrameType::MsgPtr;
178 while (consumed < len) {
179 auto begIter = bufIter + consumed;
180 auto iter = begIter;
181
182 MsgPtr msg;
183 auto es = processSingleWithDispatchViaDispatcher<TDispatcher>(iter, len - consumed, std::forward<TFrame>(frame), msg, handler);
184 consumed += static_cast<decltype(consumed)>(std::distance(begIter, iter));
186 break;
187 }
188 COMMS_ASSERT(consumed <= len);
189 }
190
191 return consumed;
192 }
193private:
194 template <typename... TParams>
195 using PolymorphicDispatchTag = comms::details::tag::Tag1<>;
196
197 template <typename... TParams>
198 using RegularDispatchTag = comms::details::tag::Tag2<>;
199
200 template <typename TMsg, typename THandler, typename...>
201 using DispatchTagTmp =
202 typename comms::util::LazyShallowConditional<
203 details::dispatchMsgPolymorphicIsCompatibleHandler<TMsg, THandler>()
204 >::template Type<
205 PolymorphicDispatchTag,
206 RegularDispatchTag
207 >;
208
209 template <typename TMsg, typename THandler, typename...>
210 using DispatchTag =
211 typename comms::util::LazyShallowConditional<
212 comms::isMessage<TMsg>()
213 >::template Type<
214 DispatchTagTmp,
215 RegularDispatchTag,
216 TMsg, THandler
217 >;
218
219 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
220 static comms::ErrorStatus processSingleWithDispatchInternal(
221 TBufIter& bufIter,
222 std::size_t len,
223 TFrame&& frame,
224 TMsg& msg,
225 THandler& handler,
226 TExtraValues... extraValues,
227 RegularDispatchTag<>)
228 {
229 using MsgType = typename std::decay<decltype(msg)>::type;
230 using FrameType = typename std::decay<decltype(frame)>::type;
231 static_assert((!comms::isMessage<MsgType>()) || (details::allMessagesAreStrongSorted<typename FrameType::AllMessages>()),
232 "Cannot process pre-allocated message, impossible to retrieve message index for proper dispatch, "
233 "use comms::option::def::Handler option to support polymorphic dispatch");
234
235 using LocalMsgIdType = details::ProcessMsgIdType<MsgType>;
236 LocalMsgIdType id = LocalMsgIdType();
237 std::size_t idx = 0U;
238
239 auto es =
241 bufIter,
242 len,
243 std::forward<TFrame>(frame),
244 msg,
247 extraValues...);
248
249 if (es != comms::ErrorStatus::Success) {
250 return es;
251 }
252
253 using FrameType = typename std::decay<decltype(frame)>::type;
254 using AllMessagesType = typename FrameType::AllMessages;
255 auto& msgObj = details::processMsgCastToMsgObj(msg);
256 comms::dispatchMsg<AllMessagesType>(id, idx, msgObj, handler);
257 return es;
258 }
259
260 template <typename TBufIter, typename TFrame, typename TMsg, typename THandler, typename... TExtraValues>
261 static comms::ErrorStatus processSingleWithDispatchInternal(
262 TBufIter& bufIter,
263 std::size_t len,
264 TFrame&& frame,
265 TMsg& msg,
266 THandler& handler,
267 TExtraValues... extraValues,
268 PolymorphicDispatchTag<>)
269 {
270 auto es =
272 bufIter,
273 len,
274 std::forward<TFrame>(frame),
275 msg,
276 extraValues...);
277
278 if (es != comms::ErrorStatus::Success) {
279 return es;
280 }
281
282 auto& msgObj = details::processMsgCastToMsgObj(msg);
283 msgObj.dispatch(handler);
284 return es;
285 }
286
287};
288
289} // namespace details
290
291} // 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: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: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: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.