22#ifndef ESI_TYPED_PORTS_H
23#define ESI_TYPED_PORTS_H
55 using std::runtime_error::runtime_error;
65 t = alias->getInnerType();
80 return {(bv->getWidth() + 7) / 8, bv->getWidth()};
88 if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
90 std::vector<uint8_t> buf(wi.
bytes, 0);
91 std::memcpy(buf.data(), &data, std::min(wi.
bytes,
sizeof(T)));
94 }
else if constexpr (std::is_base_of_v<SegmentedMessageData, T>) {
95 return data.toMessageData();
97 return MessageData(
reinterpret_cast<const uint8_t *
>(&data),
sizeof(T));
111 if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>) {
116 std::memcpy(&val, msg.
getBytes(), std::min(wi.
bytes,
sizeof(T)));
118 if constexpr (std::is_signed_v<T>) {
120 size_t signByte = signBit / 8;
121 uint8_t signMask = uint8_t(1) << (signBit % 8);
122 if (signByte < wi.
bytes && (msg.
getBytes()[signByte] & signMask)) {
125 val |=
static_cast<T
>(~T(0)) << wi.
bitWidth;
136 return fromMessageData<T>(msg,
getWireInfo(portType));
148template <
typename T,
typename =
void>
161 if (
auto *flat =
dynamic_cast<const MessageData *
>(&msg))
181 bool push(std::unique_ptr<SegmentedMessageData> &msg) {
182 std::scoped_lock<std::mutex> lock(
mutex);
184 throw std::runtime_error(
"PODTypeDeserializer::push: null message");
194 const MessageData &flat = getMessageDataRef<T>(*msg, scratch);
202 std::scoped_lock<std::mutex> lock(
mutex);
221template <
typename T,
typename =
void>
228 using type =
typename T::TypeDeserializer;
261 bool push(std::unique_ptr<SegmentedMessageData> &msg) {
262 std::scoped_lock<std::mutex> lock(
mutex);
264 throw std::runtime_error(
265 "QueuedDecodeTypeDeserializer::push: null message");
272 throw std::runtime_error(
273 "QueuedDecodeTypeDeserializer::push: decode must consume the "
275 for (std::unique_ptr<T> &value : decoded) {
277 throw std::runtime_error(
278 "QueuedDecodeTypeDeserializer::push: null decoded output");
292 std::scoped_lock<std::mutex> lock(
mutex);
308 throw std::runtime_error(
309 "QueuedDecodeTypeDeserializer::poke: null pending output");
355 "header and data frames must be the same width");
361 const MessageData &flat = detail::getMessageDataRef<T>(*msg, scratch);
362 const uint8_t *bytes = flat.
getBytes();
366 while (offset < size) {
368 size_t chunk = std::min(needed, size - offset);
382 count_type batchCount = T::_headerCount(frame);
383 if (batchCount == 0) {
387 throw std::runtime_error(
388 "SerialListTypeDeserializer: footer received before any "
424template <
typename T,
typename =
void>
429 : std::is_convertible<decltype(T::_ESI_ID), std::string_view> {};
436template <
typename T,
typename =
void>
441 : std::is_convertible<decltype(T::_ESI_WINDOW_ID), std::string_view> {};
457template <
typename T, std::
size_t N>
472 if (
auto *windowType =
dynamic_cast<const WindowType *
>(portType)) {
473 if constexpr (has_esi_window_id_v<T>) {
474 if (std::string_view(windowType->getID()) != T::_ESI_WINDOW_ID)
476 "ESI window mismatch: C++ type has _ESI_WINDOW_ID '" +
477 std::string(T::_ESI_WINDOW_ID) +
"' but port window type is '" +
478 windowType->toString(
true) +
"'");
481 "ESI type mismatch: port is a window type ('" +
482 windowType->toString(
true) +
483 "') but C++ type has no _ESI_WINDOW_ID");
486 }
else if constexpr (has_esi_window_id_v<T>) {
488 std::string(
"ESI type mismatch: C++ type has _ESI_WINDOW_ID '") +
489 std::string(T::_ESI_WINDOW_ID) +
"' but port type is not a window: '" +
493 if constexpr (has_esi_id_v<T>) {
495 if (std::string_view(portType->
getID()) != T::_ESI_ID)
497 "ESI type mismatch: C++ type has _ESI_ID '" +
498 std::string(T::_ESI_ID) +
"' but port type is '" +
500 }
else if constexpr (std::is_void_v<T>) {
501 if (!
dynamic_cast<const VoidType *
>(portType))
503 "void, but port type is '" +
506 }
else if constexpr (std::is_same_v<T, bool>) {
508 auto *bits =
dynamic_cast<const BitsType *
>(portType);
509 if (!bits || bits->getWidth() > 1)
511 "ESI type mismatch: expected BitsType with width <= 1 for "
512 "bool, but port type is '" +
514 }
else if constexpr (is_std_array_v<T>) {
519 using Element =
typename T::value_type;
520 constexpr size_t N = std::tuple_size<T>::value;
521 auto *arr =
dynamic_cast<const ArrayType *
>(portType);
524 "ESI type mismatch: expected ArrayType for std::array, but port "
527 if (arr->getSize() != N)
529 std::to_string(arr->getSize()) +
530 " does not match std::array size " +
532 verifyTypeCompatibility<Element>(arr->getElementType());
533 }
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
534 auto *sint =
dynamic_cast<const SIntType *
>(portType);
537 "ESI type mismatch: expected SIntType for signed integer, "
538 "but port type is '" +
540 if (sint->getWidth() >
sizeof(T) * 8)
542 "ESI type mismatch: SIntType width " +
543 std::to_string(sint->getWidth()) +
" does not fit in " +
544 std::to_string(
sizeof(T) * 8) +
"-bit signed integer");
546 if (
sizeof(T) > 1 && sint->getWidth() <= (
sizeof(T) / 2) * 8)
548 std::to_string(sint->getWidth()) +
549 " should use a smaller C++ type than " +
550 std::to_string(
sizeof(T) * 8) +
"-bit");
551 }
else if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>) {
553 auto *uintPort =
dynamic_cast<const UIntType *
>(portType);
554 auto *bits =
dynamic_cast<const BitsType *
>(portType);
555 if (!uintPort && !bits)
557 "ESI type mismatch: expected UIntType or BitsType for unsigned "
558 "integer, but port type is '" +
560 uint64_t width = uintPort ? uintPort->getWidth() : bits->getWidth();
561 if (width >
sizeof(T) * 8)
563 "ESI type mismatch: bit width " + std::to_string(width) +
564 " does not fit in " + std::to_string(
sizeof(T) * 8) +
565 "-bit unsigned integer");
567 if (
sizeof(T) > 1 && width <= (
sizeof(T) / 2) * 8)
569 std::to_string(width) +
570 " should use a smaller C++ type than " +
571 std::to_string(
sizeof(T) * 8) +
"-bit");
574 std::string(
"Cannot verify type compatibility for C++ type '") +
575 typeid(T).name() +
"' against ESI port type '" +
590 if constexpr (has_esi_window_id_v<T>) {
593 std::string(
"ESI type mismatch: C++ type has _ESI_WINDOW_ID '") +
594 std::string(T::_ESI_WINDOW_ID) +
595 "' but port is not a window type ('" +
597 : std::string(
"<null>")) +
602 "ESI type mismatch: port is a window type ('" +
604 "') but C++ type has no _ESI_WINDOW_ID");
606 const Type *forwardType =
607 windowType ?
static_cast<const Type *
>(windowType) : port->
getType();
608 verifyTypeCompatibility<T>(forwardType);
619template <
typename T,
bool SkipTypeCheck = false>
631 verifyTypeCompatibility<T>(
inner);
640 void write(std::unique_ptr<T> &data) {
642 throw std::runtime_error(
"TypedWritePort::write: null unique_ptr");
643 if constexpr (std::is_base_of_v<SegmentedMessageData, T>) {
717template <
typename T,
bool SkipTypeCheck = false>
748 [
this](std::unique_ptr<SegmentedMessageData> &msg) ->
bool {
764 void connect(std::function<
bool(
const T &)> callback,
767 connect([cb = std::move(callback)](
768 std::unique_ptr<T> &value) ->
bool {
return cb(*value); },
786 [
this](std::unique_ptr<SegmentedMessageData> &msg) ->
bool {
802 std::future<std::unique_ptr<T>> f =
readAsync();
812 throw std::runtime_error(
813 "Cannot read from a callback channel. `connect()` without a "
814 "callback specified to use polling mode.");
816 throw std::runtime_error(
817 "Cannot read from a disconnected channel. `connect()` first.");
820 throw std::runtime_error(
821 "Cannot read from a disconnected channel. `connect()` first.");
823 std::future<std::unique_ptr<T>> future =
pollingState->readAsync();
860 if constexpr (detail::has_type_deserializer_v<T>) {
869 throw std::runtime_error(
"Channel already connected");
870 if constexpr (SkipTypeCheck) {
873 if constexpr (!detail::has_type_deserializer_v<T>)
875 }
else if constexpr (has_esi_id_v<T>) {
876 verifyTypeCompatibility<T>(
inner);
877 }
else if constexpr (!detail::has_type_deserializer_v<T>) {
878 verifyTypeCompatibility<T>(
inner);
923 [cb = std::move(callback)](
MessageData) ->
bool {
return cb(); }, opts);
934 std::launch::deferred,
935 [f = std::move(innerFuture)]()
mutable ->
void { f.get(); });
984 return std::async(std::launch::deferred,
985 [fut = std::move(inner)]()
mutable -> T {
986 std::unique_ptr<T> v = fut.get();
988 throw std::runtime_error(
989 "TypedFunction: deserializer produced a null "
991 return std::move(*v);
999 "TypedFunction: null Function pointer (getAs failed or wrong type)");
1004 throw std::runtime_error(
"TypedFunction: must be 'connect'ed before "
1010 throw std::runtime_error(
"TypedFunction is already connected");
1015template <
typename ArgT,
typename ResultT,
bool SkipTypeCheck = false>
1036 std::future<ResultT>
call(
const ArgT &arg) {
1044 std::scoped_lock<std::mutex> lock(
callMutex);
1046 return detail::awaitDecoded<ResultT>(
resultPort->readAsync());
1053 typename First,
typename... Rest,
1054 typename = std::enable_if_t<
1055 std::is_constructible_v<ArgT, First, Rest...> &&
1056 (!std::is_same_v<std::decay_t<First>, ArgT> ||
sizeof...(Rest) != 0)>>
1057 std::future<ResultT>
call(First &&first, Rest &&...rest) {
1058 return call(ArgT(std::forward<First>(first), std::forward<Rest>(rest)...));
1062 template <
typename... Args>
1064 ->
decltype(this->
call(std::forward<Args>(args)...)) {
1065 return call(std::forward<Args>(args)...);
1073 std::optional<TypedWritePort<ArgT, SkipTypeCheck>>
argPort;
1079template <
typename ResultT,
bool SkipTypeCheck>
1102 std::scoped_lock<std::mutex> lock(
callMutex);
1104 return detail::awaitDecoded<ResultT>(
resultPort->readAsync());
1121template <
typename ArgT,
bool SkipTypeCheck>
1141 std::future<void>
call(
const ArgT &arg) {
1144 std::scoped_lock<std::mutex> lock(
callMutex);
1153 typename First,
typename... Rest,
1154 typename = std::enable_if_t<
1155 std::is_constructible_v<ArgT, First, Rest...> &&
1156 (!std::is_same_v<std::decay_t<First>, ArgT> ||
sizeof...(Rest) != 0)>>
1157 std::future<void>
call(First &&first, Rest &&...rest) {
1158 return call(ArgT(std::forward<First>(first), std::forward<Rest>(rest)...));
1162 template <
typename... Args>
1164 ->
decltype(this->
call(std::forward<Args>(args)...)) {
1165 return call(std::forward<Args>(args)...);
1173 std::optional<TypedWritePort<ArgT, SkipTypeCheck>>
argPort;
1179template <
bool SkipTypeCheck>
1202 std::scoped_lock<std::mutex> lock(
callMutex);
1258 "TypedCallback: null Callback pointer (getAs failed or wrong type)");
1264 throw std::runtime_error(
"TypedCallback is already connected");
1269template <
typename ArgT,
typename ResultT,
bool SkipTypeCheck = false>
1277 void connect(std::function<ResultT(
const ArgT &)> callback,
1278 bool quick =
false) {
1293 [
this](
const ArgT &arg) ->
bool {
1306 std::optional<TypedReadPort<ArgT, SkipTypeCheck>>
argPort;
1307 std::optional<TypedWritePort<ResultT, SkipTypeCheck>>
resultPort;
1312template <
typename ResultT,
bool SkipTypeCheck>
1320 void connect(std::function<ResultT()> callback,
bool quick =
false) {
1346 std::optional<TypedWritePort<ResultT, SkipTypeCheck>>
resultPort;
1351template <
typename ArgT,
bool SkipTypeCheck>
1359 void connect(std::function<
void(
const ArgT &)> callback,
bool quick =
false) {
1371 [
this](
const ArgT &arg) ->
bool {
1384 std::optional<TypedReadPort<ArgT, SkipTypeCheck>>
argPort;
1390template <
bool SkipTypeCheck>
1398 void connect(std::function<
void()> callback,
bool quick =
false) {
1437template <
typename T>
1478 BundlePort *port =
module->resolvePort(AppIDPath{id}, lastLookup);
1481 "' not found in module");
1488template <
typename T>
1491 T *result = port.
getAs<T>();
1494 "' has unexpected type (expected " +
1495 typeid(T).name() +
")");
1502 const std::string &name) {
1503 std::vector<uint32_t> indices;
1504 for (
const auto &[appid, port] :
module->getPorts())
1505 if (appid.name == name && appid.idx.has_value())
1506 indices.push_back(appid.idx.value());
1507 std::sort(indices.begin(), indices.end());
assert(baseType &&"element must be base type")
Arrays have a compile time specified (static) size and an element type.
Bit vectors include signed, unsigned, and signless integers.
Bits are just an array of bits.
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
T * getAs() const
Cast this Bundle port to a subclass which is actually useful.
ReadChannelPort & getRawRead(const std::string &name) const
WriteChannelPort & getRawWrite(const std::string &name) const
Get access to the raw byte streams of a channel.
Unidirectional channels are the basic communication primitive between the host and accelerator.
const Type * getType() const
const WindowType * getWindowType() const
If this port carries a windowed type, return the original WindowType (whose intoType is what getType(...
Represents either the top level or an instance of a hardware module.
const T & operator[](int idx) const
std::map< int, T > ports_
IndexedPorts(std::map< int, T > &&ports)
IndexedPorts & operator=(const IndexedPorts &)=delete
IndexedPorts(IndexedPorts &&)=default
IndexedPorts & operator=(IndexedPorts &&)=default
bool contains(int idx) const
IndexedPorts(const IndexedPorts &)=delete
A concrete flat message backed by a single vector of bytes.
const uint8_t * getBytes() const
const T * as() const
Cast to a type.
size_t getSize() const
Get the size of the data in bytes.
Helper base class for stateful deserializers which may emit zero, one, or many typed outputs for each...
detail::TypedReadOwnedCallback< T > OutputCallback
QueuedDecodeTypeDeserializer(OutputCallback output)
virtual ~QueuedDecodeTypeDeserializer()=default
std::queue< std::unique_ptr< T > > pendingOutputs
std::vector< std::unique_ptr< T > > DecodedOutputs
bool poke()
Retry delivery of any typed outputs which were previously blocked by the client callback.
bool push(std::unique_ptr< SegmentedMessageData > &msg)
Push one raw message into the deserializer.
virtual DecodedOutputs decode(std::unique_ptr< SegmentedMessageData > &msg)=0
Decode one raw message into zero or more typed outputs.
A ChannelPort which reads data from the accelerator.
virtual void connect(ReadCallback callback, const ConnectOptions &options={})
virtual std::future< MessageData > readAsync()
Asynchronous polling read.
virtual bool isConnected() const override
static constexpr uint64_t DefaultMaxDataQueueMsgs
Default max data queue size set at connect time.
virtual void disconnect() override
Disconnect the channel.
virtual void read(MessageData &outData)
Specify a buffer to read into.
Abstract multi-segment message.
virtual MessageData toMessageData() const
Flatten all segments into a standard MessageData.
Reusable serial-list window deserializer.
std::vector< data_frame > pending_frames_
typename Base::DecodedOutputs DecodedOutputs
DecodedOutputs decode(std::unique_ptr< SegmentedMessageData > &msg) override
Decode one raw message into zero or more typed outputs.
typename Base::OutputCallback OutputCallback
std::optional< header_frame > pending_header_
SerialListTypeDeserializer(OutputCallback output)
QueuedDecodeTypeDeserializer< T > Base
typename T::header_frame header_frame
static constexpr size_t kFrameSize
typename T::count_type count_type
typename T::data_frame data_frame
std::vector< uint8_t > partial_
Type aliases provide a named type which forwards to an inner type.
Root class of the ESI type system.
std::string toString(bool oneLine=false) const
services::CallService::Callback * inner
std::optional< TypedReadPort< ArgT, SkipTypeCheck > > argPort
std::optional< TypedWritePort< void > > resultPort
const services::CallService::Callback & raw() const
std::function< void(const ArgT &)> userCallback
void connect(std::function< void(const ArgT &)> callback, bool quick=false)
TypedCallback(const TypedCallback &)=delete
services::CallService::Callback & raw()
TypedCallback & operator=(const TypedCallback &)=delete
TypedCallback(services::CallService::Callback *cb)
std::optional< TypedWritePort< ResultT, SkipTypeCheck > > resultPort
services::CallService::Callback & raw()
std::optional< TypedReadPort< void > > argPort
TypedCallback(const TypedCallback &)=delete
void connect(std::function< ResultT()> callback, bool quick=false)
TypedCallback(services::CallService::Callback *cb)
std::function< ResultT()> userCallback
const services::CallService::Callback & raw() const
services::CallService::Callback * inner
TypedCallback & operator=(const TypedCallback &)=delete
std::optional< TypedWritePort< void > > resultPort
std::optional< TypedReadPort< void > > argPort
TypedCallback(services::CallService::Callback *cb)
services::CallService::Callback & raw()
std::function< void()> userCallback
void connect(std::function< void()> callback, bool quick=false)
TypedCallback & operator=(const TypedCallback &)=delete
TypedCallback(const TypedCallback &)=delete
const services::CallService::Callback & raw() const
services::CallService::Callback * inner
services::CallService::Callback * inner
std::optional< TypedReadPort< ArgT, SkipTypeCheck > > argPort
services::CallService::Callback & raw()
void connect(std::function< ResultT(const ArgT &)> callback, bool quick=false)
TypedCallback(services::CallService::Callback *cb)
std::optional< TypedWritePort< ResultT, SkipTypeCheck > > resultPort
TypedCallback & operator=(const TypedCallback &)=delete
std::function< ResultT(const ArgT &)> userCallback
const services::CallService::Callback & raw() const
TypedCallback(const TypedCallback &)=delete
auto operator()(Args &&...args) -> decltype(this->call(std::forward< Args >(args)...))
Function-call operator overloads: forward to call().
TypedFunction & operator=(const TypedFunction &)=delete
std::optional< TypedWritePort< ArgT, SkipTypeCheck > > argPort
std::future< void > call(First &&first, Rest &&...rest)
Emplace-style call: constructs ArgT in-place from the forwarded arguments and forwards to call(const ...
TypedFunction(const TypedFunction &)=delete
std::optional< TypedReadPort< void > > resultPort
const services::FuncService::Function & raw() const
services::FuncService::Function & raw()
std::future< void > call(const ArgT &arg)
services::FuncService::Function * inner
TypedFunction(services::FuncService::Function *func)
std::optional< TypedReadPort< ResultT, SkipTypeCheck > > resultPort
std::future< ResultT > call()
TypedFunction & operator=(const TypedFunction &)=delete
std::optional< TypedWritePort< void > > argPort
services::FuncService::Function & raw()
TypedFunction(const TypedFunction &)=delete
services::FuncService::Function * inner
std::future< ResultT > operator()()
Function-call operator overload: forwards to call().
const services::FuncService::Function & raw() const
TypedFunction(services::FuncService::Function *func)
const services::FuncService::Function & raw() const
TypedFunction(const TypedFunction &)=delete
TypedFunction & operator=(const TypedFunction &)=delete
services::FuncService::Function * inner
std::future< void > call()
TypedFunction(services::FuncService::Function *func)
std::optional< TypedWritePort< void > > argPort
std::optional< TypedReadPort< void > > resultPort
services::FuncService::Function & raw()
std::future< void > operator()()
Function-call operator overload: forwards to call().
std::optional< TypedWritePort< ArgT, SkipTypeCheck > > argPort
std::optional< TypedReadPort< ResultT, SkipTypeCheck > > resultPort
std::future< ResultT > call(First &&first, Rest &&...rest)
Emplace-style call: constructs ArgT in-place from the forwarded arguments and forwards to call(const ...
TypedFunction(const TypedFunction &)=delete
services::FuncService::Function & raw()
auto operator()(Args &&...args) -> decltype(this->call(std::forward< Args >(args)...))
Function-call operator overloads: forward to call().
std::future< ResultT > call(const ArgT &arg)
TypedFunction & operator=(const TypedFunction &)=delete
const services::FuncService::Function & raw() const
TypedFunction(services::FuncService::Function *func)
Implicit conversion from Function* (returned by getAs<>()).
services::FuncService::Function * inner
TypedReadPort(const TypedReadPort &)=delete
TypedReadPort & operator=(TypedReadPort &&)=delete
TypedReadPort & operator=(const TypedReadPort &)=delete
TypedReadPort(ReadChannelPort &port)
TypedReadPort(ReadChannelPort *port)
TypedReadPort(TypedReadPort &&)=delete
std::future< void > readAsync()
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
void connect(std::function< bool()> callback, const ChannelPort::ConnectOptions &opts={std::nullopt, false})
const ReadChannelPort & raw() const
Strongly typed wrapper around a raw read channel.
TypedReadPort(ReadChannelPort &port)
detail::DeserializerFor< T > Deserializer
TypedReadPort & operator=(const TypedReadPort &)=delete
std::unique_ptr< T > read()
Blocking typed read in polling mode.
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Connect in polling mode.
uint64_t maxDataQueueMsgs
void disconnect()
Disconnect the typed port and abandon any pending polling reads.
void setMaxDataQueueMsgs(uint64_t maxMsgs)
Set the maximum number of decoded typed values buffered in polling mode.
void emplaceDeserializer(detail::DeserializerOutputCallback< T > callback)
void connect(std::function< bool(const T &)> callback, const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Connect a non-owning typed callback.
const ReadChannelPort & raw() const
TypedReadPort & operator=(TypedReadPort &&)=delete
std::optional< PollingState > pollingState
TypedReadPort(const TypedReadPort &)=delete
std::optional< Deserializer > deserializer
void connect(detail::TypedReadOwnedCallback< T > callback, const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Connect an owning typed callback.
std::future< std::unique_ptr< T > > readAsync()
Asynchronous typed read in polling mode.
TypedReadPort(ReadChannelPort *port)
TypedReadPort(TypedReadPort &&)=delete
TypedWritePort(WriteChannelPort &port)
TypedWritePort(WriteChannelPort *port)
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
const WriteChannelPort & raw() const
const WriteChannelPort & raw() const
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
void write(std::unique_ptr< T > &data)
Write by taking ownership.
bool tryWrite(const T &data)
TypedWritePort(WriteChannelPort &port)
void write(const T &data)
TypedWritePort(WriteChannelPort *port)
The "void" type is a special type which can be used to represent no type.
Windows represent a fixed-size sliding window over a stream of data.
A ChannelPort which sends data to the accelerator.
virtual bool isConnected() const override
virtual void disconnect() override
void write(const MessageData &data)
A very basic blocking write API.
bool flush()
Flush any buffered data.
bool tryWrite(const MessageData &data)
A basic non-blocking write API.
virtual void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
Default deserializer for simple 1:1 typed reads.
bool push(std::unique_ptr< SegmentedMessageData > &msg)
TypedReadOwnedCallback< T > OutputCallback
std::unique_ptr< T > pendingOutput
PODTypeDeserializer(OutputCallback output, WireInfo wireInfo)
Shared queue/promise helper for polling-style read APIs.
A function call which gets attached to a service port.
A function call which gets attached to a service port.
constexpr bool has_type_deserializer_v
ChannelPort::ConnectOptions typedFunctionConnectOptions()
Standard ConnectOptions for typed function ports: untranslated frames so the deserializer can see raw...
void throwAlreadyConnected()
Throw a clear "already connected" error from connect() paths.
void throwNullFunction()
Throw the standard "null Function pointer" error used by every TypedFunction specialization.
std::function< bool(std::unique_ptr< T > &)> TypedReadOwnedCallback
Owning callback used by typed read deserializers.
void throwNotConnected()
Throw a clear "not connected" error from call() paths.
void throwCallbackAlreadyConnected()
Throw a clear "already connected" error from TypedCallback connect() paths.
typename DeserializerFor< T >::OutputCallback DeserializerOutputCallback
void throwNullCallback()
Throw the standard "null Callback pointer" error used by every TypedCallback specialization.
typename DeserializerSelector< T >::type DeserializerFor
std::future< T > awaitDecoded(std::future< std::unique_ptr< T > > inner)
Convert a std::future<std::unique_ptr<T>> (as returned by TypedReadPort::readAsync()) into a std::fut...
const MessageData & getMessageDataRef(const SegmentedMessageData &msg, MessageData &scratch)
std::string toString(const std::any &a)
'Stringify' a std::any. This is used to log std::any values by some loggers.
void verifyTypeCompatibility(const Type *portType)
MessageData toMessageData(const T &data, WireInfo wi)
Pack a C++ integral value into a MessageData with the given wire byte count.
std::vector< uint32_t > findPortIndices(HWModule *module, const std::string &name)
Return a sorted vector of the idx values for every port whose AppID name matches name.
WireInfo getWireInfo(const Type *portType)
BundlePort & findPortOrThrow(HWModule *module, const AppID &id)
Look up a BundlePort by AppID in module.
constexpr bool has_esi_id_v
T * findPortAsOrThrow(HWModule *module, const AppID &id)
Look up a BundlePort by AppID and cast it to T.
constexpr bool has_esi_window_id_v
constexpr bool is_std_array_v
const Type * unwrapTypeAlias(const Type *t)
Unwrap TypeAliasType (possibly recursively) to get the underlying type.
T fromMessageData(const MessageData &msg, WireInfo wi)
Unpack a MessageData into a C++ integral value with the given wire info.
Compute the wire byte count for a port type.
typename T::TypeDeserializer type
PODTypeDeserializer< T > type