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>();
44 virtual bool connect(
Port* other) = 0;
46 [[nodiscard]] std::string_view name()
const {
return name_; }
47 void name(
const std::string_view name) { name_ = name; }
55template <
typename Payload>
58template <
typename Payload,
typename ReturnType>
65template <
typename Payload>
68 friend class InPort<Payload>;
70 enum struct PORT_STATE : std::uint8_t {
75 enum struct SEND_OUTCOME : std::uint8_t {
80 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
82 bool connect(
Port* other)
override;
84 SEND_OUTCOME send(Payload&& payload) {
85 storage = std::move(payload);
87 case PORT_STATE::EMPTY:
88 state_ = PORT_STATE::FILLED;
89 return SEND_OUTCOME::NEW;
90 case PORT_STATE::FILLED:
91 state_ = PORT_STATE::FILLED;
92 return SEND_OUTCOME::REPLACED;
97 SEND_OUTCOME send(Payload& payload) {
100 case PORT_STATE::EMPTY:
101 state_ = PORT_STATE::FILLED;
102 return SEND_OUTCOME::NEW;
103 case PORT_STATE::FILLED:
104 state_ = PORT_STATE::FILLED;
105 return SEND_OUTCOME::REPLACED;
110 void clear() { state_ = PORT_STATE::EMPTY; }
112 PORT_STATE state()
const {
return state_; }
116 PORT_STATE state_ = PORT_STATE::EMPTY;
123template <
typename Payload>
127 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
129 bool connect(
Port* other)
override;
132 SIMO_ASSERT(connecting_port !=
nullptr);
133 SIMO_ASSERT(connecting_port->state() !=
134 OutPort<Payload>::PORT_STATE::EMPTY);
135 Payload out_p = std::move(connecting_port->storage);
136 connecting_port->clear();
141 if (connecting_port ==
nullptr ||
142 connecting_port->state() == OutPort<Payload>::PORT_STATE::EMPTY) {
145 return &connecting_port->storage;
149 if (connecting_port !=
nullptr) {
150 connecting_port->clear();
160template <
typename Payload,
typename ReturnType>
161class SIMO_PUBLIC CallbackInPort :
public Port {
165 using Callback = std::function<ReturnType(Payload)>;
167 CallbackInPort() =
default;
168 explicit CallbackInPort(Callback callback) : callback_(std::move(callback)) {}
170 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
172 bool connect(
Port* other)
override;
174 void callback(Callback callback) { callback_ = std::move(callback); }
177 bool has_callback()
const {
178 return static_cast<bool>(callback_);
182 void receive(Payload payload)
183 requires(std::is_same_v<ReturnType, void>)
186 callback_(std::forward<Payload>(payload));
191 std::optional<ReturnType> receive(Payload payload)
192 requires(!std::is_same_v<ReturnType, void>)
195 return callback_(std::forward<Payload>(payload));
203enum struct SIMO_PUBLIC VERIFY_CONTRACT_ERROR : std::uint8_t {
205 NO_CONNECTED_PORT_CONTRACT,
213template <
typename Contract>
216 std::optional<Contract> contract() {
return contract_; }
217 void contract(Contract contract) { contract_ = contract; }
221 void connected_port_contract_predicate(
222 std::function<
bool(Contract)> predicate) {
223 connected_port_contract_predicate_ = predicate;
225 std::expected<bool, VERIFY_CONTRACT_ERROR> verify_connected_port_contract() {
226 if (connected_port_ ==
nullptr) {
227 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_CONNECTED_PORT);
229 if (connected_port_->contract() == std::nullopt) {
230 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_CONNECTED_PORT_CONTRACT);
232 if (!connected_port_contract_predicate_) {
233 return std::unexpected(VERIFY_CONTRACT_ERROR::NO_PREDICATE);
235 return connected_port_contract_predicate_(*connected_port_->contract());
239 std::optional<Contract> contract_;
241 std::function<bool(Contract)> connected_port_contract_predicate_{};
247template <
typename Payload,
typename ReturnType,
typename Contract>
248class SIMO_PUBLIC CallbackContractOutPort
252 CallbackContractOutPort() =
default;
256 bool connect(
Port* other)
override;
262template <
typename Payload,
typename ReturnType,
typename Contract>
263class SIMO_PUBLIC CallbackContractInPort
264 :
public CallbackInPort<Payload, ReturnType>,
267 CallbackContractInPort() =
default;
269 explicit CallbackContractInPort(
270 CallbackInPort<Payload, ReturnType>::Callback callback)
271 : CallbackInPort<Payload, ReturnType>(std::move(callback)) {}
273 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(CallbackInPort<Payload, ReturnType>)
275 bool connect(
Port* other)
override;
280template <
typename Payload,
typename ReturnType>
284 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
286 bool connect(
Port* other)
override;
288 template <
typename Arg>
289 requires std::constructible_from<Payload, Arg&&> &&
290 (!std::is_void_v<ReturnType>)
292 std::optional<ReturnType> send(Arg&& payload) {
293 if (connecting_port ==
nullptr) {
297 return connecting_port->receive(std::forward<Arg>(payload));
300 template <
typename Arg>
301 requires std::constructible_from<Payload, Arg&&> &&
302 std::is_void_v<ReturnType>
303 void send(Arg&& payload) {
304 if (connecting_port ==
nullptr || !connecting_port->has_callback()) {
308 connecting_port->receive(std::forward<Arg>(payload));
315template <
typename Payload>
316bool OutPort<Payload>::connect(
Port* other) {
317 if (other ==
nullptr) {
320 auto* other_casted = boost::typeindex::runtime_cast<InPort<Payload>*>(other);
321 if (other_casted ==
nullptr) {
324 other_casted->connecting_port =
this;
328template <
typename Payload>
329bool InPort<Payload>::connect(Port* other) {
330 if (other ==
nullptr) {
333 auto* other_casted = boost::typeindex::runtime_cast<OutPort<Payload>*>(other);
334 if (other_casted ==
nullptr) {
337 connecting_port = other_casted;
341template <
typename Payload,
typename ReturnType>
342bool CallbackOutPort<Payload, ReturnType>::connect(Port* other) {
343 if (other ==
nullptr) {
347 boost::typeindex::runtime_cast<CallbackInPort<Payload, ReturnType>*>(
349 if (other_casted ==
nullptr) {
352 connecting_port = other_casted;
356template <
typename Payload,
typename ReturnType>
357bool CallbackInPort<Payload, ReturnType>::connect(Port* other) {
358 if (other ==
nullptr) {
362 boost::typeindex::runtime_cast<CallbackOutPort<Payload, ReturnType>*>(
364 if (other_casted ==
nullptr) {
367 other_casted->connecting_port =
this;
371template <
typename Payload,
typename ReturnType,
typename Contract>
372bool CallbackContractOutPort<Payload, ReturnType, Contract>::connect(
374 if (other ==
nullptr) {
377 auto* other_casted = boost::typeindex::runtime_cast<
379 if (other_casted ==
nullptr) {
382 ContractInterface<Contract>::connected_port(other_casted);
383 other_casted->connected_port(
this);
384 return CallbackOutPort<Payload, ReturnType>::connect(other_casted);
387template <
typename Payload,
typename ReturnType,
typename Contract>
388bool CallbackContractInPort<Payload, ReturnType, Contract>::connect(
390 if (other ==
nullptr) {
393 auto* other_casted = boost::typeindex::runtime_cast<
395 if (other_casted ==
nullptr) {
398 ContractInterface<Contract>::connected_port(other_casted);
399 other_casted->connected_port(
this);
400 return CallbackInPort<Payload, ReturnType>::connect(other_casted);
406template <
typename OutPayload,
typename InPayload>
409 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(
Port)
410 bool connect(
Port* other)
override;
413 OutPort<OutPayload>::SEND_OUTCOME
send_out(OutPayload&& payload) {
414 return out_port.send(std::move(payload));
417 OutPort<OutPayload>::SEND_OUTCOME send_out(OutPayload& payload) {
418 return out_port.send(payload);
421 void clear_out() { out_port.clear(); }
423 void clear_in() { in_port.clear(); }
429 InPayload*
peek_in() {
return in_port.peek(); }
436template <
typename Payload>
437using BidirectionalPort = BidirectionalPortTyped<Payload, Payload>;
439template <
typename OutPayload,
typename InPayload>
440bool BidirectionalPortTyped<OutPayload, InPayload>::connect(
Port* other) {
441 auto* other_casted = boost::typeindex::runtime_cast<
442 BidirectionalPortTyped<InPayload, OutPayload>*>(other);
443 if (other_casted ==
nullptr) {
446 return out_port.connect(&other_casted->in_port) &&
447 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:426
OutPort< OutPayload >::SEND_OUTCOME send_out(OutPayload &&payload)
Push a payload on the out port.
Definition Port.h:413
InPayload * peek_in()
Peek the payload from the in port.
Definition Port.h:429
General namespace for Simo.
Definition Collection.h:51