24#include "Simo/compiler/BoostTypeIndexRuntimeCast.h"
25#include "Simo/compiler/Compiler.h"
32 virtual ~Port() =
default;
33 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
35 using TypeId = boost::typeindex::type_index;
38 template <
typename Self>
40 return boost::typeindex::type_id<Self>();
43 TypeId get_runtime_type()
const {
44 return boost::typeindex::type_id_runtime(*
this);
48 virtual bool connect(Port* other) = 0;
50 virtual bool connected()
const = 0;
52 [[nodiscard]] std::string_view name()
const {
return name_; }
53 void name(
const std::string_view name) { name_ = name; }
61template <
typename Payload>
64template <
typename Payload,
typename ReturnType>
71template <
typename Payload>
74 friend class InPort<Payload>;
76 enum struct PORT_STATE : std::uint8_t {
81 enum struct SEND_OUTCOME : std::uint8_t {
86 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
88 bool connect(
Port* other)
override;
91 bool connected()
const override {
92 return connecting_port !=
nullptr;
95 SEND_OUTCOME send(Payload&& payload) {
96 storage = std::move(payload);
98 case PORT_STATE::EMPTY:
99 state_ = PORT_STATE::FILLED;
100 return SEND_OUTCOME::NEW;
101 case PORT_STATE::FILLED:
102 state_ = PORT_STATE::FILLED;
103 return SEND_OUTCOME::REPLACED;
108 SEND_OUTCOME send(Payload& payload) {
111 case PORT_STATE::EMPTY:
112 state_ = PORT_STATE::FILLED;
113 return SEND_OUTCOME::NEW;
114 case PORT_STATE::FILLED:
115 state_ = PORT_STATE::FILLED;
116 return SEND_OUTCOME::REPLACED;
121 void clear() { state_ = PORT_STATE::EMPTY; }
123 PORT_STATE state()
const {
return state_; }
127 PORT_STATE state_ = PORT_STATE::EMPTY;
135template <
typename Payload>
139 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
141 bool connect(
Port* other)
override;
144 bool connected()
const override {
145 return connecting_port !=
nullptr;
149 SIMO_ASSERT(connecting_port !=
nullptr);
150 SIMO_ASSERT(connecting_port->state() !=
151 OutPort<Payload>::PORT_STATE::EMPTY);
152 Payload out_p = std::move(connecting_port->storage);
153 connecting_port->clear();
158 if (connecting_port ==
nullptr ||
159 connecting_port->state() == OutPort<Payload>::PORT_STATE::EMPTY) {
162 return &connecting_port->storage;
166 if (connecting_port !=
nullptr) {
167 connecting_port->clear();
177template <
typename Payload,
typename ReturnType>
178class SIMO_PUBLIC CallbackInPort :
public Port {
182 using Callback = std::function<ReturnType(Payload)>;
184 CallbackInPort() =
default;
185 explicit CallbackInPort(Callback callback) : callback_(std::move(callback)) {}
187 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
189 bool connect(
Port* other)
override;
192 bool connected()
const override {
193 return connecting_port !=
nullptr;
196 void callback(Callback callback) { callback_ = std::move(callback); }
199 bool has_callback()
const {
200 return static_cast<bool>(callback_);
204 void receive(Payload payload)
205 requires(std::is_same_v<ReturnType, void>)
208 callback_(std::forward<Payload>(payload));
213 std::optional<ReturnType> receive(Payload payload)
214 requires(!std::is_same_v<ReturnType, void>)
217 return callback_(std::forward<Payload>(payload));
226enum struct SIMO_PUBLIC VERIFY_CONTRACT_ERROR : std::uint8_t {
228 NO_CONNECTED_PORT_CONTRACT,
236template <
typename Contract>
239 std::optional<Contract> contract() {
return contract_; }
240 void contract(Contract contract) { contract_ = contract; }
244 void connected_port_contract_predicate(
245 std::function<
bool(Contract)> predicate) {
246 connected_port_contract_predicate_ = predicate;
248 std::expected<bool, VERIFY_CONTRACT_ERROR> verify_connected_port_contract() {
249 if (connected_port_ ==
nullptr) {
250 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_CONNECTED_PORT);
252 if (connected_port_->contract() == std::nullopt) {
253 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_CONNECTED_PORT_CONTRACT);
255 if (!connected_port_contract_predicate_) {
256 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_PREDICATE);
258 return connected_port_contract_predicate_(*connected_port_->contract());
262 std::optional<Contract> contract_;
264 std::function<bool(Contract)> connected_port_contract_predicate_{};
270template <
typename Payload,
typename ReturnType,
typename Contract>
271class SIMO_PUBLIC CallbackContractOutPort
275 CallbackContractOutPort() =
default;
279 bool connect(
Port* other)
override;
285template <
typename Payload,
typename ReturnType,
typename Contract>
286class SIMO_PUBLIC CallbackContractInPort
287 :
public CallbackInPort<Payload, ReturnType>,
290 CallbackContractInPort() =
default;
292 explicit CallbackContractInPort(
293 CallbackInPort<Payload, ReturnType>::Callback callback)
294 : CallbackInPort<Payload, ReturnType>(std::move(callback)) {}
296 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(CallbackInPort<Payload, ReturnType>)
298 bool connect(
Port* other)
override;
303template <
typename Payload,
typename ReturnType>
307 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
309 bool connect(
Port* other)
override;
312 bool connected()
const override {
313 return connecting_port !=
nullptr;
316 template <
typename Arg>
317 requires std::constructible_from<Payload, Arg&&> &&
318 (!std::is_void_v<ReturnType>)
320 std::optional<ReturnType> send(Arg&& payload) {
321 if (connecting_port ==
nullptr) {
325 return connecting_port->receive(std::forward<Arg>(payload));
328 template <
typename Arg>
329 requires std::constructible_from<Payload, Arg&&> &&
330 std::is_void_v<ReturnType>
331 void send(Arg&& payload) {
332 if (connecting_port ==
nullptr || !connecting_port->has_callback()) {
336 connecting_port->receive(std::forward<Arg>(payload));
343template <
typename Payload>
344bool OutPort<Payload>::connect(
Port* other) {
345 if (other ==
nullptr) {
348 auto* other_casted = boost::typeindex::runtime_cast<InPort<Payload>*>(other);
349 if (other_casted ==
nullptr) {
352 connecting_port = other_casted;
353 other_casted->connecting_port =
this;
357template <
typename Payload>
358bool InPort<Payload>::connect(Port* other) {
359 if (other ==
nullptr) {
362 auto* other_casted = boost::typeindex::runtime_cast<OutPort<Payload>*>(other);
363 if (other_casted ==
nullptr) {
366 connecting_port = other_casted;
367 other_casted->connecting_port =
this;
371template <
typename Payload,
typename ReturnType>
372bool CallbackOutPort<Payload, ReturnType>::connect(Port* other) {
373 if (other ==
nullptr) {
377 boost::typeindex::runtime_cast<CallbackInPort<Payload, ReturnType>*>(
379 if (other_casted ==
nullptr) {
382 connecting_port = other_casted;
383 other_casted->connecting_port =
this;
387template <
typename Payload,
typename ReturnType>
388bool CallbackInPort<Payload, ReturnType>::connect(Port* other) {
389 if (other ==
nullptr) {
393 boost::typeindex::runtime_cast<CallbackOutPort<Payload, ReturnType>*>(
395 if (other_casted ==
nullptr) {
398 connecting_port = other_casted;
399 other_casted->connecting_port =
this;
403template <
typename Payload,
typename ReturnType,
typename Contract>
404bool CallbackContractOutPort<Payload, ReturnType, Contract>::connect(
406 if (other ==
nullptr) {
409 auto* other_casted = boost::typeindex::runtime_cast<
411 if (other_casted ==
nullptr) {
414 ContractInterface<Contract>::connected_port(other_casted);
415 other_casted->connected_port(
this);
416 return CallbackOutPort<Payload, ReturnType>::connect(other_casted);
419template <
typename Payload,
typename ReturnType,
typename Contract>
420bool CallbackContractInPort<Payload, ReturnType, Contract>::connect(
422 if (other ==
nullptr) {
425 auto* other_casted = boost::typeindex::runtime_cast<
427 if (other_casted ==
nullptr) {
430 ContractInterface<Contract>::connected_port(other_casted);
431 other_casted->connected_port(
this);
432 return CallbackInPort<Payload, ReturnType>::connect(other_casted);
438template <
typename OutPayload,
typename InPayload>
441 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
442 bool connect(
Port* other)
override;
445 bool connected()
const override {
446 return out_port.connected() && in_port.connected();
450 OutPort<OutPayload>::SEND_OUTCOME
send_out(OutPayload&& payload) {
451 return out_port.send(std::move(payload));
454 OutPort<OutPayload>::SEND_OUTCOME send_out(OutPayload& payload) {
455 return out_port.send(payload);
458 void clear_out() { out_port.clear(); }
460 void clear_in() { in_port.clear(); }
466 InPayload*
peek_in() {
return in_port.peek(); }
473template <
typename Payload>
474using BidirectionalPort = BidirectionalPortTyped<Payload, Payload>;
476template <
typename OutPayload,
typename InPayload>
477bool BidirectionalPortTyped<OutPayload, InPayload>::connect(
Port* other) {
478 auto* other_casted = boost::typeindex::runtime_cast<
479 BidirectionalPortTyped<InPayload, OutPayload>*>(other);
480 if (other_casted ==
nullptr) {
483 return out_port.connect(&other_casted->in_port) &&
484 in_port.connect(&other_casted->out_port);
Generic port. It offers the virtual method connect.
Definition Port.h:30
TypeId get_type_id(this Self &)
Utility to the get type of class. Need the type at compile time.
Definition Port.h:39
InPayload && receive_in()
Extract the payload from the in port.
Definition Port.h:463
OutPort< OutPayload >::SEND_OUTCOME send_out(OutPayload &&payload)
Push a payload on the out port.
Definition Port.h:450
InPayload * peek_in()
Peek the payload from the in port.
Definition Port.h:466
General namespace for Simo.
Definition Collection.h:51