diff --git a/.github/actions/install-iceoryx-deps-and-clang/action.yml b/.github/actions/install-iceoryx-deps-and-clang/action.yml index 1bd0ee3d7..07c680155 100644 --- a/.github/actions/install-iceoryx-deps-and-clang/action.yml +++ b/.github/actions/install-iceoryx-deps-and-clang/action.yml @@ -6,15 +6,15 @@ runs: shell: bash run: | sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" + sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main" sudo apt-get update sudo apt-get install -y libacl1-dev - sudo apt-get install -y clang-format-18 clang-tidy-18 clang-tools-18 clang-18 lld + sudo apt-get install -y clang-format-19 clang-tidy-19 clang-tools-19 clang-19 lld sudo rm /usr/bin/clang sudo rm /usr/bin/clang++ sudo rm /usr/bin/clang-tidy sudo rm /usr/bin/clang-format - sudo ln -s /usr/bin/clang-18 /usr/bin/clang - sudo ln -s /usr/bin/clang++-18 /usr/bin/clang++ - sudo ln -s /usr/bin/clang-tidy-18 /usr/bin/clang-tidy - sudo ln -s /usr/bin/clang-format-18 /usr/bin/clang-format + sudo ln -s /usr/bin/clang-19 /usr/bin/clang + sudo ln -s /usr/bin/clang++-19 /usr/bin/clang++ + sudo ln -s /usr/bin/clang-tidy-19 /usr/bin/clang-tidy + sudo ln -s /usr/bin/clang-format-19 /usr/bin/clang-format diff --git a/doc/release-notes/iceoryx2-unreleased.md b/doc/release-notes/iceoryx2-unreleased.md index f0836d2b2..cfb430ba8 100644 --- a/doc/release-notes/iceoryx2-unreleased.md +++ b/doc/release-notes/iceoryx2-unreleased.md @@ -11,6 +11,7 @@ conflicts when merging. --> +* C++ bindings for attributes [#264](https://github.com/eclipse-iceoryx/iceoryx2/issues/264) * Add Event-Multiplexer `WaitSet` [#390](https://github.com/eclipse-iceoryx/iceoryx2/issues/390) * Add `PeriodicTimer` into POSIX building blocks [#425](https://github.com/eclipse-iceoryx/iceoryx2/issues/425) * Developer permissions for resources [#460](https://github.com/eclipse-iceoryx/iceoryx2/issues/460) diff --git a/examples/cxx/event_based_communication/src/custom_publisher.hpp b/examples/cxx/event_based_communication/src/custom_publisher.hpp index 8b96e1fce..5dcc63f7a 100644 --- a/examples/cxx/event_based_communication/src/custom_publisher.hpp +++ b/examples/cxx/event_based_communication/src/custom_publisher.hpp @@ -41,8 +41,8 @@ class CustomPublisher : public iox2::FileDescriptorBased { .expect(""); } - static auto create(iox2::Node& node, - const iox2::ServiceName& service_name) -> CustomPublisher { + static auto create(iox2::Node& node, const iox2::ServiceName& service_name) + -> CustomPublisher { auto pubsub_service = node.service_builder(service_name) .publish_subscribe() .history_size(HISTORY_SIZE) diff --git a/examples/cxx/event_based_communication/src/custom_subscriber.hpp b/examples/cxx/event_based_communication/src/custom_subscriber.hpp index 566662290..31d684085 100644 --- a/examples/cxx/event_based_communication/src/custom_subscriber.hpp +++ b/examples/cxx/event_based_communication/src/custom_subscriber.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_EXAMPLES_CUSTOM_SUBSCRIBER_HPP #define IOX2_EXAMPLES_CUSTOM_SUBSCRIBER_HPP -#include "iox/into.hpp" #include "iox2/file_descriptor.hpp" #include "iox2/listener.hpp" #include "iox2/node.hpp" @@ -44,8 +43,8 @@ class CustomSubscriber : public iox2::FileDescriptorBased { auto operator=(const CustomSubscriber&) -> CustomSubscriber& = delete; auto operator=(CustomSubscriber&&) -> CustomSubscriber& = default; - static auto create(iox2::Node& node, - const iox2::ServiceName& service_name) -> CustomSubscriber { + static auto create(iox2::Node& node, const iox2::ServiceName& service_name) + -> CustomSubscriber { auto pubsub_service = node.service_builder(service_name).publish_subscribe().open_or_create().expect(""); auto event_service = node.service_builder(service_name).event().open_or_create().expect(""); diff --git a/iceoryx2-ffi/cxx/CMakeLists.txt b/iceoryx2-ffi/cxx/CMakeLists.txt index 20d2b114c..9bfee8b92 100644 --- a/iceoryx2-ffi/cxx/CMakeLists.txt +++ b/iceoryx2-ffi/cxx/CMakeLists.txt @@ -36,6 +36,10 @@ target_include_directories(includes-only-cxx # object lib add_library(iceoryx2-cxx-object-lib OBJECT + src/attribute.cpp + src/attribute_set.cpp + src/attribute_specifier.cpp + src/attribute_verifier.cpp src/config.cpp src/event_id.cpp src/file_descriptor.cpp diff --git a/iceoryx2-ffi/cxx/include/iox2/attribute.hpp b/iceoryx2-ffi/cxx/include/iox2/attribute.hpp index a12d2d4a5..05c53dc00 100644 --- a/iceoryx2-ffi/cxx/include/iox2/attribute.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/attribute.hpp @@ -13,25 +13,39 @@ #ifndef IOX2_ATTRIBUTE_HPP #define IOX2_ATTRIBUTE_HPP -#include "iox/assertions_addendum.hpp" #include "iox/string.hpp" #include "iox2/internal/iceoryx2.hpp" -#include - namespace iox2 { +/// Represents a single service attribute (key-value) pair that can be defined when the service +/// is being created. class Attribute { public: using Key = iox::string; using Value = iox::string; +}; + +/// Represents a single view service attribute (key-value) pair that can be defined when the service +/// is being created. +/// +/// @attention The parent from which the view was extracted MUST live longer than the +/// [`AttributeView`]. +class AttributeView { + public: + /// Acquires the service attribute key + auto key() const -> Attribute::Key; + + /// Acquires the service attribute value + auto value() const -> Attribute::Value; + + private: + friend class AttributeSetView; + explicit AttributeView(iox2_attribute_h_ref handle); - auto key() const -> Key { - IOX_TODO(); - } - auto value() const -> Value { - IOX_TODO(); - } + iox2_attribute_h_ref m_handle = nullptr; }; } // namespace iox2 + // +auto operator<<(std::ostream& stream, const iox2::AttributeView& value) -> std::ostream&; #endif diff --git a/iceoryx2-ffi/cxx/include/iox2/attribute_set.hpp b/iceoryx2-ffi/cxx/include/iox2/attribute_set.hpp index b8cd576e5..d6821b93a 100644 --- a/iceoryx2-ffi/cxx/include/iox2/attribute_set.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/attribute_set.hpp @@ -13,26 +13,44 @@ #ifndef IOX2_ATTRIBUTE_SET_HPP #define IOX2_ATTRIBUTE_SET_HPP -#include "iox/assertions_addendum.hpp" -#include "iox/vector.hpp" +#include "iox/function.hpp" #include "iox2/attribute.hpp" #include "iox2/internal/iceoryx2.hpp" #include namespace iox2 { -class AttributeSet { +/// Represents all service attributes. They can be set when the service is created. +/// +/// @attention The parent from which the view was extracted MUST live longer than the +/// [`AttributeSetView`]. +class AttributeSetView { public: - auto get(const Attribute::Key& key) const -> iox::vector { - IOX_TODO(); - } -}; + /// Returns the number of [`Attribute`]s stored inside the [`AttributeSet`]. + auto len() const -> uint64_t; + + /// Returns a [`AttributeView`] at a specific index. The number of indices is returned via + /// [`AttributeSetView::len()`]. + auto at(uint64_t index) const -> AttributeView; + + /// Returns all values to a specific key + void get_key_values(const Attribute::Key& key, + const iox::function& callback) const; -inline auto operator<<(std::ostream& stream, const AttributeSet& value) -> std::ostream& { - stream << "AttributeSet { }"; - return stream; -} + private: + template + friend class PortFactoryPublishSubscribe; + template + friend class PortFactoryEvent; + friend class AttributeVerifier; + friend class AttributeSpecifier; + explicit AttributeSetView(iox2_attribute_set_h_ref handle); + + iox2_attribute_set_h_ref m_handle = nullptr; +}; } // namespace iox2 +auto operator<<(std::ostream& stream, const iox2::AttributeSetView& value) -> std::ostream&; + #endif diff --git a/iceoryx2-ffi/cxx/include/iox2/attribute_specifier.hpp b/iceoryx2-ffi/cxx/include/iox2/attribute_specifier.hpp index da3af6bfb..0d90fe8f8 100644 --- a/iceoryx2-ffi/cxx/include/iox2/attribute_specifier.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/attribute_specifier.hpp @@ -14,17 +14,37 @@ #define IOX2_ATTRIBUTE_SPECIFIER_HPP #include "attribute_set.hpp" -#include "iox/assertions_addendum.hpp" namespace iox2 { + +/// Represents the set of [`Attribute`]s that are defined when the [`Service`] +/// is created. class AttributeSpecifier { public: - auto define(const Attribute::Key& key, const Attribute::Value& value) -> AttributeSpecifier& { - IOX_TODO(); - } - auto attributes() const -> AttributeSet& { - IOX_TODO(); - } + /// Creates a new empty set of [`Attribute`]s + AttributeSpecifier(); + AttributeSpecifier(const AttributeSpecifier&) = delete; + AttributeSpecifier(AttributeSpecifier&&) noexcept; + ~AttributeSpecifier(); + + auto operator=(const AttributeSpecifier&) -> AttributeSpecifier& = delete; + auto operator=(AttributeSpecifier&&) noexcept -> AttributeSpecifier&; + + /// Defines a value for a specific key. A key is allowed to have multiple values. + auto define(const Attribute::Key& key, const Attribute::Value& value) -> AttributeSpecifier&&; + + /// Returns the underlying [`AttributeSetView`] + auto attributes() const -> AttributeSetView; + + private: + template + friend class ServiceBuilderEvent; + template + friend class ServiceBuilderPublishSubscribe; + + void drop(); + + iox2_attribute_specifier_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/attribute_verifier.hpp b/iceoryx2-ffi/cxx/include/iox2/attribute_verifier.hpp index 37036adc4..868c16cc1 100644 --- a/iceoryx2-ffi/cxx/include/iox2/attribute_verifier.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/attribute_verifier.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_ATTRIBUTE_VERIFIER_HPP #define IOX2_ATTRIBUTE_VERIFIER_HPP -#include "iox/assertions_addendum.hpp" #include "iox/expected.hpp" #include "iox/vector.hpp" #include "iox2/attribute.hpp" @@ -21,25 +20,43 @@ #include "iox2/internal/iceoryx2.hpp" namespace iox2 { +/// Represents the set of [`Attribute`]s that are required when the [`Service`] +/// is opened. class AttributeVerifier { public: - AttributeVerifier() = default; - auto require(const Attribute::Key& key, const Attribute::Value& value) -> AttributeVerifier& { - IOX_TODO(); - } - auto require_key(const Attribute::Key& key) -> AttributeVerifier& { - IOX_TODO(); - } - auto attributes() const -> const AttributeSet& { - IOX_TODO(); - } - auto keys() const -> iox::vector { - IOX_TODO(); - } - - auto verify_requirements(const AttributeSet& rhs) const -> iox::expected { - IOX_TODO(); - } + /// Creates a new empty set of [`Attribute`]s + AttributeVerifier(); + AttributeVerifier(const AttributeVerifier&) = delete; + AttributeVerifier(AttributeVerifier&&) noexcept; + ~AttributeVerifier(); + + auto operator=(const AttributeVerifier&) -> AttributeVerifier& = delete; + auto operator=(AttributeVerifier&&) noexcept -> AttributeVerifier&; + + /// Requires a value for a specific key. A key is allowed to have multiple values. + auto require(const Attribute::Key& key, const Attribute::Value& value) -> AttributeVerifier&&; + + /// Requires that a specific key is defined. + auto require_key(const Attribute::Key& key) -> AttributeVerifier&&; + + /// Returns the underlying required [`AttributeSet`] + auto attributes() const -> AttributeSetView; + + /// Returns the underlying required keys + auto keys() const -> iox::vector; + + /// Verifies if the [`AttributeSet`] contains all required keys and key-value pairs. + auto verify_requirements(const AttributeSetView& rhs) const -> iox::expected; + + private: + template + friend class ServiceBuilderEvent; + template + friend class ServiceBuilderPublishSubscribe; + + void drop(); + + iox2_attribute_verifier_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/config.hpp b/iceoryx2-ffi/cxx/include/iox2/config.hpp index f9ce9c47b..832b517c7 100644 --- a/iceoryx2-ffi/cxx/include/iox2/config.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/config.hpp @@ -63,7 +63,7 @@ class Node { friend class Global; explicit Node(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; /// All configurable settings of a [`Service`]. @@ -103,7 +103,7 @@ class Service { friend class Global; explicit Service(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; /// The global settings @@ -128,7 +128,7 @@ class Global { friend class ::iox2::Config; explicit Global(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; /// Default settings for the publish-subscribe messaging pattern. These settings are used unless @@ -188,7 +188,7 @@ class PublishSubscribe { friend class Defaults; explicit PublishSubscribe(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; /// Default settings for the event messaging pattern. These settings are used unless @@ -217,7 +217,7 @@ class Event { friend class Defaults; explicit Event(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; /// Default settings. These values are used when the user in the code does not specify anything @@ -233,7 +233,7 @@ class Defaults { friend class ::iox2::Config; explicit Defaults(iox2_config_h* config); - iox2_config_h* m_config; + iox2_config_h* m_config = nullptr; }; } // namespace config @@ -258,7 +258,7 @@ class ConfigView { friend class Service; explicit ConfigView(iox2_config_ptr ptr); - iox2_config_ptr m_ptr; + iox2_config_ptr m_ptr = nullptr; }; /// Represents the configuration that iceoryx2 will utilize. It is divided into two sections: diff --git a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp index a002182a4..3c33ee94b 100644 --- a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp @@ -53,8 +53,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::SemanticStringError value) noexcept -> iox2_semantic_string_error_e { +constexpr auto +from(const iox2::SemanticStringError value) noexcept + -> iox2_semantic_string_error_e { switch (value) { case iox2::SemanticStringError::InvalidContent: return iox2_semantic_string_error_e_INVALID_CONTENT; @@ -85,8 +86,8 @@ constexpr auto from(const int value) noexcept -> iox2::S } template <> -constexpr auto -from(const iox2::ServiceType value) noexcept -> iox2_service_type_e { +constexpr auto from(const iox2::ServiceType value) noexcept + -> iox2_service_type_e { switch (value) { case iox2::ServiceType::Ipc: return iox2_service_type_e_IPC; @@ -111,8 +112,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::NodeCreationFailure value) noexcept -> iox2_node_creation_failure_e { +constexpr auto +from(const iox2::NodeCreationFailure value) noexcept + -> iox2_node_creation_failure_e { switch (value) { case iox2::NodeCreationFailure::InsufficientPermissions: return iox2_node_creation_failure_e_INSUFFICIENT_PERMISSIONS; @@ -143,8 +145,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::CallbackProgression value) noexcept -> iox2_callback_progression_e { +constexpr auto +from(const iox2::CallbackProgression value) noexcept + -> iox2_callback_progression_e { switch (value) { case iox2::CallbackProgression::Continue: return iox2_callback_progression_e_CONTINUE; @@ -258,8 +261,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::ServiceDetailsError value) noexcept -> iox2_service_details_error_e { +constexpr auto +from(const iox2::ServiceDetailsError value) noexcept + -> iox2_service_details_error_e { switch (value) { case iox2::ServiceDetailsError::FailedToOpenStaticServiceInfo: return iox2_service_details_error_e_FAILED_TO_OPEN_STATIC_SERVICE_INFO; @@ -337,8 +341,9 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto from( - const iox2::EventOpenOrCreateError value) noexcept -> iox2_event_open_or_create_error_e { +constexpr auto +from(const iox2::EventOpenOrCreateError value) noexcept + -> iox2_event_open_or_create_error_e { switch (value) { case iox2::EventOpenOrCreateError::OpenDoesNotExist: return iox2_event_open_or_create_error_e_O_DOES_NOT_EXIST; @@ -489,8 +494,9 @@ constexpr auto from(const int value) noexcept -> io } template <> -constexpr auto from( - const iox2::EventCreateError value) noexcept -> iox2_event_open_or_create_error_e { +constexpr auto +from(const iox2::EventCreateError value) noexcept + -> iox2_event_open_or_create_error_e { switch (value) { case iox2::EventCreateError::InsufficientPermissions: return iox2_event_open_or_create_error_e_C_INSUFFICIENT_PERMISSIONS; @@ -664,15 +670,14 @@ constexpr auto from -inline auto -from(const iox2::PublishSubscribeOpenError value) noexcept -> const - char* { +inline auto from(const iox2::PublishSubscribeOpenError value) noexcept + -> const char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } template <> -constexpr auto -from(const int value) noexcept -> iox2::PublishSubscribeCreateError { +constexpr auto from(const int value) noexcept + -> iox2::PublishSubscribeCreateError { const auto error = static_cast(value); switch (error) { case iox2_pub_sub_open_or_create_error_e_C_SERVICE_IN_CORRUPTED_STATE: @@ -718,9 +723,8 @@ constexpr auto from -inline auto -from(const iox2::PublishSubscribeCreateError value) noexcept -> const - char* { +inline auto from(const iox2::PublishSubscribeCreateError value) noexcept + -> const char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } @@ -784,8 +788,9 @@ constexpr auto from -inline auto from( - const iox2::PublishSubscribeOpenOrCreateError value) noexcept -> const char* { +inline auto +from(const iox2::PublishSubscribeOpenOrCreateError value) noexcept + -> const char* { return iox2_pub_sub_open_or_create_error_string(iox::into(value)); } @@ -801,8 +806,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::NotifierCreateError value) noexcept -> iox2_notifier_create_error_e { +constexpr auto +from(const iox2::NotifierCreateError value) noexcept + -> iox2_notifier_create_error_e { switch (value) { case iox2::NotifierCreateError::ExceedsMaxSupportedNotifiers: return iox2_notifier_create_error_e_EXCEEDS_MAX_SUPPORTED_NOTIFIERS; @@ -831,8 +837,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::ListenerCreateError value) noexcept -> iox2_listener_create_error_e { +constexpr auto +from(const iox2::ListenerCreateError value) noexcept + -> iox2_listener_create_error_e { switch (value) { case iox2::ListenerCreateError::ExceedsMaxSupportedListeners: return iox2_listener_create_error_e_EXCEEDS_MAX_SUPPORTED_LISTENERS; @@ -861,8 +868,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::NotifierNotifyError value) noexcept -> iox2_notifier_notify_error_e { +constexpr auto +from(const iox2::NotifierNotifyError value) noexcept + -> iox2_notifier_notify_error_e { switch (value) { case iox2::NotifierNotifyError::EventIdOutOfBounds: return iox2_notifier_notify_error_e_EVENT_ID_OUT_OF_BOUNDS; @@ -926,8 +934,9 @@ constexpr auto from(const int value) noexcept - } template <> -constexpr auto from( - const iox2::PublisherCreateError value) noexcept -> iox2_publisher_create_error_e { +constexpr auto +from(const iox2::PublisherCreateError value) noexcept + -> iox2_publisher_create_error_e { switch (value) { case iox2::PublisherCreateError::ExceedsMaxSupportedPublishers: return iox2_publisher_create_error_e_EXCEEDS_MAX_SUPPORTED_PUBLISHERS; @@ -958,8 +967,9 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto from( - const iox2::SubscriberCreateError value) noexcept -> iox2_subscriber_create_error_e { +constexpr auto +from(const iox2::SubscriberCreateError value) noexcept + -> iox2_subscriber_create_error_e { switch (value) { case iox2::SubscriberCreateError::BufferSizeExceedsMaxSupportedBufferSizeOfService: return iox2_subscriber_create_error_e_BUFFER_SIZE_EXCEEDS_MAX_SUPPORTED_BUFFER_SIZE_OF_SERVICE; @@ -1000,8 +1010,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::PublisherSendError value) noexcept -> iox2_publisher_send_error_e { +constexpr auto +from(const iox2::PublisherSendError value) noexcept + -> iox2_publisher_send_error_e { switch (value) { case iox2::PublisherSendError::ConnectionBrokenSincePublisherNoLongerExists: return iox2_publisher_send_error_e_CONNECTION_BROKEN_SINCE_PUBLISHER_NO_LONGER_EXISTS; @@ -1043,8 +1054,9 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto from( - const iox2::SubscriberReceiveError value) noexcept -> iox2_subscriber_receive_error_e { +constexpr auto +from(const iox2::SubscriberReceiveError value) noexcept + -> iox2_subscriber_receive_error_e { switch (value) { case iox2::SubscriberReceiveError::FailedToEstablishConnection: return iox2_subscriber_receive_error_e_FAILED_TO_ESTABLISH_CONNECTION; @@ -1081,8 +1093,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::PublisherLoanError value) noexcept -> iox2_publisher_loan_error_e { +constexpr auto +from(const iox2::PublisherLoanError value) noexcept + -> iox2_publisher_loan_error_e { switch (value) { case iox2::PublisherLoanError::ExceedsMaxLoanedSamples: return iox2_publisher_loan_error_e_EXCEEDS_MAX_LOANED_SAMPLES; @@ -1234,8 +1247,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::ConfigCreationError value) noexcept -> iox2_config_creation_error_e { +constexpr auto +from(const iox2::ConfigCreationError value) noexcept + -> iox2_config_creation_error_e { switch (value) { case iox2::ConfigCreationError::FailedToOpenConfigFile: return iox2_config_creation_error_e_FAILED_TO_OPEN_CONFIG_FILE; @@ -1306,8 +1320,9 @@ constexpr auto from(const int value) noexcept -> } template <> -constexpr auto from( - const iox2::WaitSetCreateError value) noexcept -> iox2_waitset_create_error_e { +constexpr auto +from(const iox2::WaitSetCreateError value) noexcept + -> iox2_waitset_create_error_e { switch (value) { case iox2::WaitSetCreateError::InternalError: return iox2_waitset_create_error_e_INTERNAL_ERROR; @@ -1371,8 +1386,9 @@ constexpr auto from(const int value) noexcept } template <> -constexpr auto from( - const iox2::WaitSetAttachmentError value) noexcept -> iox2_waitset_attachment_error_e { +constexpr auto +from(const iox2::WaitSetAttachmentError value) noexcept + -> iox2_waitset_attachment_error_e { switch (value) { case iox2::WaitSetAttachmentError::AlreadyAttached: return iox2_waitset_attachment_error_e_ALREADY_ATTACHED; @@ -1435,8 +1451,9 @@ inline auto from(const iox2::WaitSetRunError } template <> -constexpr auto from( - const iox2::SignalHandlingMode value) noexcept -> iox2_signal_handling_mode_e { +constexpr auto +from(const iox2::SignalHandlingMode value) noexcept + -> iox2_signal_handling_mode_e { switch (value) { case iox2::SignalHandlingMode::Disabled: return iox2_signal_handling_mode_e_DISABLED; diff --git a/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp b/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp index a548ea9a8..dcb0d53e2 100644 --- a/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/header_publish_subscribe.hpp @@ -42,7 +42,7 @@ class HeaderPublishSubscribe { explicit HeaderPublishSubscribe(iox2_publish_subscribe_header_h handle); void drop(); - iox2_publish_subscribe_header_h m_handle; + iox2_publish_subscribe_header_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/listener.hpp b/iceoryx2-ffi/cxx/include/iox2/listener.hpp index 2f85f7e0e..1324daca1 100644 --- a/iceoryx2-ffi/cxx/include/iox2/listener.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/listener.hpp @@ -55,8 +55,8 @@ class Listener : public FileDescriptorBased { /// currently available [`EventId`]s in buffer. /// For every received [`EventId`] the provided callback is called with the [`EventId`] as /// input argument. - auto timed_wait_all(const iox::function& callback, - const iox::units::Duration& timeout) -> iox::expected; + auto timed_wait_all(const iox::function& callback, const iox::units::Duration& timeout) + -> iox::expected; /// Blocking wait for new [`EventId`]s. Collects either /// all [`EventId`]s that were received @@ -75,8 +75,8 @@ class Listener : public FileDescriptorBased { /// has passed. If no [`EventId`] was notified it returns [`None`]. /// On error it returns [`ListenerWaitError`] is returned which describes the error /// in detail. - auto - timed_wait_one(const iox::units::Duration& timeout) -> iox::expected, ListenerWaitError>; + auto timed_wait_one(const iox::units::Duration& timeout) + -> iox::expected, ListenerWaitError>; /// Blocking wait for a new [`EventId`]. /// Sporadic wakeups can occur and if no [`EventId`] was notified it returns [`None`]. @@ -93,7 +93,7 @@ class Listener : public FileDescriptorBased { explicit Listener(iox2_listener_h handle); void drop(); - iox2_listener_h m_handle; + iox2_listener_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/node.hpp b/iceoryx2-ffi/cxx/include/iox2/node.hpp index 70a59ec5b..e8d8ecb6d 100644 --- a/iceoryx2-ffi/cxx/include/iox2/node.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/node.hpp @@ -74,7 +74,7 @@ class Node { friend class NodeBuilder; - iox2_node_h m_handle; + iox2_node_h m_handle = nullptr; }; /// Creates a new [`Node`]. @@ -106,7 +106,7 @@ class NodeBuilder { auto create() const&& -> iox::expected, NodeCreationFailure>; private: - iox2_node_builder_h m_handle; + iox2_node_builder_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/node_name.hpp b/iceoryx2-ffi/cxx/include/iox2/node_name.hpp index 263a07043..ceb1a34b3 100644 --- a/iceoryx2-ffi/cxx/include/iox2/node_name.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/node_name.hpp @@ -41,14 +41,12 @@ class NodeNameView { friend class Node; friend class NodeName; template - friend auto list_callback(iox2_node_state_e, - iox2_node_id_ptr, - iox2_node_name_ptr, - iox2_config_ptr, - iox2_callback_context) -> iox2_callback_progression_e; + friend auto + list_callback(iox2_node_state_e, iox2_node_id_ptr, iox2_node_name_ptr, iox2_config_ptr, iox2_callback_context) + -> iox2_callback_progression_e; explicit NodeNameView(iox2_node_name_ptr ptr); - iox2_node_name_ptr m_ptr; + iox2_node_name_ptr m_ptr = nullptr; }; /// Represent the name for a [`Node`]. @@ -79,7 +77,7 @@ class NodeName { void drop() noexcept; static auto create_impl(const char* value, size_t value_len) -> iox::expected; - iox2_node_name_h m_handle; + iox2_node_name_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/notifier.hpp b/iceoryx2-ffi/cxx/include/iox2/notifier.hpp index 8d376c7d1..abe8dc794 100644 --- a/iceoryx2-ffi/cxx/include/iox2/notifier.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/notifier.hpp @@ -58,7 +58,7 @@ class Notifier { explicit Notifier(iox2_notifier_h handle); void drop(); - iox2_notifier_h m_handle; + iox2_notifier_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_event.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_event.hpp index 88dd1312e..56f24987f 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_event.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_event.hpp @@ -47,7 +47,7 @@ class PortFactoryEvent { auto service_id() const -> const ServiceId&; /// Returns the attributes defined in the [`Service`] - auto attributes() const -> const AttributeSet&; + auto attributes() const -> AttributeSetView; /// Returns the StaticConfig of the [`Service`]. /// Contains all settings that never change during the lifetime of the service. @@ -77,7 +77,7 @@ class PortFactoryEvent { explicit PortFactoryEvent(iox2_port_factory_event_h handle); void drop() noexcept; - iox2_port_factory_event_h m_handle; + iox2_port_factory_event_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_listener.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_listener.hpp index d74502b41..6086edcdf 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_listener.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_listener.hpp @@ -41,7 +41,7 @@ class PortFactoryListener { explicit PortFactoryListener(iox2_port_factory_listener_builder_h handle); - iox2_port_factory_listener_builder_h m_handle; + iox2_port_factory_listener_builder_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_notifier.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_notifier.hpp index 356c58bd7..959ee5ae5 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_notifier.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_notifier.hpp @@ -47,7 +47,7 @@ class PortFactoryNotifier { explicit PortFactoryNotifier(iox2_port_factory_notifier_builder_h handle); - iox2_port_factory_notifier_builder_h m_handle; + iox2_port_factory_notifier_builder_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_publish_subscribe.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_publish_subscribe.hpp index f690beb19..2c51affd0 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_publish_subscribe.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_publish_subscribe.hpp @@ -16,7 +16,6 @@ #include "iox/assertions_addendum.hpp" #include "iox/expected.hpp" #include "iox/function.hpp" -#include "iox/string.hpp" #include "iox2/attribute_set.hpp" #include "iox2/callback_progression.hpp" #include "iox2/dynamic_config_publish_subscribe.hpp" @@ -51,7 +50,7 @@ class PortFactoryPublishSubscribe { auto service_id() const -> const ServiceId&; /// Returns the attributes defined in the [`Service`] - auto attributes() const -> const AttributeSet&; + auto attributes() const -> AttributeSetView; /// Returns the StaticConfig of the [`Service`]. /// Contains all settings that never change during the lifetime of the service. @@ -81,7 +80,7 @@ class PortFactoryPublishSubscribe { explicit PortFactoryPublishSubscribe(iox2_port_factory_pub_sub_h handle); void drop(); - iox2_port_factory_pub_sub_h m_handle { nullptr }; + iox2_port_factory_pub_sub_h m_handle = nullptr; }; template @@ -132,8 +131,8 @@ inline auto PortFactoryPublishSubscribe::service_id() co } template -inline auto PortFactoryPublishSubscribe::attributes() const -> const AttributeSet& { - IOX_TODO(); +inline auto PortFactoryPublishSubscribe::attributes() const -> AttributeSetView { + return AttributeSetView(iox2_port_factory_pub_sub_attributes(&m_handle)); } template @@ -145,8 +144,8 @@ inline auto PortFactoryPublishSubscribe::static_config() } template -inline auto -PortFactoryPublishSubscribe::dynamic_config() const -> const DynamicConfigPublishSubscribe& { +inline auto PortFactoryPublishSubscribe::dynamic_config() const + -> const DynamicConfigPublishSubscribe& { IOX_TODO(); } diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp index 95e557f35..951eace51 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp @@ -63,7 +63,7 @@ class PortFactoryPublisher { explicit PortFactoryPublisher(iox2_port_factory_publisher_builder_h handle); - iox2_port_factory_publisher_builder_h m_handle; + iox2_port_factory_publisher_builder_h m_handle = nullptr; iox::optional m_max_slice_len; iox::optional m_allocation_strategy; }; diff --git a/iceoryx2-ffi/cxx/include/iox2/port_factory_subscriber.hpp b/iceoryx2-ffi/cxx/include/iox2/port_factory_subscriber.hpp index 9b6b207fd..7a694c9bb 100644 --- a/iceoryx2-ffi/cxx/include/iox2/port_factory_subscriber.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/port_factory_subscriber.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_PORTFACTORY_SUBSCRIBER_HPP #define IOX2_PORTFACTORY_SUBSCRIBER_HPP -#include "iox/assertions_addendum.hpp" #include "iox/builder_addendum.hpp" #include "iox/expected.hpp" #include "iox2/internal/iceoryx2.hpp" @@ -47,7 +46,7 @@ class PortFactorySubscriber { explicit PortFactorySubscriber(iox2_port_factory_subscriber_builder_h handle); - iox2_port_factory_subscriber_builder_h m_handle; + iox2_port_factory_subscriber_builder_h m_handle = nullptr; }; template diff --git a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp index f75414577..c3898e86e 100644 --- a/iceoryx2-ffi/cxx/include/iox2/publisher.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/publisher.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_PUBLISHER_HPP #define IOX2_PUBLISHER_HPP -#include "iox/assertions_addendum.hpp" #include "iox/expected.hpp" #include "iox/slice.hpp" #include "iox2/connection_failure.hpp" @@ -109,7 +108,7 @@ class Publisher { explicit Publisher(iox2_publisher_h handle); void drop(); - iox2_publisher_h m_handle { nullptr }; + iox2_publisher_h m_handle = nullptr; }; template @@ -170,7 +169,7 @@ template template inline auto Publisher::send_copy(const Payload& payload) const -> iox::expected { - static_assert(std::is_trivially_copyable::value); + static_assert(std::is_trivially_copyable_v); size_t number_of_recipients = 0; auto result = @@ -218,8 +217,8 @@ inline auto Publisher::loan_uninit() template template -inline auto -Publisher::loan() -> iox::expected, PublisherLoanError> { +inline auto Publisher::loan() + -> iox::expected, PublisherLoanError> { auto sample = loan_uninit(); if (sample.has_error()) { diff --git a/iceoryx2-ffi/cxx/include/iox2/sample.hpp b/iceoryx2-ffi/cxx/include/iox2/sample.hpp index 4a1f8e5f7..2ea831f08 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_SAMPLE_HPP #define IOX2_SAMPLE_HPP -#include "iox/assertions_addendum.hpp" #include "iox/slice.hpp" #include "iox2/header_publish_subscribe.hpp" #include "iox2/internal/iceoryx2.hpp" @@ -80,7 +79,7 @@ class Sample { void drop(); iox2_sample_t m_sample; - iox2_sample_h m_handle { nullptr }; + iox2_sample_h m_handle = nullptr; }; template diff --git a/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp b/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp index 75235727e..611e9a857 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_SAMPLE_MUT_HPP #define IOX2_SAMPLE_MUT_HPP -#include "iox/assertions.hpp" #include "iox/expected.hpp" #include "iox/slice.hpp" #include "iox2/header_publish_subscribe.hpp" @@ -109,7 +108,7 @@ class SampleMut { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) will not be accessed directly but only via m_handle and will be set together with m_handle iox2_sample_mut_t m_sample; - iox2_sample_mut_h m_handle { nullptr }; + iox2_sample_mut_h m_handle = nullptr; }; template diff --git a/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp b/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp index b90dc6489..004df459f 100644 --- a/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/sample_mut_uninit.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_SAMPLE_MUT_UNINIT_HPP #define IOX2_SAMPLE_MUT_UNINIT_HPP -#include "iox/assertions_addendum.hpp" #include "iox/function.hpp" #include "iox/slice.hpp" #include "iox2/header_publish_subscribe.hpp" diff --git a/iceoryx2-ffi/cxx/include/iox2/service.hpp b/iceoryx2-ffi/cxx/include/iox2/service.hpp index a7f82459d..39d69a1c4 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service.hpp @@ -33,9 +33,8 @@ template class Service { public: /// Checks if a service under a given [`ConfigView`] does exist. - static auto does_exist(const ServiceName& service_name, - ConfigView config, - MessagingPattern messaging_pattern) -> iox::expected; + static auto does_exist(const ServiceName& service_name, ConfigView config, MessagingPattern messaging_pattern) + -> iox::expected; /// Acquires the [`ServiceDetails`] of a [`Service`]. static auto details(const ServiceName& service_name, ConfigView config, MessagingPattern messaging_pattern) diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder.hpp index 7deef1fc3..cfb63cde6 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_SERVICE_BUILDER_HPP #define IOX2_SERVICE_BUILDER_HPP -#include "iox/assertions_addendum.hpp" #include "iox2/service_builder_event.hpp" #include "iox2/service_builder_publish_subscribe.hpp" #include "iox2/service_type.hpp" @@ -44,7 +43,7 @@ class ServiceBuilder { friend class Node; ServiceBuilder(iox2_node_h_ref node_handle, iox2_service_name_ptr service_name_ptr); - iox2_service_builder_h m_handle; + iox2_service_builder_h m_handle = nullptr; }; template diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder_event.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder_event.hpp index 7cbfc5de9..dd899e6f9 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder_event.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder_event.hpp @@ -83,7 +83,7 @@ class ServiceBuilderEvent { void set_parameters(); - iox2_service_builder_event_h m_handle; + iox2_service_builder_event_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp index bcbfa00e3..92589bb63 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_builder_publish_subscribe.hpp @@ -13,7 +13,6 @@ #ifndef IOX2_SERVICE_BUILDER_PUBLISH_SUBSCRIBE_HPP #define IOX2_SERVICE_BUILDER_PUBLISH_SUBSCRIBE_HPP -#include "iox/assertions_addendum.hpp" #include "iox/builder_addendum.hpp" #include "iox/expected.hpp" #include "iox2/attribute_specifier.hpp" @@ -85,20 +84,16 @@ class ServiceBuilderPublishSubscribe { /// created. It defines a set of attributes. If the [`Service`] already exists all attribute /// requirements must be satisfied otherwise the open process will fail. If the [`Service`] /// does not exist the required attributes will be defined in the [`Service`]. - auto open_or_create_with_attributes( - const AttributeVerifier& - required_attributes) && -> iox::expected, - PublishSubscribeOpenOrCreateError>; + auto open_or_create_with_attributes(const AttributeVerifier& required_attributes) && -> iox:: + expected, PublishSubscribeOpenOrCreateError>; /// Opens an existing [`Service`]. auto open() && -> iox::expected, PublishSubscribeOpenError>; /// Opens an existing [`Service`] with attribute requirements. If the defined attribute /// requirements are not satisfied the open process will fail. - auto open_with_attributes( - const AttributeVerifier& - required_attributes) && -> iox::expected, - PublishSubscribeOpenError>; + auto open_with_attributes(const AttributeVerifier& required_attributes) && -> iox:: + expected, PublishSubscribeOpenError>; /// Creates a new [`Service`]. auto create() && -> iox::expected, PublishSubscribeCreateError>; @@ -116,7 +111,7 @@ class ServiceBuilderPublishSubscribe { void set_parameters(); - iox2_service_builder_pub_sub_h m_handle; + iox2_service_builder_pub_sub_h m_handle = nullptr; }; template @@ -185,9 +180,8 @@ inline auto ServiceBuilderPublishSubscribe:: } template -inline auto ServiceBuilderPublishSubscribe:: - open_or_create() && -> iox::expected, - PublishSubscribeOpenOrCreateError> { +inline auto ServiceBuilderPublishSubscribe::open_or_create() && -> iox:: + expected, PublishSubscribeOpenOrCreateError> { set_parameters(); iox2_port_factory_pub_sub_h port_factory_handle {}; @@ -201,8 +195,8 @@ inline auto ServiceBuilderPublishSubscribe:: } template -inline auto ServiceBuilderPublishSubscribe:: - open() && -> iox::expected, PublishSubscribeOpenError> { +inline auto ServiceBuilderPublishSubscribe::open() && -> iox:: + expected, PublishSubscribeOpenError> { set_parameters(); iox2_port_factory_pub_sub_h port_factory_handle {}; @@ -216,8 +210,8 @@ inline auto ServiceBuilderPublishSubscribe:: } template -inline auto ServiceBuilderPublishSubscribe:: - create() && -> iox::expected, PublishSubscribeCreateError> { +inline auto ServiceBuilderPublishSubscribe::create() && -> iox:: + expected, PublishSubscribeCreateError> { set_parameters(); iox2_port_factory_pub_sub_h port_factory_handle {}; @@ -236,7 +230,16 @@ inline auto ServiceBuilderPublishSubscribe::open_or_crea required_attributes) && -> iox::expected, PublishSubscribeOpenOrCreateError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_pub_sub_h port_factory_handle {}; + auto result = iox2_service_builder_pub_sub_open_or_create_with_attributes( + m_handle, &required_attributes.m_handle, nullptr, &port_factory_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryPublishSubscribe(port_factory_handle)); + } + + return iox::err(iox::into(result)); } template @@ -245,7 +248,16 @@ inline auto ServiceBuilderPublishSubscribe::open_with_at required_attributes) && -> iox::expected, PublishSubscribeOpenError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_pub_sub_h port_factory_handle {}; + auto result = iox2_service_builder_pub_sub_open_with_attributes( + m_handle, &required_attributes.m_handle, nullptr, &port_factory_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryPublishSubscribe(port_factory_handle)); + } + + return iox::err(iox::into(result)); } template @@ -253,7 +265,16 @@ inline auto ServiceBuilderPublishSubscribe::create_with_ const AttributeSpecifier& attributes) && -> iox::expected, PublishSubscribeCreateError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_pub_sub_h port_factory_handle {}; + auto result = iox2_service_builder_pub_sub_create_with_attributes( + m_handle, &attributes.m_handle, nullptr, &port_factory_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryPublishSubscribe(port_factory_handle)); + } + + return iox::err(iox::into(result)); } } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/service_name.hpp b/iceoryx2-ffi/cxx/include/iox2/service_name.hpp index e537ce6ac..698ad99e3 100644 --- a/iceoryx2-ffi/cxx/include/iox2/service_name.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/service_name.hpp @@ -46,7 +46,7 @@ class ServiceNameView { friend class PortFactoryEvent; explicit ServiceNameView(iox2_service_name_ptr ptr); - iox2_service_name_ptr m_ptr; + iox2_service_name_ptr m_ptr = nullptr; }; /// The name of a [`Service`]. @@ -73,7 +73,7 @@ class ServiceName { static auto create_impl(const char* value, size_t value_len) -> iox::expected; void drop() noexcept; - iox2_service_name_h m_handle; + iox2_service_name_h m_handle = nullptr; }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/include/iox2/static_config.hpp b/iceoryx2-ffi/cxx/include/iox2/static_config.hpp index 9d6db1c1b..50e224d7a 100644 --- a/iceoryx2-ffi/cxx/include/iox2/static_config.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/static_config.hpp @@ -21,7 +21,7 @@ namespace iox2 { class StaticConfig { public: /// Returns the attributes of the [`Service`] - auto attributes() const -> const AttributeSet&; + auto attributes() const -> AttributeSetView; /// Returns the id of the [`Service`] auto id() const -> const char*; diff --git a/iceoryx2-ffi/cxx/include/iox2/subscriber.hpp b/iceoryx2-ffi/cxx/include/iox2/subscriber.hpp index 9d3ab4b48..d0ec4e22c 100644 --- a/iceoryx2-ffi/cxx/include/iox2/subscriber.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/subscriber.hpp @@ -23,7 +23,6 @@ #include "iox2/service_type.hpp" #include "iox2/subscriber_error.hpp" #include "iox2/unique_port_id.hpp" -#include namespace iox2 { /// The receiving endpoint of a publish-subscribe communication. @@ -66,7 +65,7 @@ class Subscriber { explicit Subscriber(iox2_subscriber_h handle); void drop(); - iox2_subscriber_h m_handle { nullptr }; + iox2_subscriber_h m_handle = nullptr; }; template inline Subscriber::Subscriber(iox2_subscriber_h handle) diff --git a/iceoryx2-ffi/cxx/include/iox2/waitset.hpp b/iceoryx2-ffi/cxx/include/iox2/waitset.hpp index 9463f3fd3..f9d1f2c51 100644 --- a/iceoryx2-ffi/cxx/include/iox2/waitset.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/waitset.hpp @@ -219,8 +219,8 @@ class WaitSet { /// /// * The corresponding [`Listener`] must life at least as long as the returned [`WaitSetGuard`]. /// * The [`WaitSetGuard`] must life at least as long as the [`WaitsSet`]. - auto attach_deadline(const Listener& listener, - iox::units::Duration deadline) -> iox::expected, WaitSetAttachmentError>; + auto attach_deadline(const Listener& listener, iox::units::Duration deadline) + -> iox::expected, WaitSetAttachmentError>; /// Attaches a [`FileDescriptorBased`] object as deadline to the [`WaitSet`]. Whenever the event is received or the /// deadline is hit, the user is informed in [`WaitSet::wait_and_process()`]. @@ -232,8 +232,8 @@ class WaitSet { /// /// * The corresponding [`FileDescriptor`] must life at least as long as the returned [`WaitSetGuard`]. /// * The [`WaitSetGuard`] must life at least as long as the [`WaitsSet`]. - auto attach_deadline(const FileDescriptorBased& attachment, - iox::units::Duration deadline) -> iox::expected, WaitSetAttachmentError>; + auto attach_deadline(const FileDescriptorBased& attachment, iox::units::Duration deadline) + -> iox::expected, WaitSetAttachmentError>; /// Attaches a tick event to the [`WaitSet`]. Whenever the timeout is reached the [`WaitSet`] /// informs the user in [`WaitSet::wait_and_process()`]. @@ -251,7 +251,7 @@ class WaitSet { explicit WaitSet(iox2_waitset_h handle); void drop(); - iox2_waitset_h m_handle {}; + iox2_waitset_h m_handle = nullptr; }; /// The builder for the [`WaitSet`]. @@ -275,7 +275,7 @@ class WaitSetBuilder { auto create() const&& -> iox::expected, WaitSetCreateError>; private: - iox2_waitset_builder_h m_handle; + iox2_waitset_builder_h m_handle = nullptr; }; } // namespace iox2 #endif diff --git a/iceoryx2-ffi/cxx/src/attribute.cpp b/iceoryx2-ffi/cxx/src/attribute.cpp new file mode 100644 index 000000000..131cd9c4b --- /dev/null +++ b/iceoryx2-ffi/cxx/src/attribute.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/attribute.hpp" + +namespace iox2 { +auto AttributeView::key() const -> Attribute::Key { + Attribute::Key key; + key.unsafe_raw_access([this](auto* buffer, const auto& info) { + iox2_attribute_key(m_handle, buffer, info.total_size); + return iox2_attribute_key_len(m_handle); + }); + return key; +} + +auto AttributeView::value() const -> Attribute::Value { + Attribute::Value value; + value.unsafe_raw_access([this](auto* buffer, const auto& info) { + iox2_attribute_value(m_handle, buffer, info.total_size); + return iox2_attribute_value_len(m_handle); + }); + return value; +} + +AttributeView::AttributeView(iox2_attribute_h_ref handle) + : m_handle { handle } { +} +} // namespace iox2 + +auto operator<<(std::ostream& stream, const iox2::AttributeView& value) -> std::ostream& { + stream << "Attribute { key = \"" << value.key().c_str() << "\", value = \"" << value.value().c_str() << "\" }"; + return stream; +} diff --git a/iceoryx2-ffi/cxx/src/attribute_set.cpp b/iceoryx2-ffi/cxx/src/attribute_set.cpp new file mode 100644 index 000000000..639410a72 --- /dev/null +++ b/iceoryx2-ffi/cxx/src/attribute_set.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/attribute_set.hpp" +#include "iox2/internal/callback_context.hpp" + +namespace iox2 { +namespace { +auto get_key_values_callback(const char* value, iox2_callback_context context) -> iox2_callback_progression_e { + auto* callback = internal::ctx_cast>(context); + auto typed_value = Attribute::Value(iox::TruncateToCapacity, value); + return iox::into(callback->value()(typed_value)); +} +} // namespace + +AttributeSetView::AttributeSetView(iox2_attribute_set_h_ref handle) + : m_handle { handle } { +} + +auto AttributeSetView::len() const -> uint64_t { + return iox2_attribute_set_len(m_handle); +} + +auto AttributeSetView::at(const uint64_t index) const -> AttributeView { + return AttributeView(iox2_attribute_set_at(m_handle, index)); +} + +void AttributeSetView::get_key_values( + const Attribute::Key& key, const iox::function& callback) const { + auto ctx = internal::ctx(callback); + iox2_attribute_set_get_key_values(m_handle, key.c_str(), get_key_values_callback, static_cast(&ctx)); +} +} // namespace iox2 + +auto operator<<(std::ostream& stream, const iox2::AttributeSetView& value) -> std::ostream& { + stream << "AttributeSet { "; + for (uint64_t idx = 0; idx < value.len(); ++idx) { + auto attribute = value.at(idx); + stream << attribute; + } + return stream; +} diff --git a/iceoryx2-ffi/cxx/src/attribute_specifier.cpp b/iceoryx2-ffi/cxx/src/attribute_specifier.cpp new file mode 100644 index 000000000..ff1e97b5a --- /dev/null +++ b/iceoryx2-ffi/cxx/src/attribute_specifier.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/attribute_specifier.hpp" + +namespace iox2 { +AttributeSpecifier::AttributeSpecifier() { + iox2_attribute_specifier_new(nullptr, &m_handle); +} + +AttributeSpecifier::AttributeSpecifier(AttributeSpecifier&& rhs) noexcept + : m_handle { std::move(rhs.m_handle) } { + rhs.m_handle = nullptr; +} + +AttributeSpecifier::~AttributeSpecifier() { + drop(); +} + +auto AttributeSpecifier::operator=(AttributeSpecifier&& rhs) noexcept -> AttributeSpecifier& { + if (this != &rhs) { + drop(); + m_handle = std::move(rhs.m_handle); + rhs.m_handle = nullptr; + } + + return *this; +} + +auto AttributeSpecifier::define(const Attribute::Key& key, const Attribute::Value& value) -> AttributeSpecifier&& { + iox2_attribute_specifier_define(&m_handle, key.c_str(), value.c_str()); + return std::move(*this); +} + +auto AttributeSpecifier::attributes() const -> AttributeSetView { + return AttributeSetView(iox2_attribute_specifier_attributes(&m_handle)); +} + +void AttributeSpecifier::drop() { + if (m_handle != nullptr) { + iox2_attribute_specifier_drop(m_handle); + m_handle = nullptr; + } +} +} // namespace iox2 diff --git a/iceoryx2-ffi/cxx/src/attribute_verifier.cpp b/iceoryx2-ffi/cxx/src/attribute_verifier.cpp new file mode 100644 index 000000000..23fd92ec5 --- /dev/null +++ b/iceoryx2-ffi/cxx/src/attribute_verifier.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/attribute_verifier.hpp" + +namespace iox2 { +AttributeVerifier::AttributeVerifier() { + iox2_attribute_verifier_new(nullptr, &m_handle); +} + +AttributeVerifier::AttributeVerifier(AttributeVerifier&& rhs) noexcept + : m_handle { std::move(rhs.m_handle) } { + rhs.m_handle = nullptr; +} + +void AttributeVerifier::drop() { + if (m_handle != nullptr) { + iox2_attribute_verifier_drop(m_handle); + m_handle = nullptr; + } +} + +AttributeVerifier::~AttributeVerifier() { + drop(); +} + +auto AttributeVerifier::operator=(AttributeVerifier&& rhs) noexcept -> AttributeVerifier& { + if (this != &rhs) { + drop(); + m_handle = std::move(rhs.m_handle); + rhs.m_handle = nullptr; + } + + return *this; +} + +auto AttributeVerifier::require(const Attribute::Key& key, const Attribute::Value& value) -> AttributeVerifier&& { + iox2_attribute_verifier_require(&m_handle, key.c_str(), value.c_str()); + return std::move(*this); +} + +auto AttributeVerifier::require_key(const Attribute::Key& key) -> AttributeVerifier&& { + iox2_attribute_verifier_require_key(&m_handle, key.c_str()); + return std::move(*this); +} + +auto AttributeVerifier::attributes() const -> AttributeSetView { + return AttributeSetView(iox2_attribute_verifier_attributes(&m_handle)); +} + +auto AttributeVerifier::keys() const -> iox::vector { + auto number_of_keys = iox2_attribute_verifier_number_of_keys(&m_handle); + iox::vector attributes; + for (uint64_t i = 0; i < number_of_keys; ++i) { + // NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) used as an uninitialized buffer + char buffer[Attribute::Key::capacity()]; + iox2_attribute_verifier_key(&m_handle, i, &buffer[0], Attribute::Key::capacity()); + attributes.push_back(Attribute::Key(iox::TruncateToCapacity, &buffer[0])); + } + + return attributes; +} + +auto AttributeVerifier::verify_requirements(const AttributeSetView& rhs) const -> iox::expected { + // NOLINTNEXTLINE(hicpp-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) used as an uninitialized buffer + char buffer[Attribute::Key::capacity()]; + if (iox2_attribute_verifier_verify_requirements(&m_handle, rhs.m_handle, &buffer[0], Attribute::Key::capacity())) { + return iox::ok(); + } + + return iox::err(Attribute::Key(iox::TruncateToCapacity, &buffer[0])); +} + + +} // namespace iox2 diff --git a/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp b/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp index 3ac5932ec..6090429e5 100644 --- a/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp +++ b/iceoryx2-ffi/cxx/src/header_publish_subscribe.cpp @@ -24,8 +24,7 @@ void HeaderPublishSubscribe::drop() { } } -HeaderPublishSubscribe::HeaderPublishSubscribe(HeaderPublishSubscribe&& rhs) noexcept - : m_handle { nullptr } { +HeaderPublishSubscribe::HeaderPublishSubscribe(HeaderPublishSubscribe&& rhs) noexcept { *this = std::move(rhs); } diff --git a/iceoryx2-ffi/cxx/src/listener.cpp b/iceoryx2-ffi/cxx/src/listener.cpp index 7bc3943d3..21288b0d8 100644 --- a/iceoryx2-ffi/cxx/src/listener.cpp +++ b/iceoryx2-ffi/cxx/src/listener.cpp @@ -20,8 +20,7 @@ Listener::Listener(iox2_listener_h handle) } template -Listener::Listener(Listener&& rhs) noexcept - : m_handle { nullptr } { +Listener::Listener(Listener&& rhs) noexcept { *this = std::move(rhs); } @@ -80,8 +79,8 @@ auto Listener::try_wait_all(const iox::function& callback) -> } template -auto Listener::timed_wait_all(const iox::function& callback, - const iox::units::Duration& timeout) -> iox::expected { +auto Listener::timed_wait_all(const iox::function& callback, const iox::units::Duration& timeout) + -> iox::expected { auto ctx = internal::ctx(callback); auto timeout_timespec = timeout.timespec(); diff --git a/iceoryx2-ffi/cxx/src/node_name.cpp b/iceoryx2-ffi/cxx/src/node_name.cpp index 47f2d0da7..c5a88c830 100644 --- a/iceoryx2-ffi/cxx/src/node_name.cpp +++ b/iceoryx2-ffi/cxx/src/node_name.cpp @@ -12,8 +12,6 @@ #include "iox2/node_name.hpp" #include "iox/assertions.hpp" -#include "iox/assertions_addendum.hpp" -#include "iox/into.hpp" #include @@ -42,8 +40,7 @@ NodeName::~NodeName() { drop(); } -NodeName::NodeName(NodeName&& rhs) noexcept - : m_handle { nullptr } { +NodeName::NodeName(NodeName&& rhs) noexcept { *this = std::move(rhs); } @@ -57,8 +54,7 @@ auto NodeName::operator=(NodeName&& rhs) noexcept -> NodeName& { return *this; } -NodeName::NodeName(const NodeName& rhs) - : m_handle { nullptr } { +NodeName::NodeName(const NodeName& rhs) { *this = rhs; } diff --git a/iceoryx2-ffi/cxx/src/notifier.cpp b/iceoryx2-ffi/cxx/src/notifier.cpp index 38ae7f259..1a212c4f0 100644 --- a/iceoryx2-ffi/cxx/src/notifier.cpp +++ b/iceoryx2-ffi/cxx/src/notifier.cpp @@ -19,8 +19,7 @@ Notifier::Notifier(iox2_notifier_h handle) } template -Notifier::Notifier(Notifier&& rhs) noexcept - : m_handle { nullptr } { +Notifier::Notifier(Notifier&& rhs) noexcept { *this = std::move(rhs); } diff --git a/iceoryx2-ffi/cxx/src/port_factory_event.cpp b/iceoryx2-ffi/cxx/src/port_factory_event.cpp index de2b47c1c..43c9cb1f5 100644 --- a/iceoryx2-ffi/cxx/src/port_factory_event.cpp +++ b/iceoryx2-ffi/cxx/src/port_factory_event.cpp @@ -26,8 +26,7 @@ PortFactoryEvent::~PortFactoryEvent() { } template -PortFactoryEvent::PortFactoryEvent(PortFactoryEvent&& rhs) noexcept - : m_handle { nullptr } { +PortFactoryEvent::PortFactoryEvent(PortFactoryEvent&& rhs) noexcept { *this = std::move(rhs); } @@ -62,8 +61,8 @@ auto PortFactoryEvent::service_id() const -> const ServiceId& { } template -auto PortFactoryEvent::attributes() const -> const AttributeSet& { - IOX_TODO(); +auto PortFactoryEvent::attributes() const -> AttributeSetView { + return AttributeSetView(iox2_port_factory_event_attributes(&m_handle)); } template diff --git a/iceoryx2-ffi/cxx/src/service_builder_event.cpp b/iceoryx2-ffi/cxx/src/service_builder_event.cpp index 89f7b19df..a77e6bcf4 100644 --- a/iceoryx2-ffi/cxx/src/service_builder_event.cpp +++ b/iceoryx2-ffi/cxx/src/service_builder_event.cpp @@ -72,21 +72,48 @@ template auto ServiceBuilderEvent::open_or_create_with_attributes( const AttributeVerifier& required_attributes) && -> iox::expected, EventOpenOrCreateError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_event_h event_handle {}; + auto result = iox2_service_builder_event_open_or_create_with_attributes( + m_handle, &required_attributes.m_handle, nullptr, &event_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryEvent(event_handle)); + } + + return iox::err(iox::into(result)); } template auto ServiceBuilderEvent::open_with_attributes( const AttributeVerifier& required_attributes) && -> iox::expected, EventOpenError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_event_h event_handle {}; + auto result = iox2_service_builder_event_open_with_attributes( + m_handle, &required_attributes.m_handle, nullptr, &event_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryEvent(event_handle)); + } + + return iox::err(iox::into(result)); } template auto ServiceBuilderEvent::create_with_attributes( const AttributeSpecifier& attributes) && -> iox::expected, EventCreateError> { set_parameters(); - IOX_TODO(); + + iox2_port_factory_event_h event_handle {}; + auto result = + iox2_service_builder_event_create_with_attributes(m_handle, &attributes.m_handle, nullptr, &event_handle); + + if (result == IOX2_OK) { + return iox::ok(PortFactoryEvent(event_handle)); + } + + return iox::err(iox::into(result)); } template class ServiceBuilderEvent; diff --git a/iceoryx2-ffi/cxx/src/service_name.cpp b/iceoryx2-ffi/cxx/src/service_name.cpp index e3f8fc439..1cd56726b 100644 --- a/iceoryx2-ffi/cxx/src/service_name.cpp +++ b/iceoryx2-ffi/cxx/src/service_name.cpp @@ -12,7 +12,6 @@ #include "iox2/service_name.hpp" #include "iox/assertions.hpp" -#include "iox/into.hpp" #include @@ -41,8 +40,7 @@ ServiceName::~ServiceName() { drop(); } -ServiceName::ServiceName(ServiceName&& rhs) noexcept - : m_handle { nullptr } { +ServiceName::ServiceName(ServiceName&& rhs) noexcept { *this = std::move(rhs); } @@ -56,8 +54,7 @@ auto ServiceName::operator=(ServiceName&& rhs) noexcept -> ServiceName& { return *this; } -ServiceName::ServiceName(const ServiceName& rhs) - : m_handle { nullptr } { +ServiceName::ServiceName(const ServiceName& rhs) { *this = rhs; } @@ -86,8 +83,8 @@ auto ServiceName::create(const char* value) -> iox::expected iox::expected { +auto ServiceName::create_impl(const char* value, const size_t value_len) + -> iox::expected { iox2_service_name_h handle {}; if (value_len > IOX2_SERVICE_NAME_LENGTH) { return iox::err(SemanticStringError::ExceedsMaximumLength); diff --git a/iceoryx2-ffi/cxx/src/static_config.cpp b/iceoryx2-ffi/cxx/src/static_config.cpp index ebefb57bb..19b82137d 100644 --- a/iceoryx2-ffi/cxx/src/static_config.cpp +++ b/iceoryx2-ffi/cxx/src/static_config.cpp @@ -11,6 +11,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT #include "iox2/static_config.hpp" +#include "iox/assertions_addendum.hpp" #include "iox/into.hpp" namespace iox2 { @@ -18,7 +19,7 @@ StaticConfig::StaticConfig(iox2_static_config_t value) : m_value { value } { } -auto StaticConfig::attributes() const -> const AttributeSet& { +auto StaticConfig::attributes() const -> AttributeSetView { IOX_TODO(); } diff --git a/iceoryx2-ffi/cxx/src/waitset.cpp b/iceoryx2-ffi/cxx/src/waitset.cpp index d933c2b39..a195c3650 100644 --- a/iceoryx2-ffi/cxx/src/waitset.cpp +++ b/iceoryx2-ffi/cxx/src/waitset.cpp @@ -12,7 +12,6 @@ #include "iox2/waitset.hpp" #include "iox/into.hpp" -#include "iox2/enum_translation.hpp" #include "iox2/internal/callback_context.hpp" namespace iox2 { @@ -237,7 +236,7 @@ auto WaitSet::attach_interval(const iox::units::Duration deadline) auto result = iox2_waitset_attach_interval(&m_handle, deadline.toSeconds(), deadline.toNanoseconds() - - deadline.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC, + - (deadline.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC), nullptr, &guard_handle); @@ -256,7 +255,7 @@ auto WaitSet::attach_deadline(const FileDescriptorBased& attachment, const io attachment.file_descriptor().m_handle, deadline.toSeconds(), deadline.toNanoseconds() - - deadline.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC, + - (deadline.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC), nullptr, &guard_handle); @@ -329,12 +328,12 @@ auto WaitSet::wait_and_process_once(const iox::function auto WaitSet::wait_and_process_once_with_timeout( - const iox::function)>& fn_call, - const iox::units::Duration timeout) -> iox::expected { + const iox::function)>& fn_call, const iox::units::Duration timeout) + -> iox::expected { iox2_waitset_run_result_e run_result = iox2_waitset_run_result_e_STOP_REQUEST; auto ctx = internal::ctx(fn_call); auto timeout_secs = timeout.toSeconds(); - auto timeout_nsecs = timeout.toNanoseconds() - timeout.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC; + auto timeout_nsecs = timeout.toNanoseconds() - (timeout.toSeconds() * iox::units::Duration::NANOSECS_PER_SEC); auto result = iox2_waitset_wait_and_process_once_with_timeout( &m_handle, run_callback, static_cast(&ctx), timeout_secs, timeout_nsecs, &run_result); diff --git a/iceoryx2-ffi/cxx/tests/src/attribute_tests.cpp b/iceoryx2-ffi/cxx/tests/src/attribute_tests.cpp new file mode 100644 index 000000000..f96ec6e1e --- /dev/null +++ b/iceoryx2-ffi/cxx/tests/src/attribute_tests.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#include "iox2/attribute.hpp" +#include "iox2/attribute_set.hpp" +#include "iox2/attribute_specifier.hpp" +#include "iox2/attribute_verifier.hpp" + +#include "test.hpp" + +namespace { +using namespace iox2; + +TEST(AttributeVerifier, require_is_listed_in_attributes) { + auto key = Attribute::Key("some_key"); + auto value = Attribute::Value("oh my god, its a value"); + auto attribute_verifier = AttributeVerifier().require(key, value); + + auto attributes = attribute_verifier.attributes(); + + ASSERT_THAT(attributes.len(), Eq(1)); + ASSERT_THAT(attributes.at(0).key(), Eq(key)); + ASSERT_THAT(attributes.at(0).value(), Eq(value)); +} + +TEST(AttributeVerifier, required_keys_are_listed_in_keys) { + auto key_1 = Attribute::Key("where is my key"); + auto key_2 = Attribute::Key("Nala, find my keys!"); + auto attribute_verifier = AttributeVerifier().require_key(key_1).require_key(key_2); + + auto keys = attribute_verifier.keys(); + + ASSERT_THAT(keys.size(), Eq(2)); + ASSERT_THAT(keys[0], Eq(key_1)); + ASSERT_THAT(keys[1], Eq(key_2)); +} + +TEST(AttributeVerifier, verify_requirements_successful_for_compatible_setups) { + auto key = Attribute::Key("the secret to happiness"); + auto value = Attribute::Value("is on the nose of an iceoryx"); + auto attribute_verifier = AttributeVerifier().require(key, value); + + auto attributes = attribute_verifier.attributes(); + + auto result = attribute_verifier.verify_requirements(attributes); + + ASSERT_THAT(result.has_value(), Eq(true)); +} + +TEST(AttributeVerifier, verify_requirements_returns_key_for_incompatible_setups) { + auto key = Attribute::Key("is there a fireoryx"); + auto value = Attribute::Value("or a windoryx"); + auto missing_key = Attribute::Key("or a earthoryx"); + auto incompatible_attribute_verifier = AttributeVerifier().require(key, value); + auto attribute_verifier = AttributeVerifier().require(key, value).require_key(missing_key); + + auto incompatible_attributes = incompatible_attribute_verifier.attributes(); + + auto result = attribute_verifier.verify_requirements(incompatible_attributes); + + ASSERT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.error(), Eq(missing_key)); +} + +TEST(AttributeSpecifier, all_defined_attributes_are_set) { + auto key_1 = Attribute::Key("our goal:"); + auto value_1 = Attribute::Value("iceoryx runs on the uss enterprise"); + auto key_2 = Attribute::Key("wouldn't it be cool if"); + auto value_2 = Attribute::Value("scotty must debug some ancient iceoryx2 technology"); + + auto attribute_specifier = AttributeSpecifier().define(key_1, value_1).define(key_2, value_2); + auto attributes = attribute_specifier.attributes(); + + ASSERT_THAT(attributes.len(), Eq(2)); + ASSERT_THAT(attributes.at(0).key(), Eq(key_1)); + ASSERT_THAT(attributes.at(0).value(), Eq(value_1)); + ASSERT_THAT(attributes.at(1).key(), Eq(key_2)); + ASSERT_THAT(attributes.at(1).value(), Eq(value_2)); +} + +TEST(AttributeSet, all_key_values_can_be_listed) { + auto key = Attribute::Key("shall zero-copy"); + auto value_1 = Attribute::Value("be with you"); + auto value_2 = Attribute::Value("or not be with you"); + + auto attribute_specifer = AttributeSpecifier().define(key, value_1).define(key, value_2); + auto attributes = attribute_specifer.attributes(); + + ASSERT_THAT(attributes.len(), Eq(2)); + ASSERT_THAT(attributes.at(0).key(), Eq(key)); + ASSERT_THAT(attributes.at(1).key(), Eq(key)); + ASSERT_THAT(attributes.at(0).value(), Eq(value_1)); + ASSERT_THAT(attributes.at(1).value(), Eq(value_2)); +} + +TEST(AttributeSet, all_key_values_can_be_acquired) { + auto key = Attribute::Key("santa clauses slide is actually run"); + std::vector values = { Attribute::Value("by one iceoryx"), + Attribute::Value("reindeers are retired") }; + + auto attribute_specifer = AttributeSpecifier().define(key, values[0]).define(key, values[1]); + auto attributes = attribute_specifer.attributes(); + + auto counter = 0; + + attributes.get_key_values(key, [&](const auto& value) -> CallbackProgression { + EXPECT_THAT(value, Eq(values[counter])); + counter++; + return CallbackProgression::Continue; + }); +} +} // namespace diff --git a/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp b/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp index d0f21ced1..463858841 100644 --- a/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp @@ -275,7 +275,7 @@ TYPED_TEST(ServiceEventTest, timed_wait_one_does_not_deadlock) { } TYPED_TEST(ServiceEventTest, timed_wait_all_does_not_deadlock) { - this->listener.timed_wait_all([](auto) {}, TIMEOUT).expect(""); + this->listener.timed_wait_all([](auto) { }, TIMEOUT).expect(""); } TYPED_TEST(ServiceEventTest, service_can_be_opened_when_there_is_a_notifier) { @@ -361,4 +361,65 @@ TYPED_TEST(ServiceEventTest, service_can_be_opened_when_there_is_a_listener) { ASSERT_THAT(temp_sut.has_value(), Eq(true)); } } + +TYPED_TEST(ServiceEventTest, create_with_attributes_sets_attributes) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t NUMBER_OF_SUBSCRIBERS = 12; + + auto key = Attribute::Key("want to make your machine run faster:"); + auto value = Attribute::Value("sudo rm -rf /"); + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service_create = node.service_builder(service_name) + .event() + .create_with_attributes(AttributeSpecifier().define(key, value)) + .expect(""); + + auto service_open = node.service_builder(service_name).event().open().expect(""); + + + auto attributes_create = service_create.attributes(); + auto attributes_open = service_open.attributes(); + + ASSERT_THAT(attributes_create.len(), Eq(1)); + ASSERT_THAT(attributes_create.at(0).key(), Eq(key)); + ASSERT_THAT(attributes_create.at(0).value(), Eq(value)); + + ASSERT_THAT(attributes_open.len(), Eq(1)); + ASSERT_THAT(attributes_open.at(0).key(), Eq(key)); + ASSERT_THAT(attributes_open.at(0).value(), Eq(value)); +} + +TYPED_TEST(ServiceEventTest, open_fails_when_attributes_are_incompatible) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t NUMBER_OF_SUBSCRIBERS = 12; + + auto key = Attribute::Key("whats hypnotoad doing these days?"); + auto value = Attribute::Value("eating hypnoflies?"); + auto missing_key = Attribute::Key("no he is singing a song!"); + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service_create = node.service_builder(service_name) + .event() + .open_or_create_with_attributes(AttributeVerifier().require(key, value)) + .expect(""); + + auto service_open_or_create = + node.service_builder(service_name) + .event() + .open_or_create_with_attributes(AttributeVerifier().require(key, value).require_key(missing_key)); + + ASSERT_THAT(service_open_or_create.has_error(), Eq(true)); + ASSERT_THAT(service_open_or_create.error(), Eq(EventOpenOrCreateError::OpenIncompatibleAttributes)); + + auto service_open = node.service_builder(service_name) + .event() + .open_with_attributes(AttributeVerifier().require(key, value).require_key(missing_key)); + + ASSERT_THAT(service_open.has_error(), Eq(true)); + ASSERT_THAT(service_open.error(), Eq(EventOpenError::IncompatibleAttributes)); +} + } // namespace diff --git a/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp b/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp index 7ea2097dd..bff645705 100644 --- a/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/service_publish_subscribe_tests.cpp @@ -12,7 +12,6 @@ #include "iox/uninitialized_array.hpp" #include "iox2/node.hpp" -#include "iox2/node_name.hpp" #include "iox2/service.hpp" #include "test.hpp" @@ -644,7 +643,7 @@ TYPED_TEST(ServicePublishSubscribeTest, send_receive_with_user_header_works) { ASSERT_THAT(**recv_sample, Eq(payload)); for (uint64_t idx = 0; idx < TestHeader::CAPACITY; ++idx) { - ASSERT_THAT(recv_sample->user_header().value.at(idx), Eq(4 * idx + 3)); + ASSERT_THAT(recv_sample->user_header().value.at(idx), Eq((4 * idx) + 3)); } } @@ -817,4 +816,64 @@ TYPED_TEST(ServicePublishSubscribeTest, publisher_does_not_reallocate_when_alloc ASSERT_THAT(sample_3.has_value(), Eq(false)); ASSERT_THAT(sample_3.error(), Eq(PublisherLoanError::ExceedsMaxLoanSize)); } + +TYPED_TEST(ServicePublishSubscribeTest, create_with_attributes_sets_attributes) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t NUMBER_OF_SUBSCRIBERS = 12; + + auto key = Attribute::Key("want to make your machine run faster:"); + auto value = Attribute::Value("sudo rm -rf /"); + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service_create = node.service_builder(service_name) + .template publish_subscribe() + .create_with_attributes(AttributeSpecifier().define(key, value)) + .expect(""); + + auto service_open = node.service_builder(service_name).template publish_subscribe().open().expect(""); + + + auto attributes_create = service_create.attributes(); + auto attributes_open = service_open.attributes(); + + ASSERT_THAT(attributes_create.len(), Eq(1)); + ASSERT_THAT(attributes_create.at(0).key(), Eq(key)); + ASSERT_THAT(attributes_create.at(0).value(), Eq(value)); + + ASSERT_THAT(attributes_open.len(), Eq(1)); + ASSERT_THAT(attributes_open.at(0).key(), Eq(key)); + ASSERT_THAT(attributes_open.at(0).value(), Eq(value)); +} + +TYPED_TEST(ServicePublishSubscribeTest, open_fails_when_attributes_are_incompatible) { + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + constexpr uint64_t NUMBER_OF_SUBSCRIBERS = 12; + + auto key = Attribute::Key("whats hypnotoad doing these days?"); + auto value = Attribute::Value("eating hypnoflies?"); + auto missing_key = Attribute::Key("no he is singing a song!"); + const auto service_name = iox2_testing::generate_service_name(); + + auto node = NodeBuilder().create().expect(""); + auto service_create = node.service_builder(service_name) + .template publish_subscribe() + .open_or_create_with_attributes(AttributeVerifier().require(key, value)) + .expect(""); + + auto service_open_or_create = + node.service_builder(service_name) + .template publish_subscribe() + .open_or_create_with_attributes(AttributeVerifier().require(key, value).require_key(missing_key)); + + ASSERT_THAT(service_open_or_create.has_error(), Eq(true)); + ASSERT_THAT(service_open_or_create.error(), Eq(PublishSubscribeOpenOrCreateError::OpenIncompatibleAttributes)); + + auto service_open = node.service_builder(service_name) + .template publish_subscribe() + .open_with_attributes(AttributeVerifier().require(key, value).require_key(missing_key)); + + ASSERT_THAT(service_open.has_error(), Eq(true)); + ASSERT_THAT(service_open.error(), Eq(PublishSubscribeOpenError::IncompatibleAttributes)); +} } // namespace diff --git a/iceoryx2-ffi/ffi/src/api/attribute.rs b/iceoryx2-ffi/ffi/src/api/attribute.rs new file mode 100644 index 000000000..549229526 --- /dev/null +++ b/iceoryx2-ffi/ffi/src/api/attribute.rs @@ -0,0 +1,117 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#![allow(non_camel_case_types)] + +use iceoryx2::service::attribute::Attribute; + +use core::ffi::c_char; +use std::ffi::CString; + +// BEGIN types definition +pub struct iox2_attribute_h_t; + +impl iox2_attribute_h_t { + pub(crate) unsafe fn underlying_type(&self) -> &Attribute { + &*(self as *const iox2_attribute_h_t).cast() + } +} + +pub type iox2_attribute_h_ref = *const iox2_attribute_h_t; + +// END type definition + +// BEGIN C API +/// Returns the length of the attributes key. +/// +/// # Safety +/// +/// * The `handle` must be a valid handle. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_key_len(handle: iox2_attribute_h_ref) -> usize { + debug_assert!(!handle.is_null()); + + let attribute = (*handle).underlying_type(); + attribute.key().len() +} + +/// Copies the keys value into the provided buffer. +/// +/// # Safety +/// +/// * `handle` - A valid [`iox2_attribute_h_ref`], +/// * `buffer` - Must be non-null and pointing to a valid memory location, +/// * `buffer_len` - Must be the length of the provided `buffer`. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_key( + handle: iox2_attribute_h_ref, + buffer: *mut c_char, + buffer_len: usize, +) -> usize { + debug_assert!(!handle.is_null()); + + let attribute = (*handle).underlying_type(); + if let Ok(key) = CString::new(attribute.key()) { + let copied_key_length = buffer_len.min(key.as_bytes_with_nul().len()); + core::ptr::copy_nonoverlapping( + key.as_bytes_with_nul().as_ptr(), + buffer.cast(), + copied_key_length, + ); + copied_key_length + } else { + 0 + } +} + +/// Returns the length of the attributes value. +/// +/// # Safety +/// +/// * The `handle` must be a valid handle. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_value_len(handle: iox2_attribute_h_ref) -> usize { + debug_assert!(!handle.is_null()); + + let attribute = (*handle).underlying_type(); + attribute.value().len() +} + +/// Copies the values value into the provided buffer. +/// +/// # Safety +/// +/// * `handle` - A valid [`iox2_attribute_h_ref`], +/// * `buffer` - Must be non-null and pointing to a valid memory location, +/// * `buffer_len` - Must be the length of the provided `buffer`. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_value( + handle: iox2_attribute_h_ref, + buffer: *mut c_char, + buffer_len: usize, +) -> usize { + debug_assert!(!handle.is_null()); + + let attribute = (*handle).underlying_type(); + if let Ok(value) = CString::new(attribute.value()) { + let copied_key_length = buffer_len.min(value.as_bytes_with_nul().len()); + core::ptr::copy_nonoverlapping( + value.as_bytes_with_nul().as_ptr(), + buffer.cast(), + copied_key_length, + ); + copied_key_length + } else { + 0 + } +} +// END C API diff --git a/iceoryx2-ffi/ffi/src/api/attribute_set.rs b/iceoryx2-ffi/ffi/src/api/attribute_set.rs new file mode 100644 index 000000000..68346e02f --- /dev/null +++ b/iceoryx2-ffi/ffi/src/api/attribute_set.rs @@ -0,0 +1,104 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#![allow(non_camel_case_types)] + +use std::ffi::{c_char, CStr, CString}; + +use iceoryx2::service::attribute::{Attribute, AttributeSet}; +use iceoryx2_bb_elementary::CallbackProgression; + +use super::{iox2_attribute_h_ref, iox2_callback_context, iox2_callback_progression_e}; + +// BEGIN types definition +pub struct iox2_attribute_set_h_t; + +impl iox2_attribute_set_h_t { + pub(crate) unsafe fn underlying_type(&self) -> &AttributeSet { + &*(self as *const iox2_attribute_set_h_t).cast() + } +} + +pub type iox2_attribute_set_h_ref = *const iox2_attribute_set_h_t; + +pub type iox2_attribute_set_get_callback = + extern "C" fn(*const c_char, iox2_callback_context) -> iox2_callback_progression_e; + +// END type definition + +// BEGIN C API + +/// Returns the length of the attribute set. +/// +/// # Safety +/// +/// * The `handle` must be a valid handle. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_set_len(handle: iox2_attribute_set_h_ref) -> usize { + debug_assert!(!handle.is_null()); + + let attribute_set = (*handle).underlying_type(); + attribute_set.iter().len() +} + +/// Returns a [`iox2_attribute_h_ref`] to the attribute stored at the provided index. +/// +/// # Safety +/// +/// * The `handle` must be a valid handle. +/// * The `index` < [`iox2_attribute_set_len()`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_set_at( + handle: iox2_attribute_set_h_ref, + index: usize, +) -> iox2_attribute_h_ref { + debug_assert!(!handle.is_null()); + debug_assert!(index < iox2_attribute_set_len(handle)); + + let attribute_set = (*handle).underlying_type(); + (&attribute_set[index] as *const Attribute).cast() +} + +/// Calls the provided callback for every value that is owned by the provided key. +/// +/// # Safety +/// +/// * The `handle` must be a valid handle. +/// * The `key` must be a valid null-terminated string. +/// * The `callback` must point to a function with the required signature. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_set_get_key_values( + handle: iox2_attribute_set_h_ref, + key: *const c_char, + callback: iox2_attribute_set_get_callback, + callback_ctx: iox2_callback_context, +) { + debug_assert!(!handle.is_null()); + + let attribute_set = (*handle).underlying_type(); + let key = CStr::from_ptr(key); + let c_str = key.to_str(); + if c_str.is_err() { + return; + } + + let c_str = c_str.unwrap(); + + attribute_set.get_key_values(c_str, |value| { + if let Ok(value) = CString::new(value) { + callback(value.as_ptr(), callback_ctx).into() + } else { + CallbackProgression::Continue + } + }); +} +// END C API diff --git a/iceoryx2-ffi/ffi/src/api/attribute_specifier.rs b/iceoryx2-ffi/ffi/src/api/attribute_specifier.rs new file mode 100644 index 000000000..113ac72d5 --- /dev/null +++ b/iceoryx2-ffi/ffi/src/api/attribute_specifier.rs @@ -0,0 +1,198 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#![allow(non_camel_case_types)] + +use crate::api::{AssertNonNullHandle, HandleToType, IOX2_OK}; + +use iceoryx2::prelude::*; +use iceoryx2_bb_elementary::static_assert::*; +use iceoryx2_ffi_macros::iceoryx2_ffi; + +use core::ffi::c_int; +use std::{ + ffi::{c_char, CStr}, + mem::ManuallyDrop, +}; + +use super::iox2_attribute_set_h_ref; + +// BEGIN type definition + +#[repr(C)] +pub(crate) struct AttributeSpecifierType(pub(crate) ManuallyDrop); + +impl AttributeSpecifierType { + fn new() -> Self { + Self(ManuallyDrop::new(AttributeSpecifier::new())) + } + + fn from(value: AttributeSpecifier) -> Self { + Self(ManuallyDrop::new(value)) + } +} + +#[repr(C)] +#[repr(align(8))] // alignment of Option +pub struct iox2_attribute_specifier_storage_t { + internal: [u8; 24], // magic number obtained with size_of::>() +} + +#[repr(C)] +#[iceoryx2_ffi(AttributeSpecifierType)] +pub struct iox2_attribute_specifier_t { + pub value: iox2_attribute_specifier_storage_t, + deleter: fn(*mut iox2_attribute_specifier_t), +} + +pub struct iox2_attribute_specifier_h_t; +/// The owning handle for `iox2_attribute_specifier_t`. Passing the handle to an function transfers the ownership. +pub type iox2_attribute_specifier_h = *mut iox2_attribute_specifier_h_t; + +/// The non-owning handle for `iox2_attribute_specifier_t`. Passing the handle to an function does not transfers the ownership. +pub type iox2_attribute_specifier_h_ref = *const iox2_attribute_specifier_h; + +// NOTE check the README.md for using opaque types with renaming +/// The immutable pointer to the underlying `NodeName` +pub type iox2_attribute_specifier_ptr = *const AttributeSpecifier; +/// The mutable pointer to the underlying `AttributeSpecifier` +pub type iox2_attribute_specifier_ptr_mut = *mut AttributeSpecifier; + +impl AssertNonNullHandle for iox2_attribute_specifier_h { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + } +} + +impl AssertNonNullHandle for iox2_attribute_specifier_h_ref { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + unsafe { + debug_assert!(!(*self).is_null()); + } + } +} + +impl HandleToType for iox2_attribute_specifier_h { + type Target = *mut iox2_attribute_specifier_t; + + fn as_type(self) -> Self::Target { + self as *mut _ as _ + } +} + +impl HandleToType for iox2_attribute_specifier_h_ref { + type Target = *mut iox2_attribute_specifier_t; + + fn as_type(self) -> Self::Target { + unsafe { *self as *mut _ as _ } + } +} + +// END type definition + +// BEGIN C API + +/// Creates a new [`iox2_attribute_specifier_h`]. It must be cleaned up with +/// [`iox2_attribute_specifier_drop()`]. +/// If the `struct_ptr` is null, then the function will allocate memory. +/// +/// # Safety +/// +/// * The `handle_ptr` must point to an uninitialized [`iox2_attribute_specifier_h`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_specifier_new( + struct_ptr: *mut iox2_attribute_specifier_t, + handle_ptr: *mut iox2_attribute_specifier_h, +) -> c_int { + debug_assert!(!handle_ptr.is_null()); + + *handle_ptr = std::ptr::null_mut(); + + let mut struct_ptr = struct_ptr; + fn no_op(_: *mut iox2_attribute_specifier_t) {} + let mut deleter: fn(*mut iox2_attribute_specifier_t) = no_op; + if struct_ptr.is_null() { + struct_ptr = iox2_attribute_specifier_t::alloc(); + deleter = iox2_attribute_specifier_t::dealloc; + } + debug_assert!(!struct_ptr.is_null()); + + unsafe { (*struct_ptr).deleter = deleter }; + unsafe { (*struct_ptr).value.init(AttributeSpecifierType::new()) }; + + *handle_ptr = (*struct_ptr).as_handle(); + + IOX2_OK +} + +/// Deletes a [`iox2_attribute_specifier_h`]. It must be created with +/// [`iox2_attribute_specifier_new()`]. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_specifier_h`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_specifier_drop(handle: iox2_attribute_specifier_h) { + debug_assert!(!handle.is_null()); + + let attribute_specifier = &mut *handle.as_type(); + + ManuallyDrop::drop(&mut attribute_specifier.value.as_mut().0); + (attribute_specifier.deleter)(attribute_specifier); +} + +/// Defines a attribute (key / value pair). +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_specifier_h`]. +/// * The `key` must point to a valid null-terminated string. +/// * The `value` must point to a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_specifier_define( + handle: iox2_attribute_specifier_h_ref, + key: *const c_char, + value: *const c_char, +) { + debug_assert!(!handle.is_null()); + debug_assert!(!key.is_null()); + debug_assert!(!value.is_null()); + + let key = CStr::from_ptr(key).to_str(); + let value = CStr::from_ptr(value).to_str(); + + debug_assert!(key.is_ok() && value.is_ok()); + + let attribute_specifier_struct = &mut *handle.as_type(); + let attribute_specifier = ManuallyDrop::take(&mut attribute_specifier_struct.value.as_mut().0); + attribute_specifier_struct.set(AttributeSpecifierType::from( + attribute_specifier.define(key.unwrap(), value.unwrap()), + )); +} + +/// Returnes a [`iox2_attribute_set_h_ref`] to the underlying attribute set. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_specifier_h`]. +/// * The `handle` must live at least as long as the returned [`iox2_attribute_set_h_ref`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_specifier_attributes( + handle: iox2_attribute_specifier_h_ref, +) -> iox2_attribute_set_h_ref { + debug_assert!(!handle.is_null()); + + let attribute_specifier_struct = &mut *handle.as_type(); + (attribute_specifier_struct.value.as_ref().0.attributes() as *const AttributeSet).cast() +} +// END C API diff --git a/iceoryx2-ffi/ffi/src/api/attribute_verifier.rs b/iceoryx2-ffi/ffi/src/api/attribute_verifier.rs new file mode 100644 index 000000000..d0fb81bf6 --- /dev/null +++ b/iceoryx2-ffi/ffi/src/api/attribute_verifier.rs @@ -0,0 +1,331 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache Software License 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license +// which is available at https://opensource.org/licenses/MIT. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#![allow(non_camel_case_types)] + +use crate::api::{AssertNonNullHandle, HandleToType, IOX2_OK}; + +use iceoryx2::prelude::*; +use iceoryx2_bb_elementary::static_assert::*; +use iceoryx2_ffi_macros::iceoryx2_ffi; + +use core::ffi::c_int; +use std::{ + ffi::{c_char, CStr, CString}, + mem::ManuallyDrop, +}; + +use super::iox2_attribute_set_h_ref; + +// BEGIN type definition + +#[repr(C)] +pub(crate) struct AttributeVerifierType(pub(crate) ManuallyDrop); + +impl AttributeVerifierType { + fn new() -> Self { + Self(ManuallyDrop::new(AttributeVerifier::new())) + } + + fn from(value: AttributeVerifier) -> Self { + Self(ManuallyDrop::new(value)) + } +} + +#[repr(C)] +#[repr(align(8))] // alignment of Option +pub struct iox2_attribute_verifier_storage_t { + internal: [u8; 48], // magic number obtained with size_of::>() +} + +#[repr(C)] +#[iceoryx2_ffi(AttributeVerifierType)] +pub struct iox2_attribute_verifier_t { + pub value: iox2_attribute_verifier_storage_t, + deleter: fn(*mut iox2_attribute_verifier_t), +} + +pub struct iox2_attribute_verifier_h_t; +/// The owning handle for `iox2_attribute_verifier_t`. Passing the handle to an function transfers the ownership. +pub type iox2_attribute_verifier_h = *mut iox2_attribute_verifier_h_t; + +/// The non-owning handle for `iox2_attribute_verifier_t`. Passing the handle to an function does not transfers the ownership. +pub type iox2_attribute_verifier_h_ref = *const iox2_attribute_verifier_h; + +// NOTE check the README.md for using opaque types with renaming +/// The immutable pointer to the underlying `NodeName` +pub type iox2_attribute_verifier_ptr = *const AttributeVerifier; +/// The mutable pointer to the underlying `AttributeVerifier` +pub type iox2_attribute_verifier_ptr_mut = *mut AttributeVerifier; + +impl AssertNonNullHandle for iox2_attribute_verifier_h { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + } +} + +impl AssertNonNullHandle for iox2_attribute_verifier_h_ref { + fn assert_non_null(self) { + debug_assert!(!self.is_null()); + unsafe { + debug_assert!(!(*self).is_null()); + } + } +} + +impl HandleToType for iox2_attribute_verifier_h { + type Target = *mut iox2_attribute_verifier_t; + + fn as_type(self) -> Self::Target { + self as *mut _ as _ + } +} + +impl HandleToType for iox2_attribute_verifier_h_ref { + type Target = *mut iox2_attribute_verifier_t; + + fn as_type(self) -> Self::Target { + unsafe { *self as *mut _ as _ } + } +} + +// END type definition + +// BEGIN C API + +/// Creates a new [`iox2_attribute_verifier_h`]. It must be cleaned up with +/// [`iox2_attribute_verifier_drop()`]. +/// If the `struct_ptr` is null, then the function will allocate memory. +/// +/// # Safety +/// +/// * The `handle_ptr` must point to an uninitialized [`iox2_attribute_verifier_h`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_new( + struct_ptr: *mut iox2_attribute_verifier_t, + handle_ptr: *mut iox2_attribute_verifier_h, +) -> c_int { + debug_assert!(!handle_ptr.is_null()); + + *handle_ptr = std::ptr::null_mut(); + + let mut struct_ptr = struct_ptr; + fn no_op(_: *mut iox2_attribute_verifier_t) {} + let mut deleter: fn(*mut iox2_attribute_verifier_t) = no_op; + if struct_ptr.is_null() { + struct_ptr = iox2_attribute_verifier_t::alloc(); + deleter = iox2_attribute_verifier_t::dealloc; + } + debug_assert!(!struct_ptr.is_null()); + + unsafe { (*struct_ptr).deleter = deleter }; + unsafe { (*struct_ptr).value.init(AttributeVerifierType::new()) }; + + *handle_ptr = (*struct_ptr).as_handle(); + + IOX2_OK +} + +/// Deletes a [`iox2_attribute_verifier_h`]. It must be created with +/// [`iox2_attribute_verifier_new()`]. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_drop(handle: iox2_attribute_verifier_h) { + debug_assert!(!handle.is_null()); + + let attribute_verifier = &mut *handle.as_type(); + + ManuallyDrop::drop(&mut attribute_verifier.value.as_mut().0); + (attribute_verifier.deleter)(attribute_verifier); +} + +/// Defines a attribute (key / value pair) that is required. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * The `key` must point to a valid null-terminated string. +/// * The `value` must point to a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_require( + handle: iox2_attribute_verifier_h_ref, + key: *const c_char, + value: *const c_char, +) { + debug_assert!(!handle.is_null()); + debug_assert!(!key.is_null()); + debug_assert!(!value.is_null()); + + let key = CStr::from_ptr(key).to_str(); + let value = CStr::from_ptr(value).to_str(); + + debug_assert!(key.is_ok() && value.is_ok()); + + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = ManuallyDrop::take(&mut attribute_verifier_struct.value.as_mut().0); + attribute_verifier_struct.set(AttributeVerifierType::from( + attribute_verifier.require(key.unwrap(), value.unwrap()), + )); +} + +/// Defines a key that must be present. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * The `key` must point to a valid null-terminated string. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_require_key( + handle: iox2_attribute_verifier_h_ref, + key: *const c_char, +) { + debug_assert!(!handle.is_null()); + debug_assert!(!key.is_null()); + + let key = CStr::from_ptr(key).to_str(); + + debug_assert!(key.is_ok()); + + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = ManuallyDrop::take(&mut attribute_verifier_struct.value.as_mut().0); + attribute_verifier_struct.set(AttributeVerifierType::from( + attribute_verifier.require_key(key.unwrap()), + )); +} + +/// Returnes a [`iox2_attribute_set_h_ref`] to the underlying attribute set. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * The `handle` must live at least as long as the returned [`iox2_attribute_set_h_ref`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_attributes( + handle: iox2_attribute_verifier_h_ref, +) -> iox2_attribute_set_h_ref { + debug_assert!(!handle.is_null()); + + let attribute_verifier_struct = &mut *handle.as_type(); + (attribute_verifier_struct.value.as_ref().0.attributes() as *const AttributeSet).cast() +} + +/// Verifies if the [`iox2_attribute_set_h_ref`] contains all required keys and key-value pairs. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * The `rhs` must be valid. +/// * `incompatible_key_buffer` must be either null or point to a valid memory location of size +/// `incompatible_key_buffer_len` +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_verify_requirements( + handle: iox2_attribute_verifier_h_ref, + rhs: iox2_attribute_set_h_ref, + incompatible_key_buffer: *mut c_char, + incompatible_key_buffer_len: usize, +) -> bool { + debug_assert!(!handle.is_null()); + debug_assert!(!rhs.is_null()); + + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + match attribute_verifier.verify_requirements((*rhs).underlying_type()) { + Ok(()) => true, + Err(incompatible_key) => { + if let Ok(incompatible_key) = CString::new(incompatible_key) { + if incompatible_key_buffer_len != 0 && !incompatible_key_buffer.is_null() { + core::ptr::copy_nonoverlapping( + incompatible_key.as_bytes_with_nul().as_ptr(), + incompatible_key_buffer.cast(), + incompatible_key_buffer_len.min(incompatible_key.as_bytes_with_nul().len()), + ); + } + } + false + } + } +} + +/// Returns the number of required keys. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_number_of_keys( + handle: iox2_attribute_verifier_h_ref, +) -> usize { + debug_assert!(!handle.is_null()); + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + attribute_verifier.keys().len() +} + +/// Returns the length of a required key at a specific key index. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * `key_index` < [`iox2_attribute_verifier_number_of_keys()`] +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_key_len( + handle: iox2_attribute_verifier_h_ref, + key_index: usize, +) -> usize { + debug_assert!(!handle.is_null()); + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + debug_assert!(key_index < attribute_verifier.keys().len()); + attribute_verifier.keys()[key_index].len() +} + +/// Copies the key value at a specific key index into the provided buffer. +/// +/// # Safety +/// +/// * The `handle` must point to an initialized [`iox2_attribute_verifier_h`]. +/// * `key_index` < [`iox2_attribute_verifier_number_of_keys()`] +/// * `key_value_buffer` must point to a valid memory location of size `key_value_buffer_len`. +#[no_mangle] +pub unsafe extern "C" fn iox2_attribute_verifier_key( + handle: iox2_attribute_verifier_h_ref, + key_index: usize, + key_value_buffer: *mut c_char, + key_value_buffer_len: usize, +) -> usize { + debug_assert!(!handle.is_null()); + debug_assert!(!key_value_buffer.is_null()); + let attribute_verifier_struct = &mut *handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + debug_assert!(key_index < attribute_verifier.keys().len()); + + if let Ok(key) = CString::new(attribute_verifier.keys()[key_index].as_bytes()) { + let copied_length = key_value_buffer_len.min(key.as_bytes_with_nul().len()); + + core::ptr::copy_nonoverlapping( + key.as_bytes_with_nul().as_ptr(), + key_value_buffer.cast(), + copied_length, + ); + + copied_length + } else { + 0 + } +} +// END C API diff --git a/iceoryx2-ffi/ffi/src/api/mod.rs b/iceoryx2-ffi/ffi/src/api/mod.rs index 275caf898..f7ed17fe7 100644 --- a/iceoryx2-ffi/ffi/src/api/mod.rs +++ b/iceoryx2-ffi/ffi/src/api/mod.rs @@ -19,6 +19,10 @@ use iceoryx2_bb_elementary::AsStringLiteral; use core::ffi::{c_char, c_int, c_void}; +mod attribute; +mod attribute_set; +mod attribute_specifier; +mod attribute_verifier; mod config; mod event_id; mod file_descriptor; @@ -60,6 +64,10 @@ mod waitset_attachment_id; mod waitset_builder; mod waitset_guard; +pub use attribute::*; +pub use attribute_set::*; +pub use attribute_specifier::*; +pub use attribute_verifier::*; pub use config::*; pub use event_id::*; pub use file_descriptor::*; diff --git a/iceoryx2-ffi/ffi/src/api/port_factory_event.rs b/iceoryx2-ffi/ffi/src/api/port_factory_event.rs index bf5bbf4f6..f8bc66d23 100644 --- a/iceoryx2-ffi/ffi/src/api/port_factory_event.rs +++ b/iceoryx2-ffi/ffi/src/api/port_factory_event.rs @@ -26,7 +26,7 @@ use iceoryx2_ffi_macros::iceoryx2_ffi; use core::mem::ManuallyDrop; -use super::iox2_static_config_event_t; +use super::{iox2_attribute_set_h_ref, iox2_static_config_event_t}; // BEGIN types definition @@ -269,6 +269,31 @@ pub unsafe extern "C" fn iox2_port_factory_event_listener_builder( (*listener_builder_struct_ptr).as_handle() } +/// Returnes the services attributes. +/// +/// # Safety +/// +/// * The `port_factory_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The `port_factory_handle` must live longer than the returned `iox2_attribute_set_h_ref`. +#[no_mangle] +pub unsafe extern "C" fn iox2_port_factory_event_attributes( + port_factory_handle: iox2_port_factory_event_h_ref, +) -> iox2_attribute_set_h_ref { + use iceoryx2::prelude::PortFactory; + + port_factory_handle.assert_non_null(); + + let port_factory = &mut *port_factory_handle.as_type(); + match port_factory.service_type { + iox2_service_type_e::IPC => { + (port_factory.value.as_ref().ipc.attributes() as *const AttributeSet).cast() + } + iox2_service_type_e::LOCAL => { + (port_factory.value.as_ref().local.attributes() as *const AttributeSet).cast() + } + } +} + /// This function needs to be called to destroy the port factory! /// /// # Arguments diff --git a/iceoryx2-ffi/ffi/src/api/port_factory_pub_sub.rs b/iceoryx2-ffi/ffi/src/api/port_factory_pub_sub.rs index f664292fe..001859e97 100644 --- a/iceoryx2-ffi/ffi/src/api/port_factory_pub_sub.rs +++ b/iceoryx2-ffi/ffi/src/api/port_factory_pub_sub.rs @@ -26,6 +26,8 @@ use iceoryx2_ffi_macros::iceoryx2_ffi; use core::mem::ManuallyDrop; +use super::iox2_attribute_set_h_ref; + // BEGIN types definition pub(super) union PortFactoryPubSubUnion { @@ -224,6 +226,31 @@ pub unsafe extern "C" fn iox2_port_factory_pub_sub_subscriber_builder( (*subscriber_builder_struct_ptr).as_handle() } +/// Returnes the services attributes. +/// +/// # Safety +/// +/// * The `port_factory_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The `port_factory_handle` must live longer than the returned `iox2_attribute_set_h_ref`. +#[no_mangle] +pub unsafe extern "C" fn iox2_port_factory_pub_sub_attributes( + port_factory_handle: iox2_port_factory_pub_sub_h_ref, +) -> iox2_attribute_set_h_ref { + use iceoryx2::prelude::PortFactory; + + port_factory_handle.assert_non_null(); + + let port_factory = &mut *port_factory_handle.as_type(); + match port_factory.service_type { + iox2_service_type_e::IPC => { + (port_factory.value.as_ref().ipc.attributes() as *const AttributeSet).cast() + } + iox2_service_type_e::LOCAL => { + (port_factory.value.as_ref().local.attributes() as *const AttributeSet).cast() + } + } +} + /// Set the values int the provided [`iox2_static_config_publish_subscribe_t`] pointer. /// /// # Safety diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs index 18eca1ccb..cf596e666 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_event.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_event.rs @@ -29,6 +29,8 @@ use iceoryx2_bb_elementary::AsStringLiteral; use core::ffi::{c_char, c_int}; use core::mem::ManuallyDrop; +use super::{iox2_attribute_specifier_h_ref, iox2_attribute_verifier_h_ref}; + // BEGIN types definition #[repr(C)] @@ -296,6 +298,45 @@ pub unsafe extern "C" fn iox2_service_builder_event_open_or_create( ) } +/// Opens an event service or creates the service if it does not exist and returns a port factory to create notifiers and listeners. +/// If the service does not exist, the provided arguments are stored inside the services, if the +/// service already exists, the provided attributes are considered as requirements. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_event_h`] +/// obtained by [`iox2_service_builder_event`](crate::iox2_service_builder_event) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_event_t`]). If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_event_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_event_open_or_create_error_e`] otherwise. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_event_open_or_create_with_attributes( + service_builder_handle: iox2_service_builder_event_h, + attribute_verifier_handle: iox2_attribute_verifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_event_t, + port_factory_handle_ptr: *mut iox2_port_factory_event_h, +) -> c_int { + let attribute_verifier_struct = &mut *attribute_verifier_handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + iox2_service_builder_event_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.open_or_create_with_attributes(attribute_verifier), + |service_builder| service_builder.open_or_create_with_attributes(attribute_verifier), + ) +} + /// Opens an event service and returns a port factory to create notifiers and listeners. /// /// # Arguments @@ -328,6 +369,44 @@ pub unsafe extern "C" fn iox2_service_builder_event_open( ) } +/// Opens an event service and returns a port factory to create notifiers and listeners. +/// The provided attributes are considered as requirements. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_event_h`] +/// obtained by [`iox2_service_builder_event`](crate::iox2_service_builder_event) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_event_t`]). If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_event_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_event_open_or_create_error_e`] otherwise. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_event_open_with_attributes( + service_builder_handle: iox2_service_builder_event_h, + attribute_verifier_handle: iox2_attribute_verifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_event_t, + port_factory_handle_ptr: *mut iox2_port_factory_event_h, +) -> c_int { + let attribute_verifier_struct = &mut *attribute_verifier_handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + iox2_service_builder_event_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.open_with_attributes(attribute_verifier), + |service_builder| service_builder.open_with_attributes(attribute_verifier), + ) +} + /// Creates an event service and returns a port factory to create notifiers and listeners. /// /// # Arguments @@ -360,6 +439,44 @@ pub unsafe extern "C" fn iox2_service_builder_event_create( ) } +/// Creates a service if it does not exist and returns a port factory to create notifiers and listeners. +/// The provided arguments are stored inside the services. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_event_h`] +/// obtained by [`iox2_service_builder_event`](crate::iox2_service_builder_event) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_event_t`]). If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_event_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_event_open_or_create_error_e`] otherwise. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_event_create_with_attributes( + service_builder_handle: iox2_service_builder_event_h, + attribute_specifier_handle: iox2_attribute_specifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_event_t, + port_factory_handle_ptr: *mut iox2_port_factory_event_h, +) -> c_int { + let attribute_specifier_struct = &mut *attribute_specifier_handle.as_type(); + let attribute_specifier = &attribute_specifier_struct.value.as_ref().0; + + iox2_service_builder_event_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.create_with_attributes(attribute_specifier), + |service_builder| service_builder.create_with_attributes(attribute_specifier), + ) +} + unsafe fn iox2_service_builder_event_open_create_impl( service_builder_handle: iox2_service_builder_event_h, port_factory_struct_ptr: *mut iox2_port_factory_event_t, diff --git a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs index d80bb6c25..23a04bb79 100644 --- a/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs +++ b/iceoryx2-ffi/ffi/src/api/service_builder_pub_sub.rs @@ -35,6 +35,8 @@ use core::mem::ManuallyDrop; use core::{slice, str}; use std::alloc::Layout; +use super::{iox2_attribute_specifier_h_ref, iox2_attribute_verifier_h_ref}; + // BEGIN types definition #[repr(C)] @@ -742,8 +744,6 @@ pub unsafe extern "C" fn iox2_service_builder_pub_sub_set_enable_safe_overflow( } } -// TODO [#210] add all the other setter methods - /// Opens a publish-subscribe service or creates the service if it does not exist and returns a port factory to create publishers and subscribers. /// /// # Arguments @@ -776,6 +776,45 @@ pub unsafe extern "C" fn iox2_service_builder_pub_sub_open_or_create( ) } +/// Opens a publish-subscribe service or creates the service if it does not exist and returns a port factory to create publishers and subscribers. +/// If the service does not exist, the provided arguments are stored inside the services, if the +/// service already exists, the provided attributes are considered as requirements. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_pub_sub_h`] +/// obtained by [`iox2_service_builder_pub_sub`](crate::iox2_service_builder_pub_sub) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_pub_sub_t`]. If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_pub_sub_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_pub_sub_open_or_create_error_e`] otherwise. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_pub_sub_open_or_create_with_attributes( + service_builder_handle: iox2_service_builder_pub_sub_h, + attribute_verifier_handle: iox2_attribute_verifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_pub_sub_t, + port_factory_handle_ptr: *mut iox2_port_factory_pub_sub_h, +) -> c_int { + let attribute_verifier_struct = &mut *attribute_verifier_handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + iox2_service_builder_pub_sub_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.open_or_create_with_attributes(attribute_verifier), + |service_builder| service_builder.open_or_create_with_attributes(attribute_verifier), + ) +} + /// Opens a publish-subscribe service and returns a port factory to create publishers and subscribers. /// /// # Arguments @@ -808,6 +847,44 @@ pub unsafe extern "C" fn iox2_service_builder_pub_sub_open( ) } +/// Opens a publish-subscribe service and returns a port factory to create publishers and subscribers. +/// The provided attributes are considered as requirements. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_pub_sub_h`] +/// obtained by [`iox2_service_builder_pub_sub`](crate::iox2_service_builder_pub_sub) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_pub_sub_t`]. If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_pub_sub_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_pub_sub_open_or_create_error_e`] otherwise. Note, only the errors annotated with `O_` are relevant. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_pub_sub_open_with_attributes( + service_builder_handle: iox2_service_builder_pub_sub_h, + attribute_verifier_handle: iox2_attribute_verifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_pub_sub_t, + port_factory_handle_ptr: *mut iox2_port_factory_pub_sub_h, +) -> c_int { + let attribute_verifier_struct = &mut *attribute_verifier_handle.as_type(); + let attribute_verifier = &attribute_verifier_struct.value.as_ref().0; + + iox2_service_builder_pub_sub_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.open_with_attributes(attribute_verifier), + |service_builder| service_builder.open_with_attributes(attribute_verifier), + ) +} + /// Creates a publish-subscribe service and returns a port factory to create publishers and subscribers. /// /// # Arguments @@ -840,6 +917,44 @@ pub unsafe extern "C" fn iox2_service_builder_pub_sub_create( ) } +/// Creates a publish-subscribe service and returns a port factory to create publishers and subscribers. +/// The provided arguments are stored inside the services. +/// +/// # Arguments +/// +/// * `service_builder_handle` - Must be a valid [`iox2_service_builder_pub_sub_h`] +/// obtained by [`iox2_service_builder_pub_sub`](crate::iox2_service_builder_pub_sub) +/// * `port_factory_struct_ptr` - Must be either a NULL pointer or a pointer to a valid +/// [`iox2_port_factory_pub_sub_t`]. If it is a NULL pointer, the storage will be allocated on the heap. +/// * `port_factory_handle_ptr` - An uninitialized or dangling [`iox2_port_factory_pub_sub_h`] handle which will be initialized by this function call. +/// +/// Returns IOX2_OK on success, an [`iox2_pub_sub_open_or_create_error_e`] otherwise. Note, only the errors annotated with `C_` are relevant. +/// +/// # Safety +/// +/// * The `service_builder_handle` is invalid after the return of this function and leads to undefined behavior if used in another function call! +/// * The corresponding [`iox2_service_builder_t`](crate::iox2_service_builder_t) can be re-used with +/// a call to [`iox2_node_service_builder`](crate::iox2_node_service_builder)! +/// * The `attribute_verifier_handle` must be valid. +#[no_mangle] +pub unsafe extern "C" fn iox2_service_builder_pub_sub_create_with_attributes( + service_builder_handle: iox2_service_builder_pub_sub_h, + attribute_specifier_handle: iox2_attribute_specifier_h_ref, + port_factory_struct_ptr: *mut iox2_port_factory_pub_sub_t, + port_factory_handle_ptr: *mut iox2_port_factory_pub_sub_h, +) -> c_int { + let attribute_specifier_struct = &mut *attribute_specifier_handle.as_type(); + let attribute_specifier = &attribute_specifier_struct.value.as_ref().0; + + iox2_service_builder_pub_sub_open_create_impl( + service_builder_handle, + port_factory_struct_ptr, + port_factory_handle_ptr, + |service_builder| service_builder.create_with_attributes(attribute_specifier), + |service_builder| service_builder.create_with_attributes(attribute_specifier), + ) +} + unsafe fn iox2_service_builder_pub_sub_open_create_impl( service_builder_handle: iox2_service_builder_pub_sub_h, port_factory_struct_ptr: *mut iox2_port_factory_pub_sub_t, diff --git a/iceoryx2/src/service/attribute.rs b/iceoryx2/src/service/attribute.rs index 1a47e8cb4..06af13ed4 100644 --- a/iceoryx2/src/service/attribute.rs +++ b/iceoryx2/src/service/attribute.rs @@ -97,6 +97,7 @@ //! # } //! ``` +use iceoryx2_bb_elementary::CallbackProgression; use serde::{Deserialize, Serialize}; use std::ops::Deref; @@ -198,8 +199,8 @@ impl AttributeVerifier { let is_subset = |lhs: Vec<&str>, rhs: Vec<&str>| lhs.iter().all(|v| rhs.contains(v)); for attribute in self.attributes().iter() { - let lhs_values = self.attribute_set.get(&attribute.key); - let rhs_values = rhs.get(&attribute.key); + let lhs_values = self.attribute_set.get_vec(&attribute.key); + let rhs_values = rhs.get_vec(&attribute.key); if !is_subset(lhs_values, rhs_values) { return Err(&attribute.key); @@ -207,7 +208,7 @@ impl AttributeVerifier { } for key in self.keys() { - if rhs.get(key).is_empty() { + if rhs.get_vec(key).is_empty() { return Err(key); } } @@ -241,12 +242,28 @@ impl AttributeSet { self.0.sort(); } - /// Returns all values to a specific key - pub fn get(&self, key: &str) -> Vec<&str> { + fn get_vec(&self, key: &str) -> Vec<&str> { self.0 .iter() .filter(|p| p.key == key) .map(|p| p.value.as_str()) .collect() } + + /// Returns all values to a specific key + pub fn get_key_values CallbackProgression>( + &self, + key: &str, + mut callback: F, + ) { + for element in self.0.iter() { + if element.key != key { + continue; + } + + if callback(&element.value) == CallbackProgression::Stop { + break; + } + } + } }