23 template <
typename Function>
24 struct FunctionTraits;
33 template <
typename Return,
typename... Args>
34 struct FunctionTraits<Return (*)(Args...)>
36 using ReturnType = Return;
37 static constexpr size_t ARITY =
sizeof...(Args);
43 template <
size_t Index>
44 using Arg = std::tuple_element_t<Index, std::tuple<Args...>>;
54 struct MessageViewTraits
56 static constexpr bool VALUE =
67 template <
typename Data>
70 static constexpr bool VALUE =
82 using RemoveCVRef = std::remove_cv_t<std::remove_reference_t<T>>;
90 static constexpr bool IS_MESSAGE_VIEW =
91 MessageViewTraits<RemoveCVRef<T>>::VALUE;
100 template <
typename T>
101 static constexpr bool IS_RAW_DATA_VIEW = std::same_as<RemoveCVRef<T>,
ConstRawData> ||
109 template <
typename T>
110 static constexpr bool IS_RAW_DATA = std::same_as<RemoveCVRef<T>,
RawData>;
117 template <
typename T>
118 static constexpr bool IS_TYPED_DATA =
119 !IS_MESSAGE_VIEW<T> && !IS_RAW_DATA_VIEW<T> &&
129 template <
typename T>
130 static constexpr bool IS_CALLBACK_PAYLOAD =
131 IS_MESSAGE_VIEW<T> || IS_RAW_DATA_VIEW<T> ||
140 template <
typename T>
141 static constexpr bool IS_MUTABLE_MESSAGE_VIEW_REF =
142 IS_MESSAGE_VIEW<T> && std::is_lvalue_reference_v<T> &&
143 !std::is_const_v<std::remove_reference_t<T>>;
164 RunFun run =
nullptr;
166 TypeID::ID payload_type_id =
nullptr;
168 bool accepts_raw_payload =
false;
178 template <
typename PayloadArg>
179 static TypeID::ID PayloadTypeID()
181 static_assert(!IS_MUTABLE_MESSAGE_VIEW_REF<PayloadArg>,
182 "LibXR::Topic::Callback does not accept MessageView<T>&; "
183 "use MessageView<T> or const MessageView<T>& instead.");
184 static_assert(!IS_RAW_DATA<PayloadArg>,
185 "LibXR::Topic::Callback does not accept RawData as the payload; "
186 "use the topic's payload type T (keeps the type check), or "
187 "ConstRawData for raw bytes.");
189 if constexpr (IS_RAW_DATA_VIEW<PayloadArg>)
193 else if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
195 using View = MessageViewTraits<RemoveCVRef<PayloadArg>>;
200 static_assert(IS_TYPED_DATA<PayloadArg>,
201 "LibXR::Topic::Callback payload must be Topic::MessageView<T>, "
202 "Topic::RawMessageView, ConstRawData, T, T&, or const T&.");
213 template <
typename PayloadArg>
214 static constexpr bool AcceptsRawPayload()
216 return IS_RAW_DATA_VIEW<PayloadArg>;
233 template <
typename Function,
typename BoundArg,
typename PayloadArg>
234 static void InvokePayload(Function fun, BoundArg& arg,
bool in_isr,
238 if constexpr (std::same_as<RemoveCVRef<PayloadArg>,
ConstRawData>)
241 fun(in_isr, arg, raw_payload);
243 else if constexpr (std::same_as<RemoveCVRef<PayloadArg>,
RawMessageView>)
246 fun(in_isr, arg, raw_message);
248 else if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
250 using View = MessageViewTraits<RemoveCVRef<PayloadArg>>;
251 using Data =
typename View::DataType;
257 using Data = RemoveCVRef<PayloadArg>;
258 fun(in_isr, arg, *
reinterpret_cast<Data*
>(payload_addr));
269 template <
typename Function,
typename BoundArg,
typename PayloadArg>
270 struct PayloadOnlyBlock :
public BlockHeader
278 PayloadOnlyBlock(Function fun, BoundArg&& arg)
279 : BlockHeader{&Run, PayloadTypeID<PayloadArg>(), AcceptsRawPayload<PayloadArg>()},
294 static void Run(
const BlockHeader* header,
bool in_isr,
298 auto* block =
static_cast<const PayloadOnlyBlock*
>(header);
299 InvokePayload<Function, BoundArg, PayloadArg>(
300 block->fun_,
const_cast<BoundArg&
>(block->arg_), in_isr, timestamp,
301 payload_addr, payload_size);
316 template <
typename Function,
typename BoundArg,
typename PayloadArg>
317 struct TimestampPayloadBlock :
public BlockHeader
325 TimestampPayloadBlock(Function fun, BoundArg&& arg)
326 : BlockHeader{&Run, PayloadTypeID<PayloadArg>(), AcceptsRawPayload<PayloadArg>()},
341 static void Run(
const BlockHeader* header,
bool in_isr,
345 auto* block =
static_cast<const TimestampPayloadBlock*
>(header);
346 if constexpr (std::same_as<RemoveCVRef<PayloadArg>,
ConstRawData>)
349 block->fun_(in_isr, block->arg_, timestamp, raw_payload);
351 else if constexpr (std::same_as<RemoveCVRef<PayloadArg>,
RawMessageView>)
354 block->fun_(in_isr, block->arg_, timestamp, raw_message);
356 else if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
358 using View = MessageViewTraits<RemoveCVRef<PayloadArg>>;
359 using Data =
typename View::DataType;
360 block->fun_(in_isr, block->arg_, timestamp,
365 using Data = RemoveCVRef<PayloadArg>;
366 block->fun_(in_isr, block->arg_, timestamp,
367 *
reinterpret_cast<Data*
>(payload_addr));
383 template <
typename Function,
typename BoundArg,
size_t Arity>
386 static_assert(Arity == 3 || Arity == 4,
387 "LibXR::Topic::Callback function must be void(bool, Arg, Payload) "
388 "or void(bool, Arg, MicrosecondTimestamp, Payload).");
397 template <
typename Function,
typename BoundArg>
398 struct Factory<Function, BoundArg, 3>
400 using Traits = FunctionTraits<Function>;
401 using PayloadArg =
typename Traits::template Arg<2>;
412 static BlockHeader*
Create(Function fun, BoundArg&& arg)
414 static_assert(std::same_as<typename Traits::ReturnType, void>);
415 static_assert(std::same_as<typename Traits::template Arg<0>,
bool>);
416 static_assert(std::same_as<typename Traits::template Arg<1>, BoundArg>);
417 static_assert(IS_CALLBACK_PAYLOAD<PayloadArg>);
418 return new PayloadOnlyBlock<Function, BoundArg, PayloadArg>(fun, std::move(arg));
428 template <
typename Function,
typename BoundArg>
429 struct Factory<Function, BoundArg, 4>
431 using Traits = FunctionTraits<Function>;
433 typename Traits::template Arg<2>;
436 using PayloadArg =
typename Traits::template Arg<3>;
447 static BlockHeader*
Create(Function fun, BoundArg&& arg)
449 static_assert(std::same_as<typename Traits::ReturnType, void>);
450 static_assert(std::same_as<typename Traits::template Arg<0>,
bool>);
451 static_assert(std::same_as<typename Traits::template Arg<1>, BoundArg>);
453 static_assert(IS_CALLBACK_PAYLOAD<PayloadArg>);
454 return new TimestampPayloadBlock<Function, BoundArg, PayloadArg>(fun,
467 static void EmptyRun(
const BlockHeader* header,
bool in_isr,
474 UNUSED(payload_addr);
475 UNUSED(payload_size);
478 inline static BlockHeader empty_block_{
479 &EmptyRun,
nullptr,
false};
518 template <
typename BoundArg,
typename Callable>
521 using Function =
decltype(+std::declval<Callable>());
522 using Traits = FunctionTraits<Function>;
523 static_assert(Traits::ARITY == 3 || Traits::ARITY == 4,
524 "LibXR::Topic::Callback::Create expects a capture-free callable "
525 "with bool and bound-argument parameters.");
527 Factory<Function, BoundArg, Traits::ARITY>::Create(+fun, std::move(arg)));
538 size_t payload_size)
const
540 block_->run(block_, in_isr, timestamp, payload_addr, payload_size);
565 explicit Callback(BlockHeader* block) : block_(block ? block : &empty_block_) {}
567 BlockHeader* block_ = &empty_block_;